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/18 13:00:16 UTC

[01/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master ad4cfe6c6 -> 76d24ca04


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
index 9c48ddf..1fed7c6 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java
@@ -63,6 +63,9 @@ import org.apache.brooklyn.api.management.ha.ManagementPlaneSyncRecord;
 import org.apache.brooklyn.api.management.ha.MementoCopyMode;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.file.ArchiveBuilder;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.rest.api.ServerApi;
 import org.apache.brooklyn.rest.domain.BrooklynFeatureSummary;
 import org.apache.brooklyn.rest.domain.HighAvailabilitySummary;
@@ -72,11 +75,8 @@ import org.apache.brooklyn.rest.transform.HighAvailabilityTransformer;
 import org.apache.brooklyn.rest.util.ShutdownHandler;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.file.ArchiveBuilder;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.Identifiers;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/EffectorTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/EffectorTransformer.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/EffectorTransformer.java
index f78df8b..32a8887 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/EffectorTransformer.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/EffectorTransformer.java
@@ -27,14 +27,14 @@ import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ParameterType;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ValueResolver;
 import org.apache.brooklyn.rest.domain.EffectorSummary;
 import org.apache.brooklyn.rest.domain.EffectorSummary.ParameterSummary;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ValueResolver;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java
index 72d17db..f1b6959 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/LocationTransformer.java
@@ -32,11 +32,11 @@ import org.apache.brooklyn.location.basic.LocationInternal;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationDefinition;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.rest.domain.LocationSummary;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/TaskTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/TaskTransformer.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/TaskTransformer.java
index 6b337a0..ead9ba5 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/TaskTransformer.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/TaskTransformer.java
@@ -36,13 +36,13 @@ import brooklyn.entity.basic.BrooklynTaskTags.WrappedStream;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.HasTaskChildren;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.TaskInternal;
 import org.apache.brooklyn.rest.domain.LinkWithMetadata;
 import org.apache.brooklyn.rest.domain.TaskSummary;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.TaskInternal;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 d09d05b..d29b6e8 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
@@ -53,6 +53,7 @@ import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
 import org.apache.brooklyn.core.management.entitlement.Entitlements.StringAndArgument;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.Enrichers;
@@ -70,7 +71,6 @@ import org.apache.brooklyn.rest.domain.EntitySpec;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.javalang.Reflections;
 import brooklyn.util.net.Urls;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/DefaultExceptionMapper.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/DefaultExceptionMapper.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/DefaultExceptionMapper.java
index 491c1a7..8d78462 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/DefaultExceptionMapper.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/util/DefaultExceptionMapper.java
@@ -31,13 +31,13 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.yaml.snakeyaml.error.YAMLException;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
+import org.apache.brooklyn.core.util.flags.ClassCoercionException;
 import org.apache.brooklyn.rest.domain.ApiError;
 import org.apache.brooklyn.rest.domain.ApiError.Builder;
 
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.UserFacingException;
-import brooklyn.util.flags.ClassCoercionException;
 import brooklyn.util.text.Strings;
 
 @Provider

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynPropertiesSecurityFilterTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynPropertiesSecurityFilterTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynPropertiesSecurityFilterTest.java
index 6d8e15e..4320321 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynPropertiesSecurityFilterTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/BrooklynPropertiesSecurityFilterTest.java
@@ -35,11 +35,11 @@ import org.eclipse.jetty.server.Server;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.Test;
-
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.rest.security.provider.AnyoneSecurityProvider;
+
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.time.Time;
 
 import com.fasterxml.jackson.databind.ObjectMapper;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaMasterCheckFilterTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaMasterCheckFilterTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaMasterCheckFilterTest.java
index f5ac071..3f529ca 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaMasterCheckFilterTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/HaMasterCheckFilterTest.java
@@ -32,6 +32,8 @@ import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.management.ha.ManagementNodeState;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.http.HttpStatus;
 import org.apache.http.client.HttpClient;
 import org.eclipse.jetty.server.Server;
@@ -45,8 +47,6 @@ import brooklyn.entity.rebind.RebindTestUtils;
 import org.apache.brooklyn.rest.security.provider.AnyoneSecurityProvider;
 
 import brooklyn.test.Asserts;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.os.Os;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/CatalogResetTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/CatalogResetTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/CatalogResetTest.java
index b073c2c..e9440e8 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/CatalogResetTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/CatalogResetTest.java
@@ -27,11 +27,11 @@ import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 import org.apache.brooklyn.api.catalog.BrooklynCatalog;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
 
 import brooklyn.test.TestHttpRequestHandler;
 import brooklyn.test.TestHttpServer;
-import brooklyn.util.ResourceUtils;
 
 import com.sun.jersey.api.client.UniformInterfaceException;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/SensorResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/SensorResourceIntegrationTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/SensorResourceIntegrationTest.java
index 6af06cb..354f4ed 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/SensorResourceIntegrationTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/SensorResourceIntegrationTest.java
@@ -35,14 +35,14 @@ import brooklyn.entity.basic.EntityPredicates;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.rest.BrooklynRestApiLauncher;
 import org.apache.brooklyn.rest.BrooklynRestApiLauncherTestFixture;
 import org.apache.brooklyn.rest.testing.mocks.RestMockSimpleEntity;
 import org.apache.brooklyn.test.HttpTestUtils;
 
 import brooklyn.util.collections.MutableList;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.net.Urls;
 
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ServerResourceIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ServerResourceIntegrationTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ServerResourceIntegrationTest.java
index c228b95..0dcfd44 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ServerResourceIntegrationTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/resources/ServerResourceIntegrationTest.java
@@ -18,7 +18,7 @@
  */
 package org.apache.brooklyn.rest.resources;
 
-import static brooklyn.util.http.HttpTool.httpClientBuilder;
+import static org.apache.brooklyn.core.util.http.HttpTool.httpClientBuilder;
 import static org.testng.Assert.assertEquals;
 
 import java.net.URI;
@@ -37,14 +37,13 @@ import brooklyn.config.BrooklynProperties;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.rest.BrooklynRestApiLauncher;
 import org.apache.brooklyn.rest.BrooklynRestApiLauncherTestFixture;
 import org.apache.brooklyn.rest.security.provider.TestSecurityProvider;
 import org.apache.brooklyn.test.HttpTestUtils;
 
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
-
 import com.google.common.collect.ImmutableMap;
 
 public class ServerResourceIntegrationTest extends BrooklynRestApiLauncherTestFixture {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 04baadf..1bb5677 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
@@ -23,6 +23,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,8 +35,8 @@ import brooklyn.entity.basic.MethodEffector;
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicConfigKey;
+
 import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.flags.SetFromFlag;
 
 public class RestMockSimpleEntity extends SoftwareProcessImpl {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimplePolicy.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimplePolicy.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimplePolicy.java
index 92d488f..d6e2b77 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimplePolicy.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimplePolicy.java
@@ -20,13 +20,13 @@ package org.apache.brooklyn.rest.testing.mocks;
 
 import java.util.Map;
 
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.policy.basic.AbstractPolicy;
-import brooklyn.util.flags.SetFromFlag;
 
 public class RestMockSimplePolicy extends AbstractPolicy {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java
index 642fc10..7968089 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/util/json/BrooklynJacksonSerializerTest.java
@@ -43,6 +43,7 @@ import brooklyn.entity.basic.Entities;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.http.HttpTool;
 import org.apache.brooklyn.rest.BrooklynRestApiLauncher;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
@@ -51,7 +52,6 @@ import org.apache.brooklyn.test.entity.TestEntity;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.http.HttpTool;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java
index c0f78ac..771ba6d 100644
--- a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java
+++ b/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java
@@ -34,15 +34,14 @@ import java.util.Properties;
 
 import javax.management.remote.JMXConnectorServer;
 
+import org.apache.brooklyn.core.util.crypto.FluentKeySigner;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import brooklyn.util.crypto.FluentKeySigner;
-import brooklyn.util.crypto.SecureKeys;
-
 public class JmxmpAgentSslTest {
 
     KeyPair caRootKey;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java
----------------------------------------------------------------------
diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java
index d8fc178..3896631 100644
--- a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java
+++ b/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java
@@ -40,7 +40,8 @@ import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
 
-import brooklyn.util.crypto.SecureKeys;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+
 import brooklyn.util.crypto.SslTrustUtils;
 
 @SuppressWarnings({"rawtypes","unchecked"})

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimpleLocation.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimpleLocation.java b/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimpleLocation.java
index bf64795..9817017 100644
--- a/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimpleLocation.java
+++ b/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimpleLocation.java
@@ -20,8 +20,9 @@ package brooklyn.osgi.tests;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
+
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.location.basic.AbstractLocation;
-import brooklyn.util.flags.SetFromFlag;
 
 public class SimpleLocation extends AbstractLocation {
     @SetFromFlag("config1")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimplePolicy.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimplePolicy.java b/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimplePolicy.java
index 10a0094..f70b60b 100644
--- a/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimplePolicy.java
+++ b/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimplePolicy.java
@@ -19,10 +19,11 @@
 package brooklyn.osgi.tests;
 
 
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.config.ConfigKey;
 import brooklyn.policy.basic.AbstractPolicy;
-import brooklyn.util.flags.SetFromFlag;
 
 public class SimplePolicy extends AbstractPolicy {
     @SetFromFlag("config1")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/utils/test-bundles/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java b/utils/test-bundles/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
index 80d6b97..ece1b1e 100644
--- a/utils/test-bundles/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
+++ b/utils/test-bundles/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
@@ -18,9 +18,10 @@
  */
 package brooklyn.osgi.tests.more;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
+
 import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.effector.EffectorBody;
-import brooklyn.util.config.ConfigBag;
 
 
 public class MoreEntityImpl extends AbstractEntity implements MoreEntity {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java b/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
index 238d743..3dd4059 100644
--- a/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
+++ b/utils/test-bundles/more-entities-v2-evil-twin/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
@@ -21,7 +21,7 @@ package brooklyn.osgi.tests.more;
 import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.effector.EffectorBody;
 import org.apache.brooklyn.api.policy.PolicySpec;
-import brooklyn.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 
 public class MoreEntityImpl extends AbstractEntity implements MoreEntity {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/utils/test-bundles/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java b/utils/test-bundles/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
index 327fd23..e560b54 100644
--- a/utils/test-bundles/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
+++ b/utils/test-bundles/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MoreEntityImpl.java
@@ -21,7 +21,7 @@ package brooklyn.osgi.tests.more;
 import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.effector.EffectorBody;
 import org.apache.brooklyn.api.policy.PolicySpec;
-import brooklyn.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 
 public class MoreEntityImpl extends AbstractEntity implements MoreEntity {


[53/64] incubator-brooklyn git commit: brooklyn-software-database: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbLiveRackspaceTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbLiveRackspaceTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbLiveRackspaceTest.java
new file mode 100644
index 0000000..d5fcb25
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbLiveRackspaceTest.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.entity.database.mariadb;
+
+import java.util.Arrays;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import brooklyn.util.net.Protocol;
+import brooklyn.util.ssh.IptablesCommands;
+import brooklyn.util.ssh.IptablesCommands.Chain;
+import brooklyn.util.ssh.IptablesCommands.Policy;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * The MariaDbLiveTest installs MariaDb on various operating systems like Ubuntu, CentOS, Red Hat etc. To make sure that
+ * MariaDb works like expected on these Operating Systems.
+ */
+public class MariaDbLiveRackspaceTest extends MariaDbIntegrationTest {
+    @Test(groups = {"Live"})
+    public void test_Debian_6() throws Exception {
+        test("Debian 6");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_Ubuntu_10_0() throws Exception {
+        test("Ubuntu 10.0");
+    }
+
+    @Test(groups = {"Live", "Live-sanity"})
+    public void test_Ubuntu_12_0() throws Exception {
+        test("Ubuntu 12.0");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_Ubuntu_13() throws Exception {
+        test("Ubuntu 13");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_CentOS_6() throws Exception {
+        test("CentOS 6");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_CentOS_5() throws Exception {
+        test("CentOS 5");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_Fedora() throws Exception {
+        test("Fedora ");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_Red_Hat_Enterprise_Linux_6() throws Exception {
+        test("Red Hat Enterprise Linux 6");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_localhost() throws Exception {
+        super.test_localhost();
+    }
+
+    public void test(String osRegex) throws Exception {
+        MariaDbNode mariadb = tapp.createAndManageChild(EntitySpec.create(MariaDbNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, CREATION_SCRIPT));
+
+        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageNameRegex", osRegex);
+        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.image-id");
+        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageId");
+        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.inboundPorts", Arrays.asList(22, 3306));
+        JcloudsLocation jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve("jclouds:rackspace-cloudservers-uk");
+
+        tapp.start(ImmutableList.of(jcloudsLocation));
+
+        SshMachineLocation l = (SshMachineLocation) mariadb.getLocations().iterator().next();
+        l.execCommands("add iptables rule", ImmutableList.of(IptablesCommands.insertIptablesRule(Chain.INPUT, Protocol.TCP, 3306, Policy.ACCEPT)));
+
+        new VogellaExampleAccess("com.mysql.jdbc.Driver", mariadb.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
+    } 
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterIntegrationTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterIntegrationTest.java
new file mode 100644
index 0000000..86764cf
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterIntegrationTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.entity.database.mysql;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.Iterables;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.util.os.Os;
+
+public class MySqlClusterIntegrationTest extends BrooklynAppLiveTestSupport {
+
+    @Test(groups = {"Integration"})
+    public void test_localhost() throws Exception {
+        try {
+            MySqlClusterTestHelper.test(app, mgmt.getLocationRegistry().resolve("localhost"));
+        } finally {
+            for (Entity member : Iterables.getOnlyElement(app.getChildren()).getChildren()) {
+                String runDir = member.getAttribute(MySqlNode.RUN_DIR);
+                if (runDir != null) {
+                    Os.deleteRecursively(runDir);
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterLiveEc2Test.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterLiveEc2Test.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterLiveEc2Test.java
new file mode 100644
index 0000000..1849ab0
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterLiveEc2Test.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.entity.database.mysql;
+
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+
+import org.apache.brooklyn.api.location.Location;
+
+@Test(groups = { "Live" })
+public class MySqlClusterLiveEc2Test extends AbstractEc2LiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        MySqlClusterTestHelper.test(app, loc);
+    }
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_Debian_7_2() throws Exception { } // Disabled because MySQl not available
+
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterLiveSoftlayerTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterLiveSoftlayerTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterLiveSoftlayerTest.java
new file mode 100644
index 0000000..a911200
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterLiveSoftlayerTest.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.entity.database.mysql;
+
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractSoftlayerLiveTest;
+
+import org.apache.brooklyn.api.location.Location;
+
+@Test(groups = { "Live" })
+public class MySqlClusterLiveSoftlayerTest extends AbstractSoftlayerLiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        MySqlClusterTestHelper.test(app, loc);
+    }
+
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterTestHelper.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterTestHelper.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterTestHelper.java
new file mode 100644
index 0000000..4080173
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterTestHelper.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.entity.database.mysql;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+
+/**
+ * Runs a slightly modified version of the popular Vogella MySQL tutorial,
+ * from
+ * http://www.vogella.de/articles/MySQLJava/article.html
+ */
+public class MySqlClusterTestHelper {
+    public static final Logger log = LoggerFactory.getLogger(MySqlClusterTestHelper.class);
+
+    // From http://www.vogella.de/articles/MySQLJava/article.html
+    public static final String CREATION_SCRIPT = Joiner.on("\n").join(ImmutableList.of(
+            "CREATE DATABASE feedback;",
+            "CREATE USER 'sqluser'@'localhost' IDENTIFIED BY 'sqluserpw';",
+            "GRANT USAGE ON *.* TO 'sqluser'@'localhost';",
+            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'localhost';",
+            "CREATE USER 'sqluser'@'%' IDENTIFIED BY 'sqluserpw';",
+            "GRANT USAGE ON *.* TO 'sqluser'@'%';",
+            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'%';",
+            "FLUSH PRIVILEGES;",
+            "USE feedback;",
+            "CREATE TABLE COMMENTS (",
+            "        id INT NOT NULL AUTO_INCREMENT,", 
+            "        MYUSER VARCHAR(30) NOT NULL,",
+            "        EMAIL VARCHAR(30), ",
+            "        WEBPAGE VARCHAR(100) NOT NULL,", 
+            "        DATUM DATE NOT NULL, ",
+            "        SUMMARY VARCHAR(40) NOT NULL,",
+            "        COMMENTS VARCHAR(400) NOT NULL,",
+            "        PRIMARY KEY (ID)",
+            "    );",
+            "",
+            "INSERT INTO COMMENTS values (default, 'lars', 'myemail@gmail.com','http://www.vogella.de', '2009-09-14 10:33:11', 'Summary','My first comment' );"
+            ));
+
+    public static void test(TestApplication app, Location location) throws Exception {
+        MySqlCluster mysql = app.createAndManageChild(EntitySpec.create(MySqlCluster.class)
+                .configure(MySqlCluster.INITIAL_SIZE, 2)
+                .configure(MySqlNode.MYSQL_SERVER_CONF, MutableMap.<String, Object>of("skip-name-resolve","")));
+
+        app.start(ImmutableList.of(location));
+        log.info("MySQL started");
+        MySqlNode masterEntity = (MySqlNode) mysql.getAttribute(MySqlCluster.FIRST);
+        masterEntity.invoke(MySqlNode.EXECUTE_SCRIPT, ImmutableMap.of("commands", CREATION_SCRIPT)).asTask().getUnchecked();
+
+        VogellaExampleAccess masterDb = new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(MySqlNode.DATASTORE_URL));
+        VogellaExampleAccess slaveDb = new VogellaExampleAccess("com.mysql.jdbc.Driver", Iterables.getOnlyElement(mysql.getAttribute(MySqlCluster.SLAVE_DATASTORE_URL_LIST)));
+        masterDb.connect();
+        slaveDb.connect();
+
+        assertSlave(masterDb, slaveDb, 1);
+        masterDb.modifyDataBase();
+        assertSlave(masterDb, slaveDb, 2);
+        masterDb.revertDatabase();
+        assertSlave(masterDb, slaveDb, 1);
+
+        masterDb.close();
+        slaveDb.close();
+
+        log.info("Ran vogella MySQL example -- SUCCESS");
+    }
+
+    private static void assertSlave(final VogellaExampleAccess masterDb, final VogellaExampleAccess slaveDb, final int recordCnt) throws Exception {
+        Asserts.succeedsEventually(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    List<List<String>> masterResult = masterDb.readDataBase();
+                    assertEquals(masterResult.size(), recordCnt);
+                    assertEquals(masterResult, slaveDb.readDataBase());
+                } catch (Exception e) {
+                    throw Exceptions.propagate(e);
+                }
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlIntegrationTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlIntegrationTest.java
new file mode 100644
index 0000000..d22a979
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlIntegrationTest.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.entity.database.mysql;
+
+import java.io.File;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Networking;
+import brooklyn.util.os.Os;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableList;
+import com.google.common.io.Files;
+
+/**
+ * Runs a slightly modified version of the popular Vogella MySQL tutorial,
+ * from
+ * http://www.vogella.de/articles/MySQLJava/article.html
+ */
+public class MySqlIntegrationTest extends BrooklynAppLiveTestSupport {
+
+    public static final Logger log = LoggerFactory.getLogger(MySqlIntegrationTest.class);
+    
+    // can start in AWS by running this -- or use brooklyn CLI/REST for most clouds, or programmatic/config for set of fixed IP machines
+    static String hostname = Networking.getLocalHost().getHostName();
+
+    // From http://www.vogella.de/articles/MySQLJava/article.html
+    // Expects COMMENTS to be injected as the test.table.name config value, for VogellaExampleAccess to work.
+    public static final String CREATION_SCRIPT = Joiner.on("\n").join(ImmutableList.of(
+            "CREATE DATABASE feedback;",
+            "CREATE USER 'sqluser'@'localhost' IDENTIFIED BY 'sqluserpw';",
+            "GRANT USAGE ON *.* TO 'sqluser'@'localhost';",
+            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'localhost';",
+            "CREATE USER 'sqluser'@'%' IDENTIFIED BY 'sqluserpw';",
+            "GRANT USAGE ON *.* TO 'sqluser'@'%';",
+            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'%';",
+            "CREATE USER 'sqluser'@'$hostname' IDENTIFIED BY 'sqluserpw';",
+            "GRANT USAGE ON *.* TO 'sqluser'@'$hostname';",
+            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'$hostname';",
+            "FLUSH PRIVILEGES;",
+            "USE feedback;",
+            "CREATE TABLE ${config['test.table.name']} (",
+            "        id INT NOT NULL AUTO_INCREMENT,", 
+            "        MYUSER VARCHAR(30) NOT NULL,",
+            "        EMAIL VARCHAR(30), ",
+            "        WEBPAGE VARCHAR(100) NOT NULL,", 
+            "        DATUM DATE NOT NULL, ",
+            "        SUMMARY VARCHAR(40) NOT NULL,",
+            "        COMMENTS VARCHAR(400) NOT NULL,",
+            "        PRIMARY KEY (ID)",
+            "    );",
+            "",
+            "INSERT INTO ${config['test.table.name']} values (default, 'lars', 'myemail@gmail.com','http://www.vogella.de', '2009-09-14 10:33:11', 'Summary','My first comment' );"
+            ));
+
+    @Test(groups = {"Integration"})
+    public void test_localhost() throws Exception {
+        File dataDir = Files.createTempDir();
+        try {
+            MySqlNode mysql = app.createAndManageChild(EntitySpec.create(MySqlNode.class)
+                    .configure("mysql.server.conf", MutableMap.of("skip-name-resolve",""))
+                    .configure("creationScriptContents", CREATION_SCRIPT)
+                    .configure("dataDir", dataDir.getAbsolutePath())
+                    .configure("test.table.name", "COMMENTS")); // to ensure creation script is templated
+            LocalhostMachineProvisioningLocation location = new LocalhostMachineProvisioningLocation();
+            
+            app.start(ImmutableList.of(location));;
+            log.info("MySQL started");
+    
+            new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(MySqlNode.DATASTORE_URL)).readModifyAndRevertDataBase();
+    
+            log.info("Ran vogella MySQL example -- SUCCESS");
+    
+            // Ensure the data directory was successfully overridden.
+            File mysqlSubdirFile = new File(dataDir, "mysql");
+            Assert.assertTrue(mysqlSubdirFile.exists());
+        } finally {
+            Os.deleteRecursively(dataDir);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveEc2Test.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveEc2Test.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveEc2Test.java
new file mode 100644
index 0000000..69afffc
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveEc2Test.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.entity.database.mysql;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+
+import com.google.common.collect.ImmutableList;
+
+@Test(groups = { "Live" })
+public class MySqlLiveEc2Test extends AbstractEc2LiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        MySqlNode mysql = app.createAndManageChild(EntitySpec.create(MySqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
+                .configure("test.table.name", "COMMENTS"));
+
+        app.start(ImmutableList.of(loc));
+
+        new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
+    }
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_Debian_7_2() throws Exception { } // Disabled because MySQl not available
+
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveGceTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveGceTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveGceTest.java
new file mode 100644
index 0000000..3af4daa
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveGceTest.java
@@ -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.entity.database.mysql;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractGoogleComputeLiveTest;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+
+import com.google.common.collect.ImmutableList;
+
+@Test(groups = { "Live" })
+public class MySqlLiveGceTest extends AbstractGoogleComputeLiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        MySqlNode mysql = app.createAndManageChild(EntitySpec.create(MySqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
+                .configure("test.table.name", "COMMENTS"));
+
+        app.start(ImmutableList.of(loc));
+
+        new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
+    }
+
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveRackspaceTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveRackspaceTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveRackspaceTest.java
new file mode 100644
index 0000000..26f9fb9
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlLiveRackspaceTest.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.entity.database.mysql;
+
+import java.util.Arrays;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.testng.annotations.Test;
+
+import brooklyn.config.BrooklynProperties;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import brooklyn.util.net.Protocol;
+import brooklyn.util.ssh.IptablesCommands;
+import brooklyn.util.ssh.IptablesCommands.Chain;
+import brooklyn.util.ssh.IptablesCommands.Policy;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * The MySqlLiveTest installs MySQL on various operating systems like Ubuntu, CentOS, Red Hat etc. To make sure that
+ * MySQL works like expected on these Operating Systems.
+ */
+public class MySqlLiveRackspaceTest extends MySqlIntegrationTest {
+    @Test(groups = {"Live"})
+    public void test_Debian_6() throws Exception {
+        test("Debian 6");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_Ubuntu_10_0() throws Exception {
+        test("Ubuntu 10.0");
+    }
+
+    @Test(groups = {"Live", "Live-sanity"})
+    public void test_Ubuntu_12_0() throws Exception {
+        test("Ubuntu 12.0");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_Ubuntu_13() throws Exception {
+        test("Ubuntu 13");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_CentOS_6() throws Exception {
+        test("CentOS 6");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_CentOS_5() throws Exception {
+        test("CentOS 5");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_Fedora() throws Exception {
+        test("Fedora ");
+    }
+
+    @Test(groups = {"Live"})
+    public void test_Red_Hat_Enterprise_Linux_6() throws Exception {
+        test("Red Hat Enterprise Linux 6");
+    }
+
+    @Test(enabled=false, groups = {"Live"}) // only run this in MySqlIntegrationTest
+    public void test_localhost() throws Exception {
+        super.test_localhost();
+    }
+
+    public void test(String osRegex) throws Exception {
+        MySqlNode mysql = app.createAndManageChild(EntitySpec.create(MySqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, CREATION_SCRIPT)
+                .configure("test.table.name", "COMMENTS"));
+
+        BrooklynProperties brooklynProperties = mgmt.getBrooklynProperties();
+        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageNameRegex", osRegex);
+        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.image-id");
+        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageId");
+        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.inboundPorts", Arrays.asList(22, 3306));
+        JcloudsLocation jcloudsLocation = (JcloudsLocation) mgmt.getLocationRegistry().resolve("jclouds:rackspace-cloudservers-uk");
+
+        app.start(ImmutableList.of(jcloudsLocation));
+
+        SshMachineLocation l = (SshMachineLocation) mysql.getLocations().iterator().next();
+        l.execCommands("add iptables rule", ImmutableList.of(IptablesCommands.insertIptablesRule(Chain.INPUT, Protocol.TCP, 3306, Policy.ACCEPT)));
+
+        new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
+    } 
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlRestartIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlRestartIntegrationTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlRestartIntegrationTest.java
new file mode 100644
index 0000000..b0f0f72
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MySqlRestartIntegrationTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.entity.database.mysql;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.AbstractSoftwareProcessRestartIntegrationTest;
+import brooklyn.entity.basic.SoftwareProcess;
+
+/**
+ * Tests restart of the software *process* (as opposed to the VM).
+ */
+@Test(groups="Integration")
+public class MySqlRestartIntegrationTest extends AbstractSoftwareProcessRestartIntegrationTest {
+    
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(MySqlRestartIntegrationTest.class);
+
+    @Override
+    protected EntitySpec<? extends SoftwareProcess> newEntitySpec() {
+        return EntitySpec.create(MySqlNode.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MysqlDockerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MysqlDockerLiveTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MysqlDockerLiveTest.java
new file mode 100644
index 0000000..4bffa18
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mysql/MysqlDockerLiveTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.entity.database.mysql;
+
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import brooklyn.entity.software.AbstractDockerLiveTest;
+
+import com.google.common.collect.ImmutableList;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.testng.annotations.Test;
+
+public class MysqlDockerLiveTest extends AbstractDockerLiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+       MySqlNode mysql = app.createAndManageChild(EntitySpec.create(MySqlNode.class)
+               .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
+               .configure("test.table.name", "COMMENTS"));
+
+       app.start(ImmutableList.of(loc));
+
+       new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(DatastoreCommon.DATASTORE_URL))
+               .readModifyAndRevertDataBase();
+    }
+
+    @Test(enabled=false)
+    public void testDummy() { } // Convince testng IDE integration that this really does have test methods
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqDockerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqDockerLiveTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqDockerLiveTest.java
new file mode 100644
index 0000000..9789d18
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqDockerLiveTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.entity.database.postgresql;
+
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import brooklyn.entity.software.AbstractDockerLiveTest;
+
+import com.google.common.collect.ImmutableList;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.testng.annotations.Test;
+
+public class PostgreSqDockerLiveTest extends AbstractDockerLiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        PostgreSqlNode psql = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT));
+
+        app.start(ImmutableList.of(loc));
+
+        new VogellaExampleAccess("org.postgresql.Driver", psql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
+    }
+
+    @Test(enabled=false)
+    public void testDummy() { } // Convince testng IDE integration that this really does have test methods
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..1a75d88
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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.entity.database.postgresql;
+
+import java.util.Random;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.chef.ChefLiveTestSupport;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import brooklyn.entity.effector.EffectorTasks;
+import brooklyn.entity.software.SshEffectorTasks;
+
+import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.location.basic.PortRanges;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.time.Duration;
+
+import com.google.common.collect.ImmutableList;
+
+/** 
+ * Tests Chef installation of PostgreSql. Requires chef-server (knife).
+ * <p> 
+ * To be able to run repeatedly on the same box, you will need the patched version of the postgresql library,
+ * at https://github.com/opscode-cookbooks/postgresql/pull/73 .
+ *  
+ * @author alex
+ *
+ */
+public class PostgreSqlChefTest extends ChefLiveTestSupport {
+
+    private static final Logger log = LoggerFactory.getLogger(PostgreSqlChefTest.class);
+    
+    PostgreSqlNode psql;
+    
+    @Test(groups="Live")
+    public void testPostgresStartsAndStops() throws Exception {
+        ChefLiveTestSupport.installBrooklynChefHostedConfig(app);
+        psql = app.createAndManageChild(PostgreSqlSpecs.specChef());
+
+        app.start(ImmutableList.of(targetLocation));
+        
+        Entities.submit(psql, SshEffectorTasks.ssh("ps aux | grep [p]ostgres").requiringExitCodeZero());
+        SshMachineLocation targetMachine = EffectorTasks.getSshMachine(psql);
+        
+        psql.stop();
+        
+        try {
+            // if host is still contactable ensure postgres is not running
+            ProcessTaskWrapper<Integer> t = Entities.submit(app, SshEffectorTasks.ssh("ps aux | grep [p]ostgres").machine(targetMachine).allowingNonZeroExitCode());
+            t.getTask().blockUntilEnded(Duration.TEN_SECONDS);
+            if (!t.isDone())
+                Assert.fail("Task not finished yet: "+t.getTask());
+            Assert.assertNotEquals(t.get(), (Integer)0, "Task ended with code "+t.get()+"; output: "+t.getStdout() );
+        } catch (Exception e) {
+            // host has been killed, that is fine
+            log.info("Machine "+targetMachine+" destroyed on stop (expected - "+e+")");
+        }
+    }
+    
+    @Test(groups="Live")
+    public void testPostgresScriptAndAccess() throws Exception {
+        ChefLiveTestSupport.installBrooklynChefHostedConfig(app);
+        PortRange randomPort = PortRanges.fromString(String.format("%d+", 5420 + new Random().nextInt(10)));
+        psql = app.createAndManageChild(PostgreSqlSpecs.specChef()
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
+                .configure(PostgreSqlNode.POSTGRESQL_PORT, randomPort)
+                .configure(PostgreSqlNode.SHARED_MEMORY, "8MB")
+            );
+
+        app.start(ImmutableList.of(targetLocation));
+
+        String url = psql.getAttribute(DatastoreCommon.DATASTORE_URL);
+        log.info("Trying to connect to "+psql+" at "+url);
+        Assert.assertNotNull(url);
+        Assert.assertTrue(url.contains("542"));
+        
+        new VogellaExampleAccess("org.postgresql.Driver", url).readModifyAndRevertDataBase();
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlEc2LiveTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlEc2LiveTest.java
new file mode 100644
index 0000000..b65716b
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlEc2LiveTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.entity.database.postgresql;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+
+import com.google.common.collect.ImmutableList;
+
+public class PostgreSqlEc2LiveTest extends AbstractEc2LiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        PostgreSqlNode psql = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT));
+
+        app.start(ImmutableList.of(loc));
+
+        new VogellaExampleAccess("org.postgresql.Driver", psql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
+    }
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_Debian_6() throws Exception { } // Disabled because PostgreSql 9.1 not available
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_Ubuntu_10_0() throws Exception { } // Disabled because PostgreSql 9.1 not available
+
+    @Test(enabled=false)
+    public void testDummy() { } // Convince testng IDE integration that this really does have test methods
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlGceLiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlGceLiveTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlGceLiveTest.java
new file mode 100644
index 0000000..bec33c1
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlGceLiveTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.entity.database.postgresql;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractGoogleComputeLiveTest;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+
+import com.google.common.collect.ImmutableList;
+
+public class PostgreSqlGceLiveTest extends AbstractGoogleComputeLiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        PostgreSqlNode psql = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT));
+
+        app.start(ImmutableList.of(loc));
+
+        new VogellaExampleAccess("org.postgresql.Driver", psql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
+    }
+
+    @Test(enabled=false)
+    public void testDummy() { } // Convince testng IDE integration that this really does have test methods
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.java
new file mode 100644
index 0000000..ede5fec
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.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.entity.database.postgresql;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Runs the popular Vogella MySQL tutorial against PostgreSQL
+ * from
+ * http://www.vogella.de/articles/MySQLJava/article.html
+ */
+public class PostgreSqlIntegrationTest {
+
+    public static final Logger log = LoggerFactory.getLogger(PostgreSqlIntegrationTest.class);
+    
+    protected BrooklynProperties brooklynProperties;
+    protected ManagementContext managementContext;
+    protected TestApplication tapp;
+    
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() {
+        brooklynProperties = BrooklynProperties.Factory.newDefault();
+        managementContext = new LocalManagementContext(brooklynProperties);
+        tapp = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void ensureShutDown() {
+        Entities.destroyAllCatching(managementContext);
+    }
+
+    //from http://www.vogella.de/articles/MySQLJava/article.html
+    public static final String CREATION_SCRIPT =
+            "CREATE USER sqluser WITH PASSWORD 'sqluserpw';\n" +
+            "CREATE DATABASE feedback OWNER sqluser;\n" +
+            "\\c feedback;\n" +
+            "CREATE TABLE COMMENTS ( " +
+                    "id INT8 NOT NULL,  " +
+                    "MYUSER VARCHAR(30) NOT NULL, " +
+                    "EMAIL VARCHAR(30),  " +
+                    "WEBPAGE VARCHAR(100) NOT NULL,  " +
+                    "DATUM DATE NOT NULL,  " +
+                    "SUMMARY VARCHAR(40) NOT NULL, " +
+                    "COMMENTS VARCHAR(400) NOT NULL, " +
+                    "PRIMARY KEY (ID) " +
+                ");\n" +
+            "GRANT ALL ON comments TO sqluser;\n" +
+            "INSERT INTO COMMENTS values (1, 'lars', 'myemail@gmail.com','http://www.vogella.de', '2009-09-14 10:33:11', 'Summary','My first comment' );";
+
+    @Test(groups = "Integration")
+    public void test_localhost() throws Exception {
+        PostgreSqlNode pgsql = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, CREATION_SCRIPT)
+                .configure(PostgreSqlNode.MAX_CONNECTIONS, 10)
+                .configure(PostgreSqlNode.SHARED_MEMORY, "512kB")); // Very low so kernel configuration not needed
+
+        tapp.start(ImmutableList.of(new LocalhostMachineProvisioningLocation()));
+        String url = pgsql.getAttribute(DatastoreCommon.DATASTORE_URL);
+        log.info("PostgreSql started on "+url);
+        new VogellaExampleAccess("org.postgresql.Driver", url).readModifyAndRevertDataBase();
+        log.info("Ran vogella PostgreSql example -- SUCCESS");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRackspaceLiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRackspaceLiveTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRackspaceLiveTest.java
new file mode 100644
index 0000000..796c740
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRackspaceLiveTest.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.entity.database.postgresql;
+
+import java.util.Arrays;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import org.apache.brooklyn.location.basic.PortRanges;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+import brooklyn.util.net.Protocol;
+import brooklyn.util.ssh.IptablesCommands;
+import brooklyn.util.ssh.IptablesCommands.Chain;
+import brooklyn.util.ssh.IptablesCommands.Policy;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * The PostgreSqlRackspaceLiveTest installs Postgresql on various operating systems like Ubuntu, CentOS, Red Hat etc. To
+ * make sure that PostgreSql works like expected on these Operating Systems.
+ */
+public class PostgreSqlRackspaceLiveTest extends PostgreSqlIntegrationTest {
+    @Test(groups = "Live")
+    public void test_Debian_6() throws Exception {
+        test("Debian 6");
+    }
+
+    @Test(groups = "Live")
+    public void test_Ubuntu_10_0() throws Exception {
+        test("Ubuntu 10.0");
+    }
+
+    @Test(groups = "Live")
+    public void test_Ubuntu_11_0() throws Exception {
+        test("Ubuntu 11.0");
+    }
+
+    @Test(groups = "Live")
+    public void test_Ubuntu_12_0() throws Exception {
+        test("Ubuntu 12.0");
+    }
+
+    @Test(groups = "Live")
+    public void test_CentOS_6_0() throws Exception {
+        test("CentOS 6.0");
+    }
+
+    @Test(groups = "Live")
+    public void test_CentOS_5_6() throws Exception {
+        test("CentOS 5.6");
+    }
+
+    @Test(groups = "Live")
+    public void test_Fedora_17() throws Exception {
+        test("Fedora 17");
+    }
+
+    @Test(groups = "Live")
+    public void test_Red_Hat_Enterprise_Linux_6() throws Exception {
+        test("Red Hat Enterprise Linux 6");
+    }
+
+    @Test(groups = "Live")
+    public void test_localhost() throws Exception {
+        super.test_localhost();
+    }
+    
+    public void test(String osRegex) throws Exception {
+        PostgreSqlNode psql = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, CREATION_SCRIPT)
+                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(5432))
+                .configure(PostgreSqlNode.SHARED_MEMORY, "32MB"));
+
+        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageNameRegex", osRegex);
+        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.image-id");
+        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageId");
+        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.inboundPorts", Arrays.asList(22, 5432));
+        JcloudsLocation jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve("jclouds:rackspace-cloudservers-uk");
+
+        tapp.start(ImmutableList.of(jcloudsLocation));
+
+        SshMachineLocation l = (SshMachineLocation) psql.getLocations().iterator().next();
+        l.execCommands("add iptables rule", ImmutableList.of(IptablesCommands.insertIptablesRule(Chain.INPUT, Protocol.TCP, 5432, Policy.ACCEPT)));
+
+        String url = psql.getAttribute(DatastoreCommon.DATASTORE_URL);
+        new VogellaExampleAccess("org.postgresql.Driver", url).readModifyAndRevertDataBase();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRebindIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRebindIntegrationTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRebindIntegrationTest.java
new file mode 100644
index 0000000..8c3ee48
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRebindIntegrationTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.entity.database.postgresql;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.rebind.RebindTestFixtureWithApp;
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class PostgreSqlRebindIntegrationTest extends RebindTestFixtureWithApp {
+
+    private LocalhostMachineProvisioningLocation loc;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        loc = origApp.newLocalhostProvisioningLocation();
+    }
+
+    @Test(groups = {"Integration"})
+    public void testRebind() throws Exception {
+        origApp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class));
+        origApp.start(ImmutableList.of(loc));
+
+        // rebind
+        rebind();
+        final PostgreSqlNode newEntity = (PostgreSqlNode) Iterables.find(newApp.getChildren(), Predicates.instanceOf(PostgreSqlNode.class));
+
+        // confirm effectors still work on entity
+        EntityTestUtils.assertAttributeEqualsEventually(newEntity, PostgreSqlNode.SERVICE_UP, true);
+        newEntity.stop();
+        EntityTestUtils.assertAttributeEqualsEventually(newEntity, PostgreSqlNode.SERVICE_UP, false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRestartIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRestartIntegrationTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRestartIntegrationTest.java
new file mode 100644
index 0000000..4597d18
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlRestartIntegrationTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.entity.database.postgresql;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.AbstractSoftwareProcessRestartIntegrationTest;
+import brooklyn.entity.basic.SoftwareProcess;
+
+/**
+ * Tests restart of the software *process* (as opposed to the VM).
+ */
+@Test(groups="Integration")
+public class PostgreSqlRestartIntegrationTest extends AbstractSoftwareProcessRestartIntegrationTest {
+    
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(PostgreSqlRestartIntegrationTest.class);
+
+    @Override
+    protected EntitySpec<? extends SoftwareProcess> newEntitySpec() {
+        return EntitySpec.create(PostgreSqlNode.class);
+    }
+    
+    // TODO The second start() will fail because customize operations forbidden while there is existing data:
+    //      "If you want to create a new database system, either remove or empty".
+    // I haven't checked whether it damaged the data in the database though!
+    @Test(enabled=false, groups={"Integration", "WIP"})
+    public void testStopProcessAndStart() throws Exception {
+        super.testStopProcessAndStart();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepEc2LiveTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepEc2LiveTest.java
new file mode 100644
index 0000000..8686c5e
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepEc2LiveTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.entity.database.rubyrep;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
+import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
+
+import org.apache.brooklyn.location.basic.PortRanges;
+
+public class RubyRepEc2LiveTest extends AbstractEc2LiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        PostgreSqlNode db1 = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
+                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9111)));
+
+        PostgreSqlNode db2 = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
+                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9111)));
+
+        RubyRepIntegrationTest.startInLocation(app, db1, db2, loc);
+        RubyRepIntegrationTest.testReplication(db1, db2);
+    }
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_Debian_6() throws Exception { } // Disabled because PostgreSql 9.1 not available
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_Ubuntu_10_0() throws Exception { } // Disabled because PostgreSql 9.1 not available
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_Debian_7_2() throws Exception { } // Diabling all except Ubuntu 12.0 temporarily
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_CentOS_6_3() throws Exception { } // Diabling all except Ubuntu 12.0 temporarily
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_CentOS_5() throws Exception { } // Diabling all except Ubuntu 12.0 temporarily
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_Red_Hat_Enterprise_Linux_6() throws Exception { } // Diabling all except Ubuntu 12.0 temporarily
+
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepIntegrationTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepIntegrationTest.java
new file mode 100644
index 0000000..e58b250
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepIntegrationTest.java
@@ -0,0 +1,191 @@
+/*
+ * 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.entity.database.rubyrep;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.config.BrooklynProperties;
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import org.apache.brooklyn.entity.database.mysql.MySqlIntegrationTest;
+import org.apache.brooklyn.entity.database.mysql.MySqlNode;
+import org.apache.brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
+import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
+
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.basic.PortRanges;
+
+public class RubyRepIntegrationTest {
+
+    public static final Logger log = LoggerFactory.getLogger(RubyRepIntegrationTest.class);
+    protected BrooklynProperties brooklynProperties;
+    protected ManagementContext managementContext;
+    protected TestApplication tapp;
+    
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() {
+        brooklynProperties = BrooklynProperties.Factory.newDefault();
+        managementContext = new LocalManagementContext(brooklynProperties);
+        tapp = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() {
+        Entities.destroyAllCatching(managementContext);
+    }
+
+    @Test(groups = "Integration")
+    public void test_localhost_mysql() throws Exception {
+        MySqlNode db1 = tapp.createAndManageChild(EntitySpec.create(MySqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
+                .configure("test.table.name", "COMMENTS")
+                .configure(MySqlNode.MYSQL_PORT, PortRanges.fromInteger(9111)));
+
+        MySqlNode db2 = tapp.createAndManageChild(EntitySpec.create(MySqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
+                .configure("test.table.name", "COMMENTS")
+                .configure(MySqlNode.MYSQL_PORT, PortRanges.fromInteger(9112)));
+
+
+        startInLocation(tapp, db1, db2, new LocalhostMachineProvisioningLocation());
+        testReplication(db1, db2);
+    }
+
+    /**
+     * Altered to use a single postgresql server to avoid issues with shared memory limits
+     */
+    @Test(groups = {"Integration"})
+    public void test_localhost_postgres() throws Exception {
+        String createTwoDbsScript = PostgreSqlIntegrationTest.CREATION_SCRIPT +
+                PostgreSqlIntegrationTest.CREATION_SCRIPT.replaceAll("CREATE USER.*", "").replaceAll(" feedback", " feedback1");
+
+        PostgreSqlNode db1 = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, createTwoDbsScript)
+                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9113))
+                .configure(PostgreSqlNode.MAX_CONNECTIONS, 10)
+                .configure(PostgreSqlNode.SHARED_MEMORY, "512kB")); // Very low so kernel configuration not needed
+
+        startInLocation(tapp, db1, "feedback", db1, "feedback1", new LocalhostMachineProvisioningLocation());
+        testReplication(db1, "feedback", db1, "feedback1");
+    }
+
+    @Test(enabled = false, groups = "Integration") // TODO this doesn't appear to be supported by RubyRep
+    public void test_localhost_postgres_mysql() throws Exception {
+        PostgreSqlNode db1 = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
+                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9115))
+                .configure(PostgreSqlNode.MAX_CONNECTIONS, 10)
+                .configure(PostgreSqlNode.SHARED_MEMORY, "512kB")); // Very low so kernel configuration not needed
+
+        MySqlNode db2 = tapp.createAndManageChild(EntitySpec.create(MySqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
+                .configure(MySqlNode.MYSQL_PORT, PortRanges.fromInteger(9116)));
+
+        startInLocation(tapp, db1, db2, new LocalhostMachineProvisioningLocation());
+        testReplication(db1, db2);
+    }
+
+    public static void startInLocation(TestApplication tapp, DatastoreCommon db1, DatastoreCommon db2, Location... locations) throws Exception {
+        startInLocation(tapp, db1, "feedback", db2, "feedback", locations);
+    }
+
+    /**
+     * Configures rubyrep to connect to the two databases and starts the app
+     */
+    public static void startInLocation(TestApplication tapp, DatastoreCommon db1, String dbName1, DatastoreCommon db2, String dbName2, Location... locations) throws Exception {
+        tapp.createAndManageChild(EntitySpec.create(RubyRepNode.class)
+                .configure("startupTimeout", 300)
+                .configure("leftDatabase", db1)
+                .configure("rightDatabase", db2)
+                .configure("leftUsername", "sqluser")
+                .configure("rightUsername", "sqluser")
+                .configure("rightPassword", "sqluserpw")
+                .configure("leftPassword", "sqluserpw")
+                .configure("leftDatabaseName", dbName1)
+                .configure("rightDatabaseName", dbName2)
+                .configure("replicationInterval", 1)
+        );
+
+        tapp.start(Arrays.asList(locations));
+    }
+
+    public static void testReplication(DatastoreCommon db1, DatastoreCommon db2) throws Exception {
+        testReplication(db1, "feedback", db2, "feedback");
+    }
+
+    /**
+     * Tests replication between the two databases by altering the first and checking the change is applied to the second
+     */
+    public static void testReplication(DatastoreCommon db1, String dbName1, DatastoreCommon db2, String dbName2) throws Exception {
+        String db1Url = db1.getAttribute(DatastoreCommon.DATASTORE_URL);
+        String db2Url = db2.getAttribute(DatastoreCommon.DATASTORE_URL);
+
+        log.info("Testing replication between " + db1Url + " and " + db2Url);
+
+        VogellaExampleAccess vea1 = new VogellaExampleAccess(db1 instanceof MySqlNode ? "com.mysql.jdbc.Driver" : "org.postgresql.Driver", db1Url, dbName1);
+        VogellaExampleAccess vea2 = new VogellaExampleAccess(db2 instanceof MySqlNode ? "com.mysql.jdbc.Driver" : "org.postgresql.Driver", db2Url, dbName2);
+
+        try {
+            vea1.connect();
+            List<List<String>> rs = vea1.readDataBase();
+            assertEquals(rs.size(), 1);
+
+            vea2.connect();
+            rs = vea2.readDataBase();
+            assertEquals(rs.size(), 1);
+
+            log.info("Modifying left database");
+            vea1.modifyDataBase();
+
+            log.info("Reading left database");
+            rs = vea1.readDataBase();
+            assertEquals(rs.size(), 2);
+
+            log.info("Reading right database");
+            rs = vea2.readDataBase();
+
+            for (int i = 0; i < 60 && rs.size() != 2; i++) {
+                log.info("Sleeping for a second");
+                Thread.sleep(1000);
+                rs = vea2.readDataBase();
+            }
+
+            assertEquals(rs.size(), 2);
+        } finally {
+            vea1.close();
+            vea2.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepRackspaceLiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepRackspaceLiveTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepRackspaceLiveTest.java
new file mode 100644
index 0000000..f72b13c
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepRackspaceLiveTest.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.entity.database.rubyrep;
+
+import java.util.Arrays;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.testng.annotations.Test;
+
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
+import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
+
+import org.apache.brooklyn.location.basic.PortRanges;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.net.Protocol;
+import brooklyn.util.ssh.IptablesCommands;
+import brooklyn.util.ssh.IptablesCommands.Chain;
+import brooklyn.util.ssh.IptablesCommands.Policy;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * The RubyRepRackspaceLiveTest installs RubyRep on various operating systems like Ubuntu, CentOS, Red Hat etc. To make sure that
+ * RubyRep and PostgreSql works like expected on these Operating Systems.
+ */
+public class RubyRepRackspaceLiveTest extends RubyRepIntegrationTest {
+    
+    @Test(groups = "Live")
+    public void test_Debian_6() throws Exception {
+        test("Debian 6");
+    }
+
+    @Test(groups = "Live")
+    public void test_Ubuntu_10_0() throws Exception {
+        test("Ubuntu 10.0");
+    }
+
+    @Test(groups = "Live")
+    public void test_Ubuntu_12_0() throws Exception {
+        test("Ubuntu 12.0");
+    }
+
+    @Test(groups = "Live")
+    public void test_Ubuntu_13() throws Exception {
+        test("Ubuntu 13");
+    }
+
+    @Test(groups = "Live")
+    public void test_CentOS_6() throws Exception {
+        test("CentOS 6");
+    }
+
+    @Test(groups = "Live")
+    public void test_CentOS_5() throws Exception {
+        test("CentOS 5");
+    }
+
+    @Test(groups = "Live")
+    public void test_Fedora() throws Exception {
+        test("Fedora ");
+    }
+
+    @Test(groups = "Live")
+    public void test_Red_Hat_Enterprise_Linux_6() throws Exception {
+        test("Red Hat Enterprise Linux 6");
+    }
+
+    public void test(String osRegex) throws Exception {
+        PostgreSqlNode db1 = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
+                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9111)));
+        PostgreSqlNode db2 = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
+                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9111)));
+
+        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageNameRegex", osRegex);
+        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.image-id");
+        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageId");
+        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.inboundPorts", Arrays.asList(22, 9111));
+        Location loc = managementContext.getLocationRegistry().resolve("jclouds:rackspace-cloudservers-uk");
+        
+        startInLocation(tapp, db1, db2, loc);
+
+        //hack to get the port for mysql open; is the inbounds property not respected on rackspace??
+        for (DatastoreCommon node : ImmutableSet.of(db1, db2)) {
+            SshMachineLocation l = (SshMachineLocation) node.getLocations().iterator().next();
+            l.execCommands("add iptables rule", ImmutableList.of(IptablesCommands.insertIptablesRule(Chain.INPUT, Protocol.TCP, 9111, Policy.ACCEPT)));
+        }
+
+        testReplication(db1, db2);
+    }
+    
+    // disable inherited non-live tests
+    @Test(enabled = false, groups = "Integration")
+    public void test_localhost_mysql() throws Exception {
+        super.test_localhost_mysql();
+    }
+
+    // disable inherited non-live tests
+    @Test(enabled = false, groups = "Integration")
+    public void test_localhost_postgres() throws Exception {
+        super.test_localhost_postgres();
+    }
+
+    // disable inherited non-live tests
+    @Test(enabled = false, groups = "Integration")
+    public void test_localhost_postgres_mysql() throws Exception {
+        super.test_localhost_postgres_mysql();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 5b58c72..48bfafa 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
@@ -41,7 +41,7 @@ import brooklyn.entity.BrooklynAppLiveTestSupport;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.SameServerEntity;
 import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.database.mysql.MySqlNode;
+import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import brooklyn.event.basic.DependentConfiguration;
 
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;



[05/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/enricher/TimeFractionDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/TimeFractionDeltaEnricher.java b/policy/src/main/java/brooklyn/enricher/TimeFractionDeltaEnricher.java
index e1fce23..d86aec0 100644
--- a/policy/src/main/java/brooklyn/enricher/TimeFractionDeltaEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/TimeFractionDeltaEnricher.java
@@ -27,9 +27,9 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.enricher.basic.AbstractTypeTransformingEnricher;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java b/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
index 3f7357d..0d5e066 100644
--- a/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/TimeWeightedDeltaEnricher.java
@@ -24,13 +24,13 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.enricher.basic.AbstractTypeTransformingEnricher;
 import brooklyn.enricher.basic.YamlTimeWeightedDeltaEnricher;
 import brooklyn.util.GroovyJavaMethods;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetrics.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetrics.java b/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetrics.java
index e927c1e..f717812 100644
--- a/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetrics.java
+++ b/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetrics.java
@@ -21,10 +21,10 @@ package brooklyn.entity.brooklyn;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 @ImplementedBy(BrooklynMetricsImpl.class)
 public interface BrooklynMetrics extends Entity {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetricsImpl.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetricsImpl.java b/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetricsImpl.java
index 93ece4a..caf1120 100644
--- a/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetricsImpl.java
+++ b/policy/src/main/java/brooklyn/entity/brooklyn/BrooklynMetricsImpl.java
@@ -26,9 +26,9 @@ import java.util.concurrent.TimeUnit;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.internal.LocalSubscriptionManager;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
 
 import brooklyn.entity.basic.AbstractEntity;
-import brooklyn.util.task.BasicExecutionManager;
 
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java b/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
index 28c2123..9da5e12 100644
--- a/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
@@ -40,6 +40,9 @@ import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.Tasks;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BrooklynTaskTags;
@@ -52,9 +55,6 @@ import brooklyn.policy.autoscaling.SizeHistory.WindowSummary;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.loadbalancing.LoadBalancingPolicy;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java b/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
index 1747424..dde1609 100644
--- a/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
@@ -38,6 +38,7 @@ import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,7 +47,6 @@ import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.followthesun.FollowTheSunPool.ContainerItemPair;
 import brooklyn.policy.loadbalancing.Movable;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java b/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
index f88dc60..0c2f4d2 100644
--- a/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
+++ b/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
@@ -28,6 +28,9 @@ import java.util.concurrent.atomic.AtomicReference;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.apache.brooklyn.core.util.task.ScheduledTask;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,9 +42,6 @@ import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.task.BasicTask;
-import brooklyn.util.task.ScheduledTask;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/ha/ConditionalSuspendPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/ConditionalSuspendPolicy.java b/policy/src/main/java/brooklyn/policy/ha/ConditionalSuspendPolicy.java
index 9be8256..9a869ae 100644
--- a/policy/src/main/java/brooklyn/policy/ha/ConditionalSuspendPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/ha/ConditionalSuspendPolicy.java
@@ -23,13 +23,13 @@ import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.policy.basic.AbstractPolicy;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.javalang.JavaClassNames;
 
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/ha/ConnectionFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/ConnectionFailureDetector.java b/policy/src/main/java/brooklyn/policy/ha/ConnectionFailureDetector.java
index a1a59a4..ff5d60e 100644
--- a/policy/src/main/java/brooklyn/policy/ha/ConnectionFailureDetector.java
+++ b/policy/src/main/java/brooklyn/policy/ha/ConnectionFailureDetector.java
@@ -20,13 +20,13 @@ package brooklyn.policy.ha;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.event.Sensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.BasicNotificationSensor;
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.net.Networking;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/ha/ServiceFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/ServiceFailureDetector.java b/policy/src/main/java/brooklyn/policy/ha/ServiceFailureDetector.java
index 7ae6f33..2e4b719 100644
--- a/policy/src/main/java/brooklyn/policy/ha/ServiceFailureDetector.java
+++ b/policy/src/main/java/brooklyn/policy/ha/ServiceFailureDetector.java
@@ -24,6 +24,10 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.apache.brooklyn.core.util.task.ScheduledTask;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -38,11 +42,7 @@ import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.BasicNotificationSensor;
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.task.BasicTask;
-import brooklyn.util.task.ScheduledTask;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/ha/ServiceReplacer.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/ServiceReplacer.java b/policy/src/main/java/brooklyn/policy/ha/ServiceReplacer.java
index 459c13e..884f2df 100644
--- a/policy/src/main/java/brooklyn/policy/ha/ServiceReplacer.java
+++ b/policy/src/main/java/brooklyn/policy/ha/ServiceReplacer.java
@@ -35,6 +35,8 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -48,9 +50,7 @@ import brooklyn.event.basic.BasicNotificationSensor;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Ticker;
 import com.google.common.collect.Lists;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java b/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
index 3a3f0b4..d53434e 100644
--- a/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
+++ b/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
@@ -28,6 +28,8 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -40,8 +42,6 @@ import brooklyn.event.basic.BasicNotificationSensor;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/ha/SshMachineFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/SshMachineFailureDetector.java b/policy/src/main/java/brooklyn/policy/ha/SshMachineFailureDetector.java
index 7d31cf7..1fa9982 100644
--- a/policy/src/main/java/brooklyn/policy/ha/SshMachineFailureDetector.java
+++ b/policy/src/main/java/brooklyn/policy/ha/SshMachineFailureDetector.java
@@ -23,16 +23,18 @@ import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicNotificationSensor;
+
 import org.apache.brooklyn.location.basic.Machines;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/loadbalancing/ItemsInContainersGroup.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/loadbalancing/ItemsInContainersGroup.java b/policy/src/main/java/brooklyn/policy/loadbalancing/ItemsInContainersGroup.java
index ac93639..efd41d8 100644
--- a/policy/src/main/java/brooklyn/policy/loadbalancing/ItemsInContainersGroup.java
+++ b/policy/src/main/java/brooklyn/policy/loadbalancing/ItemsInContainersGroup.java
@@ -21,11 +21,11 @@ package brooklyn.policy.loadbalancing;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.DynamicGroup;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java b/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
index f5ae09c..2c50883 100644
--- a/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,7 +45,6 @@ import brooklyn.policy.autoscaling.AutoScalerPolicy;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.loadbalancing.BalanceableWorkerPool.ContainerItemPair;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/policy/loadbalancing/Movable.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/loadbalancing/Movable.java b/policy/src/main/java/brooklyn/policy/loadbalancing/Movable.java
index f95ba4f..b0f1658 100644
--- a/policy/src/main/java/brooklyn/policy/loadbalancing/Movable.java
+++ b/policy/src/main/java/brooklyn/policy/loadbalancing/Movable.java
@@ -19,6 +19,7 @@
 package brooklyn.policy.loadbalancing;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.Effector;
@@ -26,7 +27,6 @@ import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.entity.basic.MethodEffector;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/test/java/brooklyn/enricher/HttpLatencyDetectorTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/brooklyn/enricher/HttpLatencyDetectorTest.java b/policy/src/test/java/brooklyn/enricher/HttpLatencyDetectorTest.java
index 9777e03..7c7a9f3 100644
--- a/policy/src/test/java/brooklyn/enricher/HttpLatencyDetectorTest.java
+++ b/policy/src/test/java/brooklyn/enricher/HttpLatencyDetectorTest.java
@@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.http.BetterMockWebServer;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -35,9 +36,10 @@ import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.Entities;
 import brooklyn.event.basic.Sensors;
+
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.http.BetterMockWebServer;
 
 import com.google.common.collect.ImmutableList;
 import com.google.mockwebserver.MockResponse;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/test/java/brooklyn/enricher/RebindEnricherTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/brooklyn/enricher/RebindEnricherTest.java b/policy/src/test/java/brooklyn/enricher/RebindEnricherTest.java
index ac1b5c1..a01fd17 100644
--- a/policy/src/test/java/brooklyn/enricher/RebindEnricherTest.java
+++ b/policy/src/test/java/brooklyn/enricher/RebindEnricherTest.java
@@ -24,6 +24,7 @@ import java.net.URL;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.http.BetterMockWebServer;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.testng.annotations.AfterMethod;
@@ -33,7 +34,6 @@ import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.rebind.RebindTestFixtureWithApp;
 import brooklyn.event.basic.Sensors;
 import brooklyn.test.Asserts;
-import brooklyn.util.http.BetterMockWebServer;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/test/java/brooklyn/policy/ha/ServiceReplacerTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/brooklyn/policy/ha/ServiceReplacerTest.java b/policy/src/test/java/brooklyn/policy/ha/ServiceReplacerTest.java
index 5a88649..c679224 100644
--- a/policy/src/test/java/brooklyn/policy/ha/ServiceReplacerTest.java
+++ b/policy/src/test/java/brooklyn/policy/ha/ServiceReplacerTest.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
@@ -60,7 +61,6 @@ import org.apache.brooklyn.location.basic.SimulatedLocation;
 
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.test.Asserts;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.javalang.JavaClassNames;
 
 import com.google.common.base.Predicate;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/test/java/brooklyn/policy/ha/ServiceRestarterTest.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/brooklyn/policy/ha/ServiceRestarterTest.java b/policy/src/test/java/brooklyn/policy/ha/ServiceRestarterTest.java
index ce0fbf1..81cff78 100644
--- a/policy/src/test/java/brooklyn/policy/ha/ServiceRestarterTest.java
+++ b/policy/src/test/java/brooklyn/policy/ha/ServiceRestarterTest.java
@@ -31,6 +31,7 @@ import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -45,7 +46,6 @@ import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.trait.FailingEntity;
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.test.Asserts;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntity.java
----------------------------------------------------------------------
diff --git a/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntity.java b/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntity.java
index da4472e..70d4b57 100644
--- a/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntity.java
+++ b/policy/src/test/java/brooklyn/policy/loadbalancing/MockContainerEntity.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.EffectorParam;
@@ -30,7 +31,6 @@ import brooklyn.entity.basic.AbstractGroup;
 import brooklyn.entity.basic.MethodEffector;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 @ImplementedBy(MockContainerEntityImpl.class)
 public interface MockContainerEntity extends AbstractGroup, BalanceableContainer<Movable>, Startable {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessDriver.java b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessDriver.java
index bf7454d..a1b4ea8 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessDriver.java
@@ -29,19 +29,19 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.os.Os;
 import brooklyn.util.stream.ReaderInputStream;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Optional;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
index c8efbb9..31ee4be 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/AbstractSoftwareProcessSshDriver.java
@@ -29,6 +29,11 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.sshj.SshjTool;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -45,18 +50,15 @@ import brooklyn.entity.basic.lifecycle.ScriptHelper;
 import brooklyn.entity.effector.EffectorTasks;
 import brooklyn.entity.software.SshEffectorTasks;
 import brooklyn.event.feed.ConfigToAttributes;
+
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.internal.ssh.sshj.SshjTool;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.stream.KnownSizeInputStream;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.StringPredicates;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/SameServerDriverLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/SameServerDriverLifecycleEffectorTasks.java b/software/base/src/main/java/brooklyn/entity/basic/SameServerDriverLifecycleEffectorTasks.java
index 1a926a5..c7d19c1 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SameServerDriverLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SameServerDriverLifecycleEffectorTasks.java
@@ -27,6 +27,8 @@ import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.PortRange;
 import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,9 +45,7 @@ import brooklyn.entity.trait.StartableMethods;
 import org.apache.brooklyn.location.basic.LocationConfigKeys;
 
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.DynamicTasks;
 
 public class SameServerDriverLifecycleEffectorTasks extends MachineLifecycleEffectorTasks {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/SameServerEntity.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/SameServerEntity.java b/software/base/src/main/java/brooklyn/entity/basic/SameServerEntity.java
index 080cb87..374402a 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SameServerEntity.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SameServerEntity.java
@@ -24,6 +24,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ServiceStateLogic.ComputeServiceIndicatorsFromChildrenAndMembers;
@@ -31,7 +32,6 @@ import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.QuorumCheck;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/SameServerEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/SameServerEntityImpl.java b/software/base/src/main/java/brooklyn/entity/basic/SameServerEntityImpl.java
index 32050fd..ff58d89 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SameServerEntityImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SameServerEntityImpl.java
@@ -24,13 +24,13 @@ import java.util.Collection;
 
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
 
 import brooklyn.entity.basic.ServiceStateLogic.ComputeServiceIndicatorsFromChildrenAndMembers;
 import brooklyn.entity.software.MachineLifecycleEffectorTasks;
 import brooklyn.util.collections.QuorumCheck;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
 
 public class SameServerEntityImpl extends AbstractEntity implements SameServerEntity {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
index cf0dd6b..e80013f 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcess.java
@@ -24,6 +24,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Lifecycle.Transition;
@@ -33,7 +34,6 @@ import brooklyn.event.basic.AttributeSensorAndConfigKey;
 import brooklyn.event.basic.MapConfigKey;
 import brooklyn.event.basic.Sensors;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessDriverLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessDriverLifecycleEffectorTasks.java b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessDriverLifecycleEffectorTasks.java
index 1067333..457bb12 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessDriverLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessDriverLifecycleEffectorTasks.java
@@ -23,6 +23,8 @@ import java.util.Map;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,8 +33,6 @@ import brooklyn.entity.basic.SoftwareProcess.RestartSoftwareParameters;
 import brooklyn.entity.basic.SoftwareProcess.RestartSoftwareParameters.RestartMachineMode;
 import brooklyn.entity.software.MachineLifecycleEffectorTasks;
 import brooklyn.entity.trait.StartableMethods;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.text.Strings;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
index dffe783..0ae6339 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/SoftwareProcessImpl.java
@@ -18,7 +18,6 @@
  */
 package brooklyn.entity.basic;
 
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import groovy.time.TimeDuration;
 
@@ -42,6 +41,10 @@ import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.PortRange;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.policy.EnricherSpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,10 +61,7 @@ import org.apache.brooklyn.location.cloud.CloudLocationConfig;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.CountdownTimer;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java b/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java
index b66bd62..29ef57f 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/VanillaSoftwareProcessSshDriver.java
@@ -24,11 +24,13 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver;
+import org.apache.brooklyn.core.util.file.ArchiveUtils;
 
 import brooklyn.entity.basic.lifecycle.ScriptHelper;
+
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.file.ArchiveUtils;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunner.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunner.java b/software/base/src/main/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunner.java
index 670b1df..7d51e22 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunner.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunner.java
@@ -21,7 +21,7 @@ package brooklyn.entity.basic.lifecycle;
 import java.util.List;
 import java.util.Map;
 
-import brooklyn.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
 
 /** Marks something which can run scripts. Called "Naive" because it hides too much of the complexity,
  * about script execution and other ssh-related tasks (put, etc). The {@link SshTasks} approach seems better.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/basic/lifecycle/ScriptHelper.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/lifecycle/ScriptHelper.java b/software/base/src/main/java/brooklyn/entity/basic/lifecycle/ScriptHelper.java
index 07532f8..da9e0a1 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/lifecycle/ScriptHelper.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/lifecycle/ScriptHelper.java
@@ -19,7 +19,6 @@
 package brooklyn.entity.basic.lifecycle;
 
 import static java.lang.String.format;
-import brooklyn.util.internal.ssh.ShellTool;
 import groovy.lang.Closure;
 
 import java.io.ByteArrayOutputStream;
@@ -35,20 +34,23 @@ import javax.annotation.Nullable;
 import org.apache.brooklyn.api.management.ExecutionContext;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.TaskQueueingContext;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.mutex.WithMutexes;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BrooklynTaskTags;
+
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.GroovyJavaMethods;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
-import brooklyn.util.mutex.WithMutexes;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
index 7cbae99..22dae74 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynEntityMirrorImpl.java
@@ -25,6 +25,10 @@ import java.util.concurrent.Callable;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.entity.Effector;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.http.HttpStatus;
 
 import brooklyn.entity.basic.AbstractEntity;
@@ -39,11 +43,7 @@ import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.util.collections.Jsonya;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.net.Urls;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
index da6016b..83314db 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
@@ -31,6 +31,7 @@ import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.management.ha.ManagementNodeState;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BrooklynConfigKeys;
@@ -45,7 +46,6 @@ import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSens
 import brooklyn.event.basic.MapConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.net.Networking;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
index 4250b74..4f1c2d5 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
@@ -31,6 +31,11 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.TaskAdaptable;
 import org.apache.brooklyn.api.management.ha.ManagementNodeState;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskTags;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.http.HttpStatus;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,21 +64,18 @@ import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.event.feed.http.JsonFunctions;
+
 import org.apache.brooklyn.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.location.basic.Locations;
+
 import brooklyn.util.collections.Jsonya;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.PropagatedRuntimeException;
 import brooklyn.util.guava.Functionals;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.javalang.Enums;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.repeat.Repeater;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskTags;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
index ab4ffb2..55c544e 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
@@ -34,16 +34,18 @@ import brooklyn.entity.brooklynnode.BrooklynNode.ExistingFileBehaviour;
 import brooklyn.entity.drivers.downloads.DownloadSubstituters;
 import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
 import brooklyn.entity.software.SshEffectorTasks;
+
+import org.apache.brooklyn.core.util.file.ArchiveBuilder;
+import org.apache.brooklyn.core.util.file.ArchiveUtils;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.file.ArchiveBuilder;
-import brooklyn.util.file.ArchiveUtils;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.net.Networking;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClient.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClient.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClient.java
index 25df319..58d1229 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClient.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClient.java
@@ -20,8 +20,8 @@ package brooklyn.entity.brooklynnode;
 
 import java.util.Map;
 
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java
index 2403380..59449a2 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java
@@ -25,6 +25,9 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.HttpClient;
 import org.slf4j.Logger;
@@ -37,11 +40,8 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.net.Urls;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.Tasks;
 
 public class EntityHttpClientImpl implements EntityHttpClient {
     private static final Logger LOG = LoggerFactory.getLogger(EntityHttpClientImpl.class);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
index 0cb944e..05b28eb 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
@@ -23,11 +23,11 @@ import java.util.Collection;
 import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Effector;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 
 import brooklyn.entity.brooklynnode.BrooklynEntityMirrorImpl.RemoteEffector;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.effector.Effectors.EffectorBuilder;
-import brooklyn.util.http.HttpToolResponse;
 
 import com.google.common.base.Function;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
index 798f9b5..df902b1 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
@@ -31,6 +31,9 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.TaskAdaptable;
 import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.management.ha.ManagementNodeState;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -47,10 +50,7 @@ import brooklyn.entity.effector.EffectorBody;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.net.Urls;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
index 9c3a17b..1706a93 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynNodeUpgradeEffectorBody.java
@@ -26,6 +26,9 @@ import org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.management.ha.ManagementNodeState;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,10 +47,7 @@ import brooklyn.entity.effector.EffectorBody;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.software.SshEffectorTasks;
 import brooklyn.event.basic.MapConfigKey;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.net.Urls;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
index 3817b6b..d5a5555 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SelectMasterEffectorBody.java
@@ -27,6 +27,8 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.management.ha.ManagementNodeState;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,9 +41,7 @@ import brooklyn.entity.brooklynnode.BrooklynNode.SetHighAvailabilityPriorityEffe
 import brooklyn.entity.effector.EffectorBody;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.repeat.Repeater;
-import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
index 2edf67d..89387d5 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityModeEffectorBody.java
@@ -21,6 +21,8 @@ package brooklyn.entity.brooklynnode.effector;
 import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
 import org.apache.brooklyn.api.management.ha.ManagementNodeState;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.http.HttpStatus;
 
 import brooklyn.entity.brooklynnode.BrooklynNode;
@@ -30,9 +32,7 @@ import brooklyn.entity.effector.EffectorBody;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.event.feed.http.JsonFunctions;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Functionals;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.javalang.Enums;
 
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityPriorityEffectorBody.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityPriorityEffectorBody.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityPriorityEffectorBody.java
index 884d7ba..b9496d5 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityPriorityEffectorBody.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/SetHighAvailabilityPriorityEffectorBody.java
@@ -19,6 +19,8 @@
 package brooklyn.entity.brooklynnode.effector;
 
 import org.apache.brooklyn.api.entity.Effector;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.http.HttpStatus;
 
 import brooklyn.entity.brooklynnode.BrooklynNode;
@@ -26,8 +28,6 @@ import brooklyn.entity.brooklynnode.BrooklynNode.SetHighAvailabilityPriorityEffe
 import brooklyn.entity.brooklynnode.EntityHttpClient;
 import brooklyn.entity.effector.EffectorBody;
 import brooklyn.entity.effector.Effectors;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.http.HttpToolResponse;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/chef/ChefAttributeFeed.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/chef/ChefAttributeFeed.java b/software/base/src/main/java/brooklyn/entity/chef/ChefAttributeFeed.java
index fde4f51..8d3a1ef 100644
--- a/software/base/src/main/java/brooklyn/entity/chef/ChefAttributeFeed.java
+++ b/software/base/src/main/java/brooklyn/entity/chef/ChefAttributeFeed.java
@@ -31,6 +31,8 @@ import java.util.concurrent.TimeUnit;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,8 +43,6 @@ import brooklyn.event.feed.AbstractFeed;
 import brooklyn.event.feed.PollHandler;
 import brooklyn.event.feed.Poller;
 import brooklyn.event.feed.ssh.SshPollValue;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Joiner;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/chef/ChefConfig.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/chef/ChefConfig.java b/software/base/src/main/java/brooklyn/entity/chef/ChefConfig.java
index 769d8d0..e768280 100644
--- a/software/base/src/main/java/brooklyn/entity/chef/ChefConfig.java
+++ b/software/base/src/main/java/brooklyn/entity/chef/ChefConfig.java
@@ -18,11 +18,12 @@
  */
 package brooklyn.entity.chef;
 
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.MapConfigKey;
 import brooklyn.event.basic.SetConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.annotations.Beta;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java b/software/base/src/main/java/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
index 9f6bf82..402d8d3 100644
--- a/software/base/src/main/java/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/brooklyn/entity/chef/ChefLifecycleEffectorTasks.java
@@ -23,6 +23,11 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskTags;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,14 +42,9 @@ import org.apache.brooklyn.location.basic.Machines;
 import brooklyn.util.collections.Jsonya;
 import brooklyn.util.collections.Jsonya.Navigator;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.net.Urls;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskTags;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/chef/ChefServerTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/chef/ChefServerTasks.java b/software/base/src/main/java/brooklyn/entity/chef/ChefServerTasks.java
index 743e335..b192f0b 100644
--- a/software/base/src/main/java/brooklyn/entity/chef/ChefServerTasks.java
+++ b/software/base/src/main/java/brooklyn/entity/chef/ChefServerTasks.java
@@ -24,8 +24,8 @@ import java.io.IOException;
 import java.nio.charset.Charset;
 import java.security.KeyPair;
 
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.crypto.SecureKeys;
 
 import com.google.common.base.Throwables;
 import com.google.common.io.Files;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/chef/ChefSoloDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/chef/ChefSoloDriver.java b/software/base/src/main/java/brooklyn/entity/chef/ChefSoloDriver.java
index 0d9935c..ce727af 100644
--- a/software/base/src/main/java/brooklyn/entity/chef/ChefSoloDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/chef/ChefSoloDriver.java
@@ -21,12 +21,13 @@ package brooklyn.entity.chef;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.management.TaskAdaptable;
 import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
 import brooklyn.entity.basic.ConfigKeys;
+
 import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.task.DynamicTasks;
 
 import com.google.common.annotations.Beta;
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/chef/ChefTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/chef/ChefTasks.java b/software/base/src/main/java/brooklyn/entity/chef/ChefTasks.java
index 369df99..31f99a5 100644
--- a/software/base/src/main/java/brooklyn/entity/chef/ChefTasks.java
+++ b/software/base/src/main/java/brooklyn/entity/chef/ChefTasks.java
@@ -23,19 +23,19 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.TaskAdaptable;
 import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.core.util.file.ArchiveTasks;
+import org.apache.brooklyn.core.util.file.ArchiveUtils.ArchiveType;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.effector.EffectorTasks;
 import brooklyn.entity.software.SshEffectorTasks;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.file.ArchiveTasks;
-import brooklyn.util.file.ArchiveUtils.ArchiveType;
 import brooklyn.util.net.Urls;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/chef/KnifeConvergeTaskFactory.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/chef/KnifeConvergeTaskFactory.java b/software/base/src/main/java/brooklyn/entity/chef/KnifeConvergeTaskFactory.java
index f9ec730..b32cad7 100644
--- a/software/base/src/main/java/brooklyn/entity/chef/KnifeConvergeTaskFactory.java
+++ b/software/base/src/main/java/brooklyn/entity/chef/KnifeConvergeTaskFactory.java
@@ -29,16 +29,18 @@ import com.google.common.base.Strings;
 import com.google.common.net.HostAndPort;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.effector.EffectorTasks;
+
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.collections.Jsonya;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/chef/KnifeTaskFactory.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/chef/KnifeTaskFactory.java b/software/base/src/main/java/brooklyn/entity/chef/KnifeTaskFactory.java
index f3b748f..52abcc2 100644
--- a/software/base/src/main/java/brooklyn/entity/chef/KnifeTaskFactory.java
+++ b/software/base/src/main/java/brooklyn/entity/chef/KnifeTaskFactory.java
@@ -24,15 +24,15 @@ import java.util.List;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.internal.ssh.process.ProcessTool;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.core.util.task.system.internal.SystemProcessTaskFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.util.collections.MutableList;
-import brooklyn.util.internal.ssh.process.ProcessTool;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.system.ProcessTaskFactory;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-import brooklyn.util.task.system.internal.SystemProcessTaskFactory;
 import brooklyn.util.text.StringEscapes.BashStringEscapes;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java b/software/base/src/main/java/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
index 1853259..e6b3245 100644
--- a/software/base/src/main/java/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/java/JavaSoftwareProcessSshDriver.java
@@ -28,6 +28,13 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -48,18 +55,13 @@ import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.effector.EffectorTasks;
 import brooklyn.entity.software.SshEffectorTasks;
+
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.internal.ssh.ShellTool;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.system.ProcessTaskFactory;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.StringEscapes.BashStringEscapes;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java b/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java
index 2f88ff8..7e7c4c6 100644
--- a/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java
+++ b/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java
@@ -26,6 +26,9 @@ import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.core.util.BrooklynMavenArtifacts;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,11 +36,11 @@ import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.event.feed.jmx.JmxHelper;
+
 import org.apache.brooklyn.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.location.basic.Locations;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.BrooklynMavenArtifacts;
-import brooklyn.util.ResourceUtils;
+
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.guava.Maybe;
@@ -46,7 +49,6 @@ import brooklyn.util.jmx.jmxrmi.JmxRmiAgent;
 import brooklyn.util.maven.MavenArtifact;
 import brooklyn.util.maven.MavenRetriever;
 import brooklyn.util.net.Urls;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java b/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java
index 2c91999..dc57a3d 100644
--- a/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java
+++ b/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java
@@ -26,13 +26,14 @@ import java.security.PrivateKey;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 
+import org.apache.brooklyn.core.util.crypto.FluentKeySigner;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+import org.apache.brooklyn.core.util.task.Tasks;
+
 import brooklyn.util.collections.MutableMap.Builder;
-import brooklyn.util.crypto.FluentKeySigner;
-import brooklyn.util.crypto.SecureKeys;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.jmx.jmxmp.JmxmpAgent;
 import brooklyn.util.net.Urls;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.base.Preconditions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/java/UsesJava.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/java/UsesJava.java b/software/base/src/main/java/brooklyn/entity/java/UsesJava.java
index 1f824a1..a1afb97 100644
--- a/software/base/src/main/java/brooklyn/entity/java/UsesJava.java
+++ b/software/base/src/main/java/brooklyn/entity/java/UsesJava.java
@@ -18,6 +18,8 @@
  */
 package brooklyn.entity.java;
 
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 
@@ -25,7 +27,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.MapConfigKey;
 import brooklyn.event.basic.SetConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 public interface UsesJava {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/java/UsesJavaMXBeans.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/java/UsesJavaMXBeans.java b/software/base/src/main/java/brooklyn/entity/java/UsesJavaMXBeans.java
index f15e217..a556811 100644
--- a/software/base/src/main/java/brooklyn/entity/java/UsesJavaMXBeans.java
+++ b/software/base/src/main/java/brooklyn/entity/java/UsesJavaMXBeans.java
@@ -21,12 +21,12 @@ package brooklyn.entity.java;
 import java.util.Map;
 
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 public interface UsesJavaMXBeans {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/java/UsesJmx.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/java/UsesJmx.java b/software/base/src/main/java/brooklyn/entity/java/UsesJmx.java
index 141c5e5..2bb5bf0 100644
--- a/software/base/src/main/java/brooklyn/entity/java/UsesJmx.java
+++ b/software/base/src/main/java/brooklyn/entity/java/UsesJmx.java
@@ -24,6 +24,7 @@ import java.security.cert.Certificate;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -34,8 +35,6 @@ import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 
 import org.apache.brooklyn.location.basic.PortRanges;
 
-import brooklyn.util.flags.SetFromFlag;
-
 public interface UsesJmx extends UsesJava {
 
     public static final int DEFAULT_JMX_PORT = 1099; // RMI port?

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/java/VanillaJavaApp.java
----------------------------------------------------------------------
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 42e3090..6ae48e8 100644
--- a/software/base/src/main/java/brooklyn/entity/java/VanillaJavaApp.java
+++ b/software/base/src/main/java/brooklyn/entity/java/VanillaJavaApp.java
@@ -23,13 +23,13 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.Sensors;
 import brooklyn.util.collections.MutableList;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppImpl.java b/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppImpl.java
index 719a0ba..bbee991 100644
--- a/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppImpl.java
@@ -24,12 +24,12 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.annotations.VisibleForTesting;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppSshDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppSshDriver.java b/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppSshDriver.java
index 104dd7d..db1bb63 100644
--- a/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppSshDriver.java
@@ -28,16 +28,18 @@ import java.util.Map;
 import javax.annotation.Nullable;
 
 import brooklyn.entity.basic.lifecycle.ScriptHelper;
+
+import org.apache.brooklyn.core.util.file.ArchiveBuilder;
+import org.apache.brooklyn.core.util.file.ArchiveUtils;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.file.ArchiveBuilder;
-import brooklyn.util.file.ArchiveUtils;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.StringEscapes.BashStringEscapes;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/machine/MachineEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/machine/MachineEntityImpl.java b/software/base/src/main/java/brooklyn/entity/machine/MachineEntityImpl.java
index f101e66..7459c19 100644
--- a/software/base/src/main/java/brooklyn/entity/machine/MachineEntityImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/machine/MachineEntityImpl.java
@@ -31,11 +31,13 @@ import brooklyn.entity.software.SshEffectorTasks;
 import brooklyn.event.feed.ssh.SshFeed;
 import brooklyn.event.feed.ssh.SshPollConfig;
 import brooklyn.event.feed.ssh.SshPollValue;
+
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.location.basic.Machines;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
index c35e287..e5066f2 100644
--- a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
@@ -31,6 +31,7 @@ import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.api.management.LocationManager;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -51,7 +52,6 @@ import org.apache.brooklyn.location.dynamic.DynamicLocation;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.DynamicTasks;
 
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocation.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocation.java b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocation.java
index 704459b..df0a76c 100644
--- a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocation.java
+++ b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolLocation.java
@@ -34,11 +34,10 @@ import brooklyn.entity.basic.ConfigKeys;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.location.basic.AbstractLocation;
 import org.apache.brooklyn.location.dynamic.DynamicLocation;
 
-import brooklyn.util.flags.SetFromFlag;
-
 public class ServerPoolLocation extends AbstractLocation implements MachineProvisioningLocation<MachineLocation>,
         DynamicLocation<ServerPool, ServerPoolLocation> {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/service/EntityLaunchListener.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/service/EntityLaunchListener.java b/software/base/src/main/java/brooklyn/entity/service/EntityLaunchListener.java
index 354653d..e263d0d 100644
--- a/software/base/src/main/java/brooklyn/entity/service/EntityLaunchListener.java
+++ b/software/base/src/main/java/brooklyn/entity/service/EntityLaunchListener.java
@@ -28,11 +28,11 @@ import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.management.ExecutionManager;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.Tasks;
 
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.BrooklynTaskTags.EffectorCallTag;
 import brooklyn.entity.basic.Lifecycle;
-import brooklyn.util.task.Tasks;
 
 public class EntityLaunchListener implements Runnable, SensorEventListener<Lifecycle> {
     private static final String SSH_LAUNCH_TASK_PREFIX = "ssh: launching";


[61/64] incubator-brooklyn git commit: This closes #820

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


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

Branch: refs/heads/master
Commit: ab3a3db1b728f9e5f0f601b8d0344d4a873fd58e
Parents: ff5ec44 c14fef5
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Aug 18 11:27:42 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 18 11:27:42 2015 +0100

----------------------------------------------------------------------
 .../src/main/java/brooklyn/BrooklynVersion.java |    6 +-
 .../brooklyn/basic/AbstractBrooklynObject.java  |  249 ----
 .../brooklyn/basic/BasicConfigurableObject.java |  120 --
 .../brooklyn/basic/BrooklynDynamicType.java     |  284 -----
 .../brooklyn/basic/BrooklynObjectInternal.java  |  104 --
 .../brooklyn/basic/BrooklynTypeSnapshot.java    |  102 --
 .../main/java/brooklyn/basic/BrooklynTypes.java |  132 ---
 .../basic/internal/ApiObjectsFactoryImpl.java   |   42 -
 .../brooklyn/config/BrooklynProperties.java     |    6 +-
 .../brooklyn/config/BrooklynServerPaths.java    |    2 +-
 .../config/internal/AbstractConfigMapImpl.java  |    4 +-
 .../enricher/CustomAggregatingEnricher.java     |    2 +-
 .../main/java/brooklyn/enricher/Enrichers.java  |    2 +-
 .../enricher/basic/AbstractEnricher.java        |    4 +-
 .../basic/AbstractMultipleSensorAggregator.java |    2 +-
 .../basic/AbstractTypeTransformingEnricher.java |    2 +-
 .../brooklyn/enricher/basic/Aggregator.java     |    2 +-
 .../enricher/basic/EnricherDynamicType.java     |    2 +-
 .../enricher/basic/EnricherTypeSnapshot.java    |    2 +-
 .../java/brooklyn/enricher/basic/Joiner.java    |    2 +-
 .../brooklyn/enricher/basic/Propagator.java     |    6 +-
 .../brooklyn/enricher/basic/Transformer.java    |    4 +-
 .../brooklyn/enricher/basic/UpdatingMap.java    |    2 +-
 .../basic/YamlTimeWeightedDeltaEnricher.java    |    2 +-
 .../brooklyn/entity/basic/AbstractEffector.java |    4 +-
 .../brooklyn/entity/basic/AbstractEntity.java   |   16 +-
 .../java/brooklyn/entity/basic/BasicGroup.java  |    2 +-
 .../entity/basic/BrooklynConfigKeys.java        |    4 +-
 .../entity/basic/BrooklynShutdownHooks.java     |    2 +-
 .../brooklyn/entity/basic/BrooklynTaskTags.java |    6 +-
 .../java/brooklyn/entity/basic/ConfigKeys.java  |    2 +-
 .../java/brooklyn/entity/basic/DataEntity.java  |    2 +-
 .../brooklyn/entity/basic/DynamicGroup.java     |    2 +-
 .../brooklyn/entity/basic/DynamicGroupImpl.java |    2 +-
 .../entity/basic/EffectorStartableImpl.java     |    3 +-
 .../java/brooklyn/entity/basic/Entities.java    |   20 +-
 .../brooklyn/entity/basic/EntityConfigMap.java  |   10 +-
 .../entity/basic/EntityDynamicType.java         |    2 +-
 .../brooklyn/entity/basic/EntityFunctions.java  |    2 +-
 .../brooklyn/entity/basic/EntityInternal.java   |    4 +-
 .../basic/EntityTransientCopyInternal.java      |    2 +-
 .../entity/basic/EntityTypeSnapshot.java        |    2 +-
 .../java/brooklyn/entity/basic/EntityTypes.java |    2 +-
 .../java/brooklyn/entity/basic/Lifecycle.java   |    2 +-
 .../brooklyn/entity/basic/MethodEffector.java   |    2 +-
 .../java/brooklyn/entity/basic/Sanitizer.java   |    2 +-
 .../entity/basic/ServiceStateLogic.java         |    2 +-
 .../entity/effector/AddChildrenEffector.java    |    2 +-
 .../brooklyn/entity/effector/AddEffector.java   |    2 +-
 .../brooklyn/entity/effector/AddSensor.java     |    2 +-
 .../brooklyn/entity/effector/EffectorBody.java  |   10 +-
 .../brooklyn/entity/effector/EffectorTasks.java |   10 +-
 .../brooklyn/entity/effector/Effectors.java     |    4 +-
 .../group/AbstractMembershipTrackingPolicy.java |    2 +-
 .../java/brooklyn/entity/group/Cluster.java     |    2 +-
 .../brooklyn/entity/group/DynamicCluster.java   |    2 +-
 .../entity/group/DynamicClusterImpl.java        |    8 +-
 .../brooklyn/entity/group/DynamicFabric.java    |    2 +-
 .../entity/group/DynamicMultiGroup.java         |    2 +-
 .../entity/group/QuarantineGroupImpl.java       |    4 +-
 .../entity/proxying/EntityProxyImpl.java        |    6 +-
 .../entity/proxying/InternalEntityFactory.java  |    6 +-
 .../proxying/InternalLocationFactory.java       |    4 +-
 .../entity/proxying/InternalPolicyFactory.java  |    4 +-
 .../AbstractBrooklynObjectRebindSupport.java    |    4 +-
 .../rebind/ActivePartialRebindIteration.java    |    2 +-
 .../rebind/BasicCatalogItemRebindSupport.java   |    2 +-
 .../rebind/BasicEnricherRebindSupport.java      |    4 +-
 .../entity/rebind/BasicEntityRebindSupport.java |    2 +-
 .../entity/rebind/BasicFeedRebindSupport.java   |    4 +-
 .../rebind/BasicLocationRebindSupport.java      |    4 +-
 .../entity/rebind/BasicPolicyRebindSupport.java |    7 +-
 .../rebind/ImmediateDeltaChangeListener.java    |    2 +-
 .../rebind/PeriodicDeltaChangeListener.java     |    6 +-
 .../brooklyn/entity/rebind/RebindIteration.java |    8 +-
 .../entity/rebind/RebindManagerImpl.java        |    6 +-
 .../entity/rebind/dto/BasicEntityMemento.java   |    3 +-
 .../entity/rebind/dto/BasicLocationMemento.java |    2 +-
 .../entity/rebind/dto/MementosGenerators.java   |    8 +-
 .../BrooklynMementoPersisterToObjectStore.java  |    2 +-
 .../persister/BrooklynPersistenceUtils.java     |    4 +-
 .../rebind/persister/FileBasedObjectStore.java  |    2 +-
 .../rebind/persister/XmlMementoSerializer.java  |    2 +-
 .../rebind/transformer/CompoundTransformer.java |    4 +-
 .../transformer/CompoundTransformerLoader.java  |    4 +-
 .../java/brooklyn/entity/trait/Startable.java   |    4 +-
 .../brooklyn/entity/trait/StartableMethods.java |    6 +-
 .../java/brooklyn/event/basic/AttributeMap.java |    2 +-
 .../basic/AttributeSensorAndConfigKey.java      |    2 +-
 .../brooklyn/event/basic/BasicConfigKey.java    |    4 +-
 .../event/basic/DependentConfiguration.java     |   16 +-
 .../basic/PortAttributeSensorAndConfigKey.java  |    2 +-
 ...platedStringAttributeSensorAndConfigKey.java |    2 +-
 .../java/brooklyn/event/feed/AbstractFeed.java  |    2 +-
 .../event/feed/AttributePollHandler.java        |    4 +-
 .../main/java/brooklyn/event/feed/Poller.java   |    6 +-
 .../java/brooklyn/event/feed/http/HttpFeed.java |    6 +-
 .../event/feed/http/HttpPollConfig.java         |    4 +-
 .../brooklyn/event/feed/http/HttpPollValue.java |    2 +-
 .../brooklyn/event/feed/http/HttpPolls.java     |    5 +-
 .../event/feed/http/HttpValueFunctions.java     |    3 +-
 .../brooklyn/event/feed/shell/ShellFeed.java    |    6 +-
 .../java/brooklyn/event/feed/ssh/SshFeed.java   |    6 +-
 .../windows/WindowsPerformanceCounterFeed.java  |    4 +-
 .../policy/basic/AbstractEntityAdjunct.java     |  510 --------
 .../brooklyn/policy/basic/AbstractPolicy.java   |  119 --
 .../java/brooklyn/policy/basic/AdjunctType.java |  174 ---
 .../brooklyn/policy/basic/ConfigMapImpl.java    |  140 ---
 .../policy/basic/GeneralPurposePolicy.java      |   36 -
 .../java/brooklyn/policy/basic/Policies.java    |   73 --
 .../policy/basic/PolicyDynamicType.java         |   44 -
 .../policy/basic/PolicyTypeSnapshot.java        |   40 -
 .../util/BrooklynLanguageExtensions.java        |   48 -
 .../brooklyn/util/BrooklynMavenArtifacts.java   |   58 -
 .../brooklyn/util/BrooklynNetworkUtils.java     |   41 -
 .../main/java/brooklyn/util/ResourceUtils.java  |  639 ----------
 .../java/brooklyn/util/config/ConfigBag.java    |  588 ----------
 .../brooklyn/util/crypto/FluentKeySigner.java   |  192 ---
 .../java/brooklyn/util/crypto/SecureKeys.java   |  184 ---
 .../java/brooklyn/util/file/ArchiveBuilder.java |  423 -------
 .../java/brooklyn/util/file/ArchiveTasks.java   |   58 -
 .../java/brooklyn/util/file/ArchiveUtils.java   |  351 ------
 .../util/flags/ClassCoercionException.java      |   39 -
 .../java/brooklyn/util/flags/FlagUtils.java     |  587 ----------
 .../brooklyn/util/flags/MethodCoercions.java    |  183 ---
 .../java/brooklyn/util/flags/SetFromFlag.java   |   71 --
 .../java/brooklyn/util/flags/TypeCoercions.java |  879 --------------
 .../main/java/brooklyn/util/http/HttpTool.java  |  387 -------
 .../brooklyn/util/http/HttpToolResponse.java    |  185 ---
 .../util/internal/ConfigKeySelfExtracting.java  |   41 -
 .../java/brooklyn/util/internal/Repeater.java   |  369 ------
 .../ssh/BackoffLimitedRetryHandler.java         |   74 --
 .../util/internal/ssh/ShellAbstractTool.java    |  442 -------
 .../brooklyn/util/internal/ssh/ShellTool.java   |  113 --
 .../util/internal/ssh/SshAbstractTool.java      |  172 ---
 .../util/internal/ssh/SshException.java         |   32 -
 .../brooklyn/util/internal/ssh/SshTool.java     |  174 ---
 .../util/internal/ssh/cli/SshCliTool.java       |  316 -----
 .../util/internal/ssh/process/ProcessTool.java  |  214 ----
 .../internal/ssh/sshj/SshjClientConnection.java |  282 -----
 .../util/internal/ssh/sshj/SshjTool.java        | 1091 ------------------
 .../util/javalang/ReflectionScanner.java        |  135 ---
 .../brooklyn/util/javalang/UrlClassLoader.java  |   69 --
 .../java/brooklyn/util/mutex/MutexSupport.java  |  120 --
 .../brooklyn/util/mutex/SemaphoreForTasks.java  |  112 --
 .../util/mutex/SemaphoreWithOwners.java         |  231 ----
 .../java/brooklyn/util/mutex/WithMutexes.java   |   45 -
 .../src/main/java/brooklyn/util/osgi/Osgis.java |  719 ------------
 .../util/task/AbstractExecutionContext.java     |   75 --
 .../util/task/BasicExecutionContext.java        |  221 ----
 .../util/task/BasicExecutionManager.java        |  755 ------------
 .../main/java/brooklyn/util/task/BasicTask.java |  892 --------------
 .../java/brooklyn/util/task/CanSetName.java     |   25 -
 .../java/brooklyn/util/task/CompoundTask.java   |  131 ---
 .../brooklyn/util/task/DeferredSupplier.java    |   38 -
 .../util/task/DynamicSequentialTask.java        |  480 --------
 .../java/brooklyn/util/task/DynamicTasks.java   |  337 ------
 .../brooklyn/util/task/ExecutionListener.java   |   31 -
 .../java/brooklyn/util/task/ExecutionUtils.java |   49 -
 .../java/brooklyn/util/task/ForwardingTask.java |  325 ------
 .../util/task/ListenableForwardingFuture.java   |   50 -
 .../java/brooklyn/util/task/ParallelTask.java   |   85 --
 .../java/brooklyn/util/task/ScheduledTask.java  |  185 ---
 .../java/brooklyn/util/task/SequentialTask.java |   58 -
 .../util/task/SingleThreadedScheduler.java      |  216 ----
 .../java/brooklyn/util/task/TaskBuilder.java    |  184 ---
 .../java/brooklyn/util/task/TaskInternal.java   |  125 --
 .../java/brooklyn/util/task/TaskScheduler.java  |   41 -
 .../main/java/brooklyn/util/task/TaskTags.java  |   71 --
 .../src/main/java/brooklyn/util/task/Tasks.java |  488 --------
 .../java/brooklyn/util/task/ValueResolver.java  |  426 -------
 .../util/task/ssh/SshFetchTaskFactory.java      |   89 --
 .../util/task/ssh/SshFetchTaskWrapper.java      |  135 ---
 .../util/task/ssh/SshPutTaskFactory.java        |  123 --
 .../brooklyn/util/task/ssh/SshPutTaskStub.java  |   69 --
 .../util/task/ssh/SshPutTaskWrapper.java        |  190 ---
 .../java/brooklyn/util/task/ssh/SshTasks.java   |  236 ----
 .../internal/AbstractSshExecTaskFactory.java    |   58 -
 .../ssh/internal/PlainSshExecTaskFactory.java   |   71 --
 .../util/task/system/ProcessTaskFactory.java    |   65 --
 .../util/task/system/ProcessTaskStub.java       |  101 --
 .../util/task/system/ProcessTaskWrapper.java    |  187 ---
 .../brooklyn/util/task/system/SystemTasks.java  |   29 -
 .../internal/AbstractProcessTaskFactory.java    |  214 ----
 .../system/internal/ExecWithLoggingHelpers.java |  200 ----
 .../internal/SystemProcessTaskFactory.java      |  131 ---
 .../brooklyn/util/text/DataUriSchemeParser.java |  267 -----
 .../brooklyn/util/text/TemplateProcessor.java   |  397 -------
 ...ompilerIndependentOuterClassFieldMapper.java |  166 ---
 .../xstream/EnumCaseForgivingConverter.java     |   60 -
 .../EnumCaseForgivingSingleValueConverter.java  |   35 -
 .../util/xstream/ImmutableListConverter.java    |   54 -
 .../util/xstream/ImmutableMapConverter.java     |   56 -
 .../util/xstream/ImmutableSetConverter.java     |   54 -
 .../util/xstream/Inet4AddressConverter.java     |   65 --
 .../brooklyn/util/xstream/MapConverter.java     |  104 --
 .../util/xstream/MutableSetConverter.java       |   44 -
 .../util/xstream/StringKeyMapConverter.java     |  134 ---
 .../brooklyn/util/xstream/XmlSerializer.java    |   97 --
 .../java/brooklyn/util/xstream/XmlUtil.java     |   59 -
 .../brooklyn/basic/AbstractBrooklynObject.java  |  249 ++++
 .../brooklyn/basic/BasicConfigurableObject.java |  120 ++
 .../brooklyn/basic/BrooklynDynamicType.java     |  284 +++++
 .../brooklyn/basic/BrooklynObjectInternal.java  |  104 ++
 .../brooklyn/basic/BrooklynTypeSnapshot.java    |  102 ++
 .../apache/brooklyn/basic/BrooklynTypes.java    |  132 +++
 .../basic/internal/ApiObjectsFactoryImpl.java   |   42 +
 .../catalog/internal/BasicBrooklynCatalog.java  |    4 +-
 .../catalog/internal/CatalogClasspathDo.java    |    6 +-
 .../core/catalog/internal/CatalogDto.java       |    2 +-
 .../core/catalog/internal/CatalogDtoUtils.java  |    2 +-
 .../catalog/internal/CatalogInitialization.java |    4 +-
 .../core/catalog/internal/CatalogItemDo.java    |    2 +-
 .../internal/CatalogItemDtoAbstract.java        |    6 +-
 .../core/catalog/internal/CatalogUtils.java     |    2 +-
 .../catalog/internal/CatalogXmlSerializer.java  |    8 +-
 .../internal/BrooklynFeatureEnablement.java     |    2 +-
 .../core/internal/BrooklynInitialization.java   |    9 +-
 .../management/entitlement/Entitlements.java    |    2 +-
 .../ha/HighAvailabilityManagerImpl.java         |    4 +-
 .../core/management/ha/OsgiManager.java         |    4 +-
 .../internal/AbstractManagementContext.java     |    8 +-
 .../internal/AsyncCollectionChangeAdapter.java  |    4 +-
 .../internal/BrooklynGarbageCollector.java      |    6 +-
 .../core/management/internal/EffectorUtils.java |    4 +-
 .../internal/EntityManagementUtils.java         |    4 +-
 .../management/internal/LocalEntityManager.java |    2 +-
 .../internal/LocalLocationManager.java          |    4 +-
 .../internal/LocalManagementContext.java        |   10 +-
 .../internal/LocalSubscriptionManager.java      |    4 +-
 .../management/internal/LocalUsageManager.java  |    2 +-
 .../internal/ManagementContextInternal.java     |    2 +-
 .../policy/basic/AbstractEntityAdjunct.java     |  510 ++++++++
 .../core/policy/basic/AbstractPolicy.java       |  119 ++
 .../brooklyn/core/policy/basic/AdjunctType.java |  174 +++
 .../core/policy/basic/ConfigMapImpl.java        |  140 +++
 .../core/policy/basic/GeneralPurposePolicy.java |   36 +
 .../brooklyn/core/policy/basic/Policies.java    |   73 ++
 .../core/policy/basic/PolicyDynamicType.java    |   44 +
 .../core/policy/basic/PolicyTypeSnapshot.java   |   40 +
 .../core/util/BrooklynLanguageExtensions.java   |   48 +
 .../core/util/BrooklynMavenArtifacts.java       |   58 +
 .../core/util/BrooklynNetworkUtils.java         |   44 +
 .../brooklyn/core/util/ResourceUtils.java       |  639 ++++++++++
 .../brooklyn/core/util/config/ConfigBag.java    |  589 ++++++++++
 .../core/util/crypto/FluentKeySigner.java       |  192 +++
 .../brooklyn/core/util/crypto/SecureKeys.java   |  186 +++
 .../brooklyn/core/util/file/ArchiveBuilder.java |  424 +++++++
 .../brooklyn/core/util/file/ArchiveTasks.java   |   58 +
 .../brooklyn/core/util/file/ArchiveUtils.java   |  351 ++++++
 .../core/util/flags/ClassCoercionException.java |   39 +
 .../brooklyn/core/util/flags/FlagUtils.java     |  587 ++++++++++
 .../core/util/flags/MethodCoercions.java        |  183 +++
 .../brooklyn/core/util/flags/SetFromFlag.java   |   71 ++
 .../brooklyn/core/util/flags/TypeCoercions.java |  879 ++++++++++++++
 .../brooklyn/core/util/http/HttpTool.java       |  387 +++++++
 .../core/util/http/HttpToolResponse.java        |  185 +++
 .../util/internal/ConfigKeySelfExtracting.java  |   41 +
 .../brooklyn/core/util/internal/Repeater.java   |  370 ++++++
 .../ssh/BackoffLimitedRetryHandler.java         |   74 ++
 .../util/internal/ssh/ShellAbstractTool.java    |  442 +++++++
 .../core/util/internal/ssh/ShellTool.java       |  113 ++
 .../core/util/internal/ssh/SshAbstractTool.java |  172 +++
 .../core/util/internal/ssh/SshException.java    |   32 +
 .../core/util/internal/ssh/SshTool.java         |  174 +++
 .../core/util/internal/ssh/cli/SshCliTool.java  |  317 +++++
 .../util/internal/ssh/process/ProcessTool.java  |  215 ++++
 .../internal/ssh/sshj/SshjClientConnection.java |  282 +++++
 .../core/util/internal/ssh/sshj/SshjTool.java   | 1091 ++++++++++++++++++
 .../core/util/javalang/ReflectionScanner.java   |  135 +++
 .../core/util/javalang/UrlClassLoader.java      |   70 ++
 .../brooklyn/core/util/mutex/MutexSupport.java  |  119 ++
 .../core/util/mutex/SemaphoreForTasks.java      |  112 ++
 .../core/util/mutex/SemaphoreWithOwners.java    |  231 ++++
 .../brooklyn/core/util/mutex/WithMutexes.java   |   45 +
 .../apache/brooklyn/core/util/osgi/Osgis.java   |  720 ++++++++++++
 .../util/task/AbstractExecutionContext.java     |   75 ++
 .../core/util/task/BasicExecutionContext.java   |  221 ++++
 .../core/util/task/BasicExecutionManager.java   |  755 ++++++++++++
 .../brooklyn/core/util/task/BasicTask.java      |  892 ++++++++++++++
 .../brooklyn/core/util/task/CanSetName.java     |   25 +
 .../brooklyn/core/util/task/CompoundTask.java   |  131 +++
 .../core/util/task/DeferredSupplier.java        |   38 +
 .../core/util/task/DynamicSequentialTask.java   |  480 ++++++++
 .../brooklyn/core/util/task/DynamicTasks.java   |  337 ++++++
 .../core/util/task/ExecutionListener.java       |   31 +
 .../brooklyn/core/util/task/ExecutionUtils.java |   49 +
 .../brooklyn/core/util/task/ForwardingTask.java |  325 ++++++
 .../util/task/ListenableForwardingFuture.java   |   50 +
 .../brooklyn/core/util/task/ParallelTask.java   |   85 ++
 .../brooklyn/core/util/task/ScheduledTask.java  |  185 +++
 .../brooklyn/core/util/task/SequentialTask.java |   58 +
 .../core/util/task/SingleThreadedScheduler.java |  216 ++++
 .../brooklyn/core/util/task/TaskBuilder.java    |  184 +++
 .../brooklyn/core/util/task/TaskInternal.java   |  125 ++
 .../brooklyn/core/util/task/TaskScheduler.java  |   41 +
 .../brooklyn/core/util/task/TaskTags.java       |   71 ++
 .../apache/brooklyn/core/util/task/Tasks.java   |  488 ++++++++
 .../brooklyn/core/util/task/ValueResolver.java  |  426 +++++++
 .../core/util/task/ssh/SshFetchTaskFactory.java |   88 ++
 .../core/util/task/ssh/SshFetchTaskWrapper.java |  135 +++
 .../core/util/task/ssh/SshPutTaskFactory.java   |  123 ++
 .../core/util/task/ssh/SshPutTaskStub.java      |   69 ++
 .../core/util/task/ssh/SshPutTaskWrapper.java   |  189 +++
 .../brooklyn/core/util/task/ssh/SshTasks.java   |  236 ++++
 .../internal/AbstractSshExecTaskFactory.java    |   58 +
 .../ssh/internal/PlainSshExecTaskFactory.java   |   71 ++
 .../util/task/system/ProcessTaskFactory.java    |   66 ++
 .../core/util/task/system/ProcessTaskStub.java  |  102 ++
 .../util/task/system/ProcessTaskWrapper.java    |  187 +++
 .../core/util/task/system/SystemTasks.java      |   29 +
 .../internal/AbstractProcessTaskFactory.java    |  216 ++++
 .../system/internal/ExecWithLoggingHelpers.java |  202 ++++
 .../internal/SystemProcessTaskFactory.java      |  131 +++
 .../core/util/text/DataUriSchemeParser.java     |  267 +++++
 .../core/util/text/TemplateProcessor.java       |  398 +++++++
 ...ompilerIndependentOuterClassFieldMapper.java |  166 +++
 .../xstream/EnumCaseForgivingConverter.java     |   60 +
 .../EnumCaseForgivingSingleValueConverter.java  |   35 +
 .../util/xstream/ImmutableListConverter.java    |   54 +
 .../util/xstream/ImmutableMapConverter.java     |   56 +
 .../util/xstream/ImmutableSetConverter.java     |   54 +
 .../util/xstream/Inet4AddressConverter.java     |   65 ++
 .../core/util/xstream/MapConverter.java         |  104 ++
 .../core/util/xstream/MutableSetConverter.java  |   44 +
 .../util/xstream/StringKeyMapConverter.java     |  134 +++
 .../core/util/xstream/XmlSerializer.java        |   97 ++
 .../brooklyn/core/util/xstream/XmlUtil.java     |   59 +
 .../location/access/BrooklynAccessUtils.java    |    8 +-
 .../PortForwardManagerLocationResolver.java     |    3 +-
 .../location/basic/AbstractLocation.java        |    8 +-
 .../basic/AbstractLocationResolver.java         |    2 +-
 .../AggregatingMachineProvisioningLocation.java |    2 +-
 .../location/basic/BasicLocationRegistry.java   |    2 +-
 .../location/basic/BasicMachineDetails.java     |   10 +-
 .../location/basic/ByonLocationResolver.java    |    4 +-
 .../FixedListMachineProvisioningLocation.java   |    4 +-
 .../location/basic/HostLocationResolver.java    |    2 +-
 .../basic/LocalhostLocationResolver.java        |    3 +-
 .../LocalhostMachineProvisioningLocation.java   |   10 +-
 ...calhostPropertiesFromBrooklynProperties.java |    3 +-
 .../location/basic/LocationConfigUtils.java     |    8 +-
 .../location/basic/LocationDynamicType.java     |    2 +-
 .../location/basic/LocationInternal.java        |    4 +-
 ...ocationPropertiesFromBrooklynProperties.java |    4 +-
 .../location/basic/LocationTypeSnapshot.java    |    2 +-
 .../brooklyn/location/basic/MultiLocation.java  |    2 +-
 .../location/basic/NamedLocationResolver.java   |    2 +-
 .../brooklyn/location/basic/PortRanges.java     |    3 +-
 .../basic/SingleMachineLocationResolver.java    |    2 +-
 .../SingleMachineProvisioningLocation.java      |    3 +-
 .../location/basic/SshMachineLocation.java      |   32 +-
 ...bstractCloudMachineProvisioningLocation.java |    4 +-
 .../location/cloud/CloudLocationConfig.java     |    3 +-
 .../cloud/names/AbstractCloudMachineNamer.java  |    4 +-
 .../cloud/names/BasicCloudMachineNamer.java     |    4 +-
 .../location/cloud/names/CloudMachineNamer.java |    3 +-
 .../cloud/names/CustomMachineNamer.java         |    6 +-
 .../location/dynamic/DynamicLocation.java       |    2 +-
 .../location/dynamic/LocationOwner.java         |    2 +-
 .../brooklyn/location/geo/HostGeoInfo.java      |    2 +-
 .../location/geo/LocalhostExternalIpLoader.java |    4 +-
 ...pi.basic.internal.ApiObjectsFactoryInterface |    2 +-
 .../brooklyn/camp/lite/CampYamlLiteTest.java    |    4 +-
 .../camp/lite/TestAppAssemblyInstantiator.java  |    2 +-
 .../enricher/basic/BasicEnricherTest.java       |    2 +-
 .../java/brooklyn/entity/EffectorSayHiTest.java |    2 +-
 .../entity/EntityPreManagementTest.java         |    2 +-
 .../java/brooklyn/entity/SetFromFlagTest.java   |    2 +-
 .../brooklyn/entity/basic/ConfigMapTest.java    |    4 +-
 .../basic/DependentConfigurationTest.java       |    2 +-
 .../brooklyn/entity/basic/EntityConfigTest.java |    2 +-
 .../brooklyn/entity/basic/EntitySpecTest.java   |    4 +-
 ...apListAndOtherStructuredConfigKeyTest.groovy |    2 +-
 .../entity/basic/PolicyRegistrationTest.java    |    2 +-
 .../brooklyn/entity/basic/SanitizerTest.java    |    3 +-
 .../entity/effector/EffectorBasicTest.java      |    2 +-
 .../effector/EffectorConcatenateTest.java       |    4 +-
 .../entity/effector/EffectorTaskTest.java       |   10 +-
 .../entity/group/GroupPickUpEntitiesTest.java   |    2 +-
 .../java/brooklyn/entity/rebind/Dumpers.java    |    2 +-
 .../entity/rebind/RebindCatalogEntityTest.java  |    3 +-
 .../entity/rebind/RebindCatalogItemTest.java    |    3 +-
 .../entity/rebind/RebindEnricherTest.java       |    2 +-
 .../rebind/RebindEntityDynamicTypeInfoTest.java |    2 +-
 .../entity/rebind/RebindEntityTest.java         |    2 +-
 .../entity/rebind/RebindFailuresTest.java       |    4 +-
 .../brooklyn/entity/rebind/RebindFeedTest.java  |    4 +-
 .../entity/rebind/RebindFeedWithHaTest.java     |    4 +-
 .../entity/rebind/RebindLocationTest.java       |    2 +-
 .../entity/rebind/RebindManagerTest.java        |    5 +-
 .../entity/rebind/RebindPolicyTest.java         |    4 +-
 .../entity/rebind/RebindTestFixture.java        |    2 +-
 .../transformer/impl/XsltTransformerTest.java   |    4 +-
 .../brooklyn/entity/trait/FailingEntity.java    |    2 +-
 .../entity/trait/FailingEntityImpl.java         |    2 +-
 .../entity/trait/StartableMethodsTest.java      |    3 +-
 .../java/brooklyn/event/feed/PollerTest.java    |    2 +-
 .../brooklyn/event/feed/http/HttpFeedTest.java  |    4 +-
 .../event/feed/http/HttpValueFunctionsTest.java |    3 +-
 .../brooklyn/policy/basic/BasicPolicyTest.java  |   89 --
 .../brooklyn/policy/basic/EnricherTypeTest.java |   59 -
 .../brooklyn/policy/basic/PolicyConfigTest.java |  202 ----
 .../policy/basic/PolicySubscriptionTest.java    |  125 --
 .../brooklyn/policy/basic/PolicyTypeTest.java   |   58 -
 .../EntityCleanupLongevityTestFixture.java      |    4 +-
 .../FilePersistencePerformanceTest.java         |    2 +-
 .../qa/performance/TaskPerformanceTest.java     |    4 +-
 .../test/java/brooklyn/test/HttpService.java    |    4 +-
 .../java/brooklyn/test/policy/TestEnricher.java |    2 +-
 .../java/brooklyn/test/policy/TestPolicy.java   |    4 +-
 .../util/BrooklynMavenArtifactsTest.java        |   96 --
 .../brooklyn/util/ResourceUtilsHttpTest.java    |  196 ----
 .../java/brooklyn/util/ResourceUtilsTest.java   |  189 ---
 .../brooklyn/util/config/ConfigBagTest.java     |  191 ---
 .../util/crypto/SecureKeysAndSignerTest.java    |  166 ---
 .../brooklyn/util/file/ArchiveBuilderTest.java  |  193 ----
 .../brooklyn/util/file/ArchiveUtilsTest.java    |  135 ---
 .../util/flags/MethodCoercionsTest.java         |  146 ---
 .../brooklyn/util/http/BetterMockWebServer.java |  138 ---
 .../util/http/HttpToolIntegrationTest.java      |   98 --
 .../brooklyn/util/internal/FlagUtilsTest.java   |  314 -----
 .../brooklyn/util/internal/RepeaterTest.groovy  |  255 ----
 .../util/internal/TypeCoercionsTest.java        |  360 ------
 .../util/internal/ssh/RecordingSshTool.java     |   95 --
 .../internal/ssh/ShellToolAbstractTest.java     |  439 -------
 .../ssh/SshToolAbstractIntegrationTest.java     |  301 -----
 .../ssh/SshToolAbstractPerformanceTest.java     |  137 ---
 .../ssh/cli/SshCliToolIntegrationTest.java      |  119 --
 .../ssh/cli/SshCliToolPerformanceTest.java      |   44 -
 .../ssh/process/ProcessToolIntegrationTest.java |   69 --
 .../ssh/process/ProcessToolStaticsTest.java     |   79 --
 .../sshj/SshjToolAsyncStubIntegrationTest.java  |  177 ---
 .../ssh/sshj/SshjToolIntegrationTest.java       |  313 -----
 .../ssh/sshj/SshjToolPerformanceTest.java       |   44 -
 .../brooklyn/util/mutex/WithMutexesTest.java    |  126 --
 .../test/java/brooklyn/util/osgi/OsgisTest.java |   41 -
 .../util/ssh/BashCommandsIntegrationTest.java   |  501 --------
 .../task/BasicTaskExecutionPerformanceTest.java |  206 ----
 .../util/task/BasicTaskExecutionTest.java       |  460 --------
 .../util/task/BasicTasksFutureTest.java         |  224 ----
 .../util/task/CompoundTaskExecutionTest.java    |  252 ----
 .../util/task/DynamicSequentialTaskTest.java    |  365 ------
 .../util/task/NonBasicTaskExecutionTest.java    |  126 --
 .../util/task/ScheduledExecutionTest.java       |  287 -----
 .../util/task/SingleThreadedSchedulerTest.java  |  192 ---
 .../util/task/TaskFinalizationTest.java         |   62 -
 .../test/java/brooklyn/util/task/TasksTest.java |  181 ---
 .../brooklyn/util/task/ValueResolverTest.java   |  132 ---
 .../brooklyn/util/task/ssh/SshTasksTest.java    |  207 ----
 .../util/task/system/SystemTasksTest.java       |  134 ---
 .../util/text/DataUriSchemeParserTest.java      |   52 -
 .../util/text/TemplateProcessorTest.java        |  179 ---
 .../util/xstream/CompilerCompatibilityTest.java |  154 ---
 .../util/xstream/ConverterTestFixture.java      |   40 -
 .../xstream/EnumCaseForgivingConverterTest.java |   52 -
 .../xstream/ImmutableListConverterTest.java     |   59 -
 .../util/xstream/InetAddressConverterTest.java  |   41 -
 .../util/xstream/StringKeyMapConverterTest.java |   77 --
 .../java/brooklyn/util/xstream/XmlUtilTest.java |   33 -
 .../core/catalog/internal/CatalogDtoTest.java   |    2 +-
 .../core/catalog/internal/CatalogLoadTest.java  |    3 +-
 .../core/catalog/internal/CatalogScanTest.java  |    2 +-
 .../AcmeEntitlementManagerTestFixture.java      |    2 +-
 .../entitlement/EntityEntitlementTest.java      |    2 +-
 .../internal/EntityExecutionManagerTest.java    |    8 +-
 .../management/osgi/OsgiStandaloneTest.java     |    6 +-
 .../osgi/OsgiVersionMoreEntityTest.java         |    2 +-
 .../core/policy/basic/BasicPolicyTest.java      |   90 ++
 .../core/policy/basic/EnricherTypeTest.java     |   59 +
 .../core/policy/basic/PolicyConfigTest.java     |  202 ++++
 .../policy/basic/PolicySubscriptionTest.java    |  128 ++
 .../core/policy/basic/PolicyTypeTest.java       |   59 +
 .../core/util/BrooklynMavenArtifactsTest.java   |   98 ++
 .../core/util/ResourceUtilsHttpTest.java        |  197 ++++
 .../brooklyn/core/util/ResourceUtilsTest.java   |  190 +++
 .../core/util/config/ConfigBagTest.java         |  193 ++++
 .../util/crypto/SecureKeysAndSignerTest.java    |  169 +++
 .../core/util/file/ArchiveBuilderTest.java      |  194 ++++
 .../core/util/file/ArchiveUtilsTest.java        |  139 +++
 .../core/util/flags/MethodCoercionsTest.java    |  149 +++
 .../core/util/http/BetterMockWebServer.java     |  138 +++
 .../core/util/http/HttpToolIntegrationTest.java |  100 ++
 .../core/util/internal/FlagUtilsTest.java       |  314 +++++
 .../core/util/internal/RepeaterTest.groovy      |  257 +++++
 .../core/util/internal/TypeCoercionsTest.java   |  360 ++++++
 .../util/internal/ssh/RecordingSshTool.java     |   97 ++
 .../internal/ssh/ShellToolAbstractTest.java     |  441 +++++++
 .../ssh/SshToolAbstractIntegrationTest.java     |  304 +++++
 .../ssh/SshToolAbstractPerformanceTest.java     |  138 +++
 .../ssh/cli/SshCliToolIntegrationTest.java      |  119 ++
 .../ssh/cli/SshCliToolPerformanceTest.java      |   44 +
 .../ssh/process/ProcessToolIntegrationTest.java |   69 ++
 .../ssh/process/ProcessToolStaticsTest.java     |   80 ++
 .../sshj/SshjToolAsyncStubIntegrationTest.java  |  178 +++
 .../ssh/sshj/SshjToolIntegrationTest.java       |  314 +++++
 .../ssh/sshj/SshjToolPerformanceTest.java       |   44 +
 .../core/util/mutex/WithMutexesTest.java        |  129 +++
 .../brooklyn/core/util/osgi/OsgisTest.java      |   41 +
 .../util/ssh/BashCommandsIntegrationTest.java   |  504 ++++++++
 .../task/BasicTaskExecutionPerformanceTest.java |  209 ++++
 .../core/util/task/BasicTaskExecutionTest.java  |  462 ++++++++
 .../core/util/task/BasicTasksFutureTest.java    |  227 ++++
 .../util/task/CompoundTaskExecutionTest.java    |  258 +++++
 .../util/task/DynamicSequentialTaskTest.java    |  371 ++++++
 .../util/task/NonBasicTaskExecutionTest.java    |  130 +++
 .../core/util/task/ScheduledExecutionTest.java  |  291 +++++
 .../util/task/SingleThreadedSchedulerTest.java  |  195 ++++
 .../core/util/task/TaskFinalizationTest.java    |   63 +
 .../brooklyn/core/util/task/TasksTest.java      |  184 +++
 .../core/util/task/ValueResolverTest.java       |  134 +++
 .../core/util/task/ssh/SshTasksTest.java        |  213 ++++
 .../core/util/task/system/SystemTasksTest.java  |  137 +++
 .../core/util/text/DataUriSchemeParserTest.java |   53 +
 .../core/util/text/TemplateProcessorTest.java   |  180 +++
 .../util/xstream/CompilerCompatibilityTest.java |  158 +++
 .../core/util/xstream/ConverterTestFixture.java |   40 +
 .../xstream/EnumCaseForgivingConverterTest.java |   53 +
 .../xstream/ImmutableListConverterTest.java     |   60 +
 .../util/xstream/InetAddressConverterTest.java  |   42 +
 .../util/xstream/StringKeyMapConverterTest.java |   78 ++
 .../brooklyn/core/util/xstream/XmlUtilTest.java |   34 +
 .../location/basic/AbstractLocationTest.java    |    2 +-
 .../basic/LegacyAbstractLocationTest.java       |    2 +-
 .../location/basic/LocationConfigTest.java      |    2 +-
 .../location/basic/LocationConfigUtilsTest.java |    3 +-
 .../brooklyn/location/basic/PortRangesTest.java |    3 +-
 .../SshMachineLocationIntegrationTest.java      |    9 +-
 .../SshMachineLocationPerformanceTest.java      |    2 +-
 .../SshMachineLocationReuseIntegrationTest.java |    4 +-
 .../location/basic/SshMachineLocationTest.java  |   14 +-
 .../location/cloud/CloudMachineNamerTest.java   |    4 +-
 .../location/cloud/CustomMachineNamerTest.java  |    3 +-
 .../brooklyn/test/entity/BlockingEntity.java    |    2 +-
 .../apache/brooklyn/test/entity/TestEntity.java |    2 +-
 .../rebind/compiler_compatibility_eclipse.xml   |   20 +-
 .../rebind/compiler_compatibility_oracle.xml    |   18 +-
 .../brooklyn/demo/GlobalWebFabricExample.java   |    6 +-
 .../brooklyn/demo/KafkaClusterExample.java      |    2 +-
 .../demo/StandaloneQpidBrokerExample.java       |    4 +-
 .../brooklyn/demo/CumulusRDFApplication.java    |    8 +-
 .../apache/brooklyn/demo/StormSampleApp.java    |    2 +-
 .../demo/WebClusterDatabaseExampleApp.java      |    6 +-
 .../demo/WebClusterDatabaseExampleGroovy.groovy |    6 +-
 .../policy/os/AdvertiseWinrmLoginPolicy.java    |    3 +-
 .../brooklyn/policy/os/CreateUserPolicy.java    |    6 +-
 .../location/jclouds/BrooklynMachinePool.java   |    2 +-
 .../jclouds/ComputeServiceRegistry.java         |    3 +-
 .../jclouds/ComputeServiceRegistryImpl.java     |    2 +-
 .../jclouds/JcloudsByonLocationResolver.java    |    2 +-
 .../location/jclouds/JcloudsLocation.java       |   18 +-
 .../location/jclouds/JcloudsLocationConfig.java |    3 +-
 .../jclouds/JcloudsLocationCustomizer.java      |    3 +-
 .../location/jclouds/JcloudsMachineNamer.java   |    2 +-
 ...JcloudsPropertiesFromBrooklynProperties.java |    4 +-
 .../jclouds/JcloudsSshMachineLocation.java      |    2 +-
 .../brooklyn/location/jclouds/JcloudsUtil.java  |    2 +-
 .../jclouds/JcloudsWinRmMachineLocation.java    |    2 +-
 .../jclouds/SudoTtyFixingCustomizer.java        |    7 +-
 .../JcloudsLocationSecurityGroupCustomizer.java |    4 +-
 .../persister/jclouds/BlobStoreExpiryTest.java  |    6 +-
 .../policy/os/CreateUserPolicyLiveTest.java     |    2 +-
 .../policy/os/CreateUserPolicyTest.java         |    3 +-
 .../jclouds/AbstractJcloudsStubbedLiveTest.java |    3 +-
 .../jclouds/BailOutJcloudsLocation.java         |    2 +-
 ...ationTemplateOptionsCustomisersLiveTest.java |    4 +-
 .../location/jclouds/JcloudsLocationTest.java   |    2 +-
 .../jclouds/JcloudsMachineNamerTest.java        |    2 +-
 .../jclouds/RebindJcloudsLocationLiveTest.java  |    2 +-
 .../jclouds/RebindJcloudsLocationTest.java      |    3 +-
 .../java/brooklyn/enricher/DeltaEnricher.java   |    2 +-
 .../brooklyn/enricher/HttpLatencyDetector.java  |    2 +-
 .../brooklyn/enricher/RollingMeanEnricher.java  |    2 +-
 .../enricher/RollingTimeWindowMeanEnricher.java |    2 +-
 .../enricher/TimeFractionDeltaEnricher.java     |    2 +-
 .../enricher/TimeWeightedDeltaEnricher.java     |    2 +-
 .../entity/brooklyn/BrooklynMetrics.java        |    2 +-
 .../entity/brooklyn/BrooklynMetricsImpl.java    |    2 +-
 .../policy/autoscaling/AutoScalerPolicy.java    |    8 +-
 .../policy/followthesun/FollowTheSunPolicy.java |    4 +-
 .../policy/ha/AbstractFailureDetector.java      |    8 +-
 .../policy/ha/ConditionalSuspendPolicy.java     |    4 +-
 .../policy/ha/ConnectionFailureDetector.java    |    2 +-
 .../policy/ha/ServiceFailureDetector.java       |    8 +-
 .../brooklyn/policy/ha/ServiceReplacer.java     |    6 +-
 .../brooklyn/policy/ha/ServiceRestarter.java    |    6 +-
 .../policy/ha/SshMachineFailureDetector.java    |    4 +-
 .../loadbalancing/ItemsInContainersGroup.java   |    2 +-
 .../loadbalancing/LoadBalancingPolicy.java      |    4 +-
 .../brooklyn/policy/loadbalancing/Movable.java  |    2 +-
 .../enricher/HttpLatencyDetectorTest.java       |    4 +-
 .../brooklyn/enricher/RebindEnricherTest.java   |    2 +-
 .../brooklyn/policy/ha/ServiceReplacerTest.java |    2 +-
 .../policy/ha/ServiceRestarterTest.java         |    2 +-
 .../loadbalancing/MockContainerEntity.java      |    2 +-
 .../entity/database/derby/DerbyDatabase.java    |    4 +-
 .../database/derby/DerbyDatabaseSshDriver.java  |    4 +-
 .../entity/database/derby/DerbySchema.java      |    8 +-
 .../postgresql/PostgreSqlNodeSaltImpl.java      |   12 +-
 .../apache/brooklyn/entity/salt/SaltConfig.java |   11 +-
 .../brooklyn/entity/salt/SaltConfigs.java       |    4 +-
 .../entity/salt/SaltLifecycleEffectorTasks.java |    8 +-
 .../brooklyn/entity/salt/SaltStackMaster.java   |    9 +-
 .../entity/salt/SaltStackMasterSshDriver.java   |    5 +-
 .../apache/brooklyn/entity/salt/SaltTasks.java  |   13 +-
 .../postgresql/PostgreSqlSaltLiveTest.java      |   11 +-
 .../brooklyn/entity/salt/SaltConfigsTest.java   |    2 +-
 .../entity/salt/SaltLiveTestSupport.java        |    8 +-
 .../entity/monitoring/zabbix/ZabbixFeed.java    |    4 +-
 .../monitoring/zabbix/ZabbixMonitored.java      |    2 +-
 .../monitoring/zabbix/ZabbixPollConfig.java     |    2 +-
 .../entity/monitoring/zabbix/ZabbixServer.java  |    2 +-
 .../nosql/hazelcast/HazelcastCluster.java       |    9 +-
 .../nosql/hazelcast/HazelcastClusterImpl.java   |    8 +-
 .../entity/nosql/hazelcast/HazelcastNode.java   |    9 +-
 .../nosql/hazelcast/HazelcastNodeImpl.java      |    2 +-
 .../nosql/hazelcast/HazelcastNodeSshDriver.java |    6 +-
 .../nosql/infinispan/Infinispan5Server.java     |    4 +-
 .../nosql/infinispan/Infinispan5SshDriver.java  |    4 +-
 .../hazelcast/HazelcastClusterEc2LiveTest.java  |    4 +-
 .../HazelcastClusterSoftlayerLiveTest.java      |    4 +-
 .../Infinispan5ServerIntegrationTest.groovy     |    6 +-
 .../basic/AbstractSoftwareProcessDriver.java    |    8 +-
 .../basic/AbstractSoftwareProcessSshDriver.java |   12 +-
 .../SameServerDriverLifecycleEffectorTasks.java |    4 +-
 .../brooklyn/entity/basic/SameServerEntity.java |    2 +-
 .../entity/basic/SameServerEntityImpl.java      |    6 +-
 .../brooklyn/entity/basic/SoftwareProcess.java  |    2 +-
 ...wareProcessDriverLifecycleEffectorTasks.java |    4 +-
 .../entity/basic/SoftwareProcessImpl.java       |    8 +-
 .../basic/VanillaSoftwareProcessSshDriver.java  |    4 +-
 .../basic/lifecycle/NaiveScriptRunner.java      |    2 +-
 .../entity/basic/lifecycle/ScriptHelper.java    |   12 +-
 .../brooklynnode/BrooklynEntityMirrorImpl.java  |    8 +-
 .../entity/brooklynnode/BrooklynNode.java       |    2 +-
 .../entity/brooklynnode/BrooklynNodeImpl.java   |   12 +-
 .../brooklynnode/BrooklynNodeSshDriver.java     |   10 +-
 .../entity/brooklynnode/EntityHttpClient.java   |    4 +-
 .../brooklynnode/EntityHttpClientImpl.java      |    6 +-
 .../brooklynnode/RemoteEffectorBuilder.java     |    2 +-
 .../BrooklynClusterUpgradeEffectorBody.java     |    6 +-
 .../BrooklynNodeUpgradeEffectorBody.java        |    6 +-
 .../effector/SelectMasterEffectorBody.java      |    4 +-
 .../SetHighAvailabilityModeEffectorBody.java    |    4 +-
 ...SetHighAvailabilityPriorityEffectorBody.java |    4 +-
 .../brooklyn/entity/chef/ChefAttributeFeed.java |    4 +-
 .../java/brooklyn/entity/chef/ChefConfig.java   |    3 +-
 .../entity/chef/ChefLifecycleEffectorTasks.java |   10 +-
 .../brooklyn/entity/chef/ChefServerTasks.java   |    2 +-
 .../brooklyn/entity/chef/ChefSoloDriver.java    |    3 +-
 .../java/brooklyn/entity/chef/ChefTasks.java    |   10 +-
 .../entity/chef/KnifeConvergeTaskFactory.java   |    4 +-
 .../brooklyn/entity/chef/KnifeTaskFactory.java  |   10 +-
 .../java/JavaSoftwareProcessSshDriver.java      |   16 +-
 .../java/brooklyn/entity/java/JmxSupport.java   |    8 +-
 .../brooklyn/entity/java/JmxmpSslSupport.java   |    7 +-
 .../java/brooklyn/entity/java/UsesJava.java     |    3 +-
 .../brooklyn/entity/java/UsesJavaMXBeans.java   |    2 +-
 .../main/java/brooklyn/entity/java/UsesJmx.java |    3 +-
 .../brooklyn/entity/java/VanillaJavaApp.java    |    2 +-
 .../entity/java/VanillaJavaAppImpl.java         |    2 +-
 .../entity/java/VanillaJavaAppSshDriver.java    |   10 +-
 .../entity/machine/MachineEntityImpl.java       |    6 +-
 .../brooklyn/entity/pool/ServerPoolImpl.java    |    2 +-
 .../entity/pool/ServerPoolLocation.java         |    3 +-
 .../entity/service/EntityLaunchListener.java    |    2 +-
 .../entity/service/InitdServiceInstaller.java   |   12 +-
 .../entity/service/SystemServiceEnricher.java   |   14 +-
 .../entity/software/MachineInitTasks.java       |    8 +-
 .../software/MachineLifecycleEffectorTasks.java |    8 +-
 .../software/ProvidesProvisioningFlags.java     |    3 +-
 .../entity/software/SshEffectorTasks.java       |   24 +-
 .../brooklyn/entity/software/StaticSensor.java  |    6 +-
 .../entity/software/http/HttpRequestSensor.java |    2 +-
 .../software/java/JmxAttributeSensor.java       |    6 +-
 .../entity/software/ssh/SshCommandEffector.java |    2 +-
 .../entity/software/ssh/SshCommandSensor.java   |    4 +-
 .../winrm/WindowsPerformanceCounterSensors.java |    2 +-
 .../java/brooklyn/event/feed/jmx/JmxHelper.java |    2 +-
 .../basic/SoftwareProcessEntityLatchTest.java   |    2 +-
 .../basic/SoftwareProcessEntityRebindTest.java  |    3 +-
 .../entity/basic/SoftwareProcessEntityTest.java |    6 +-
 ...SoftwareProcessSshDriverIntegrationTest.java |    2 +-
 ...ftwareProcessAndChildrenIntegrationTest.java |    2 +-
 .../entity/basic/lifecycle/MyEntityImpl.java    |    6 +-
 .../basic/lifecycle/NaiveScriptRunnerTest.java  |    6 +-
 .../basic/lifecycle/StartStopSshDriverTest.java |    8 +-
 .../BrooklynNodeIntegrationTest.java            |    8 +-
 .../brooklynnode/CallbackEntityHttpClient.java  |    4 +-
 .../entity/chef/ChefLiveTestSupport.java        |    2 +-
 .../chef/ChefServerTasksIntegrationTest.java    |    2 +-
 .../ChefSoloDriverMySqlEntityLiveTest.java      |    2 +-
 .../java/brooklyn/entity/java/JavaOptsTest.java |    6 +-
 .../brooklyn/entity/java/JmxSupportTest.java    |    4 +-
 .../brooklyn/entity/java/SslKeyConfigTest.java  |    5 +-
 .../entity/java/VanillaJavaAppRebindTest.java   |    2 +-
 .../entity/java/VanillaJavaAppTest.java         |    8 +-
 .../MachineLifecycleEffectorTasksTest.java      |    4 +-
 .../entity/software/SoftwareEffectorTest.java   |    5 +-
 .../entity/software/SshEffectorTasksTest.java   |    6 +-
 .../entity/software/StaticSensorTest.java       |    2 +-
 .../software/http/HttpRequestSensorTest.java    |    2 +-
 .../mysql/AbstractToyMySqlEntityTest.java       |    2 +-
 .../mysql/DynamicToyMySqlEntityBuilder.java     |    8 +-
 .../software/ssh/SshCommandIntegrationTest.java |    2 +-
 .../entity/database/DatastoreMixins.java        |    4 +-
 .../entity/database/crate/CrateNode.java        |    3 +-
 .../entity/database/mariadb/MariaDbDriver.java  |    3 +-
 .../entity/database/mariadb/MariaDbNode.java    |    3 +-
 .../database/mariadb/MariaDbNodeImpl.java       |    4 +-
 .../database/mariadb/MariaDbSshDriver.java      |    4 +-
 .../entity/database/mysql/MySqlClusterImpl.java |    4 +-
 .../entity/database/mysql/MySqlDriver.java      |    3 +-
 .../entity/database/mysql/MySqlNode.java        |    3 +-
 .../entity/database/mysql/MySqlNodeImpl.java    |    4 +-
 .../entity/database/mysql/MySqlSshDriver.java   |    4 +-
 .../database/postgresql/PostgreSqlDriver.java   |    3 +-
 .../database/postgresql/PostgreSqlNode.java     |    3 +-
 .../PostgreSqlNodeChefImplFromScratch.java      |    8 +-
 .../database/postgresql/PostgreSqlNodeImpl.java |    2 +-
 .../postgresql/PostgreSqlSshDriver.java         |    8 +-
 .../entity/database/rubyrep/RubyRepNode.java    |    2 +-
 .../database/postgresql/PostgreSqlChefTest.java |    2 +-
 software/messaging/pom.xml                      |   10 +-
 .../entity/messaging/MessageBroker.java         |   34 -
 .../java/brooklyn/entity/messaging/Queue.java   |   51 -
 .../java/brooklyn/entity/messaging/Topic.java   |   46 -
 .../messaging/activemq/ActiveMQBroker.java      |   81 --
 .../messaging/activemq/ActiveMQBrokerImpl.java  |  124 --
 .../messaging/activemq/ActiveMQDestination.java |   24 -
 .../activemq/ActiveMQDestinationImpl.java       |   66 --
 .../messaging/activemq/ActiveMQDriver.java      |   28 -
 .../messaging/activemq/ActiveMQQueue.java       |   27 -
 .../messaging/activemq/ActiveMQQueueImpl.java   |   69 --
 .../messaging/activemq/ActiveMQSpecs.java       |   33 -
 .../messaging/activemq/ActiveMQSshDriver.java   |  145 ---
 .../messaging/activemq/ActiveMQTopic.java       |   27 -
 .../messaging/activemq/ActiveMQTopicImpl.java   |   50 -
 .../entity/messaging/amqp/AmqpExchange.java     |   45 -
 .../entity/messaging/amqp/AmqpServer.java       |   53 -
 .../entity/messaging/jms/JMSBroker.java         |   58 -
 .../entity/messaging/jms/JMSBrokerImpl.java     |  168 ---
 .../entity/messaging/jms/JMSDestination.java    |   29 -
 .../messaging/jms/JMSDestinationImpl.java       |   51 -
 .../kafka/AbstractfKafkaSshDriver.java          |  133 ---
 .../brooklyn/entity/messaging/kafka/Kafka.java  |   44 -
 .../entity/messaging/kafka/KafkaBroker.java     |   83 --
 .../messaging/kafka/KafkaBrokerDriver.java      |   27 -
 .../entity/messaging/kafka/KafkaBrokerImpl.java |  170 ---
 .../messaging/kafka/KafkaBrokerSshDriver.java   |   97 --
 .../entity/messaging/kafka/KafkaCluster.java    |   92 --
 .../messaging/kafka/KafkaClusterImpl.java       |  206 ----
 .../entity/messaging/kafka/KafkaZooKeeper.java  |   58 -
 .../messaging/kafka/KafkaZooKeeperDriver.java   |   28 -
 .../messaging/kafka/KafkaZooKeeperImpl.java     |   47 -
 .../kafka/KafkaZooKeeperSshDriver.java          |   82 --
 .../entity/messaging/qpid/QpidBroker.java       |   79 --
 .../entity/messaging/qpid/QpidBrokerImpl.java   |  147 ---
 .../entity/messaging/qpid/QpidDestination.java  |   32 -
 .../messaging/qpid/QpidDestinationImpl.java     |  101 --
 .../entity/messaging/qpid/QpidDriver.java       |   28 -
 .../entity/messaging/qpid/QpidQueue.java        |   29 -
 .../entity/messaging/qpid/QpidQueueImpl.java    |   66 --
 .../entity/messaging/qpid/QpidSshDriver.java    |  137 ---
 .../entity/messaging/qpid/QpidTopic.java        |   27 -
 .../entity/messaging/qpid/QpidTopicImpl.java    |   56 -
 .../entity/messaging/rabbit/RabbitBroker.java   |   91 --
 .../messaging/rabbit/RabbitBrokerImpl.java      |  121 --
 .../messaging/rabbit/RabbitDestination.java     |   92 --
 .../entity/messaging/rabbit/RabbitDriver.java   |   32 -
 .../entity/messaging/rabbit/RabbitQueue.java    |   85 --
 .../messaging/rabbit/RabbitSshDriver.java       |  208 ----
 .../brooklyn/entity/messaging/storm/Storm.java  |  105 --
 .../entity/messaging/storm/StormDeployment.java |   42 -
 .../messaging/storm/StormDeploymentImpl.java    |   77 --
 .../entity/messaging/storm/StormDriver.java     |   27 -
 .../entity/messaging/storm/StormImpl.java       |  118 --
 .../entity/messaging/storm/StormSshDriver.java  |  272 -----
 .../entity/zookeeper/AbstractZooKeeperImpl.java |  109 --
 .../entity/zookeeper/ZooKeeperDriver.java       |   27 -
 .../entity/zookeeper/ZooKeeperEnsemble.java     |   53 -
 .../entity/zookeeper/ZooKeeperEnsembleImpl.java |  105 --
 .../entity/zookeeper/ZooKeeperNode.java         |   67 --
 .../entity/zookeeper/ZooKeeperNodeImpl.java     |   33 -
 .../entity/zookeeper/ZooKeeperSshDriver.java    |  163 ---
 .../entity/messaging/MessageBroker.java         |   34 +
 .../apache/brooklyn/entity/messaging/Queue.java |   51 +
 .../apache/brooklyn/entity/messaging/Topic.java |   46 +
 .../messaging/activemq/ActiveMQBroker.java      |   81 ++
 .../messaging/activemq/ActiveMQBrokerImpl.java  |  124 ++
 .../messaging/activemq/ActiveMQDestination.java |   24 +
 .../activemq/ActiveMQDestinationImpl.java       |   66 ++
 .../messaging/activemq/ActiveMQDriver.java      |   28 +
 .../messaging/activemq/ActiveMQQueue.java       |   27 +
 .../messaging/activemq/ActiveMQQueueImpl.java   |   69 ++
 .../messaging/activemq/ActiveMQSpecs.java       |   33 +
 .../messaging/activemq/ActiveMQSshDriver.java   |  145 +++
 .../messaging/activemq/ActiveMQTopic.java       |   27 +
 .../messaging/activemq/ActiveMQTopicImpl.java   |   50 +
 .../entity/messaging/amqp/AmqpExchange.java     |   45 +
 .../entity/messaging/amqp/AmqpServer.java       |   53 +
 .../entity/messaging/jms/JMSBroker.java         |   58 +
 .../entity/messaging/jms/JMSBrokerImpl.java     |  168 +++
 .../entity/messaging/jms/JMSDestination.java    |   29 +
 .../messaging/jms/JMSDestinationImpl.java       |   51 +
 .../kafka/AbstractfKafkaSshDriver.java          |  133 +++
 .../brooklyn/entity/messaging/kafka/Kafka.java  |   45 +
 .../entity/messaging/kafka/KafkaBroker.java     |   85 ++
 .../messaging/kafka/KafkaBrokerDriver.java      |   27 +
 .../entity/messaging/kafka/KafkaBrokerImpl.java |  170 +++
 .../messaging/kafka/KafkaBrokerSshDriver.java   |   97 ++
 .../entity/messaging/kafka/KafkaCluster.java    |   92 ++
 .../messaging/kafka/KafkaClusterImpl.java       |  206 ++++
 .../entity/messaging/kafka/KafkaZooKeeper.java  |   58 +
 .../messaging/kafka/KafkaZooKeeperDriver.java   |   28 +
 .../messaging/kafka/KafkaZooKeeperImpl.java     |   47 +
 .../kafka/KafkaZooKeeperSshDriver.java          |   82 ++
 .../entity/messaging/qpid/QpidBroker.java       |   79 ++
 .../entity/messaging/qpid/QpidBrokerImpl.java   |  147 +++
 .../entity/messaging/qpid/QpidDestination.java  |   32 +
 .../messaging/qpid/QpidDestinationImpl.java     |  101 ++
 .../entity/messaging/qpid/QpidDriver.java       |   28 +
 .../entity/messaging/qpid/QpidQueue.java        |   29 +
 .../entity/messaging/qpid/QpidQueueImpl.java    |   66 ++
 .../entity/messaging/qpid/QpidSshDriver.java    |  137 +++
 .../entity/messaging/qpid/QpidTopic.java        |   27 +
 .../entity/messaging/qpid/QpidTopicImpl.java    |   56 +
 .../entity/messaging/rabbit/RabbitBroker.java   |   91 ++
 .../messaging/rabbit/RabbitBrokerImpl.java      |  121 ++
 .../messaging/rabbit/RabbitDestination.java     |   92 ++
 .../entity/messaging/rabbit/RabbitDriver.java   |   32 +
 .../entity/messaging/rabbit/RabbitQueue.java    |   85 ++
 .../messaging/rabbit/RabbitSshDriver.java       |  208 ++++
 .../brooklyn/entity/messaging/storm/Storm.java  |  105 ++
 .../entity/messaging/storm/StormDeployment.java |   42 +
 .../messaging/storm/StormDeploymentImpl.java    |   77 ++
 .../entity/messaging/storm/StormDriver.java     |   27 +
 .../entity/messaging/storm/StormImpl.java       |  118 ++
 .../entity/messaging/storm/StormSshDriver.java  |  272 +++++
 .../entity/zookeeper/AbstractZooKeeperImpl.java |  109 ++
 .../entity/zookeeper/ZooKeeperDriver.java       |   27 +
 .../entity/zookeeper/ZooKeeperEnsemble.java     |   53 +
 .../entity/zookeeper/ZooKeeperEnsembleImpl.java |  105 ++
 .../entity/zookeeper/ZooKeeperNode.java         |   67 ++
 .../entity/zookeeper/ZooKeeperNodeImpl.java     |   33 +
 .../entity/zookeeper/ZooKeeperSshDriver.java    |  163 +++
 .../entity/messaging/activemq/activemq.xml      |  154 ---
 .../messaging/kafka/kafka-google-doorway.jpg    |  Bin 15692 -> 0 bytes
 .../entity/messaging/kafka/server.properties    |  112 --
 .../entity/messaging/kafka/zookeeper.properties |   13 -
 .../entity/messaging/rabbit/rabbitmq.config     |    5 -
 .../brooklyn/entity/messaging/storm/storm.yaml  |   39 -
 .../brooklyn/entity/messaging/zookeeper/zoo.cfg |   42 -
 .../entity/messaging/activemq/activemq.xml      |  154 +++
 .../messaging/kafka/kafka-google-doorway.jpg    |  Bin 0 -> 15692 bytes
 .../entity/messaging/kafka/server.properties    |  112 ++
 .../entity/messaging/kafka/zookeeper.properties |   13 +
 .../entity/messaging/rabbit/rabbitmq.config     |    5 +
 .../brooklyn/entity/messaging/storm/storm.yaml  |   39 +
 .../brooklyn/entity/messaging/zookeeper/zoo.cfg |   42 +
 .../messaging/activemq/ActiveMQEc2LiveTest.java |  117 --
 .../activemq/ActiveMQGoogleComputeLiveTest.java |  117 --
 .../activemq/ActiveMQIntegrationTest.java       |  258 -----
 .../messaging/kafka/KafkaIntegrationTest.java   |  142 ---
 .../entity/messaging/kafka/KafkaLiveTest.java   |   68 --
 .../entity/messaging/kafka/KafkaSupport.java    |  109 --
 .../entity/messaging/qpid/QpidEc2LiveTest.java  |   46 -
 .../messaging/qpid/QpidIntegrationTest.java     |  254 ----
 .../messaging/rabbit/RabbitEc2LiveTest.java     |   98 --
 .../messaging/rabbit/RabbitIntegrationTest.java |  189 ---
 .../messaging/storm/LocalhostLiveTest.java      |   32 -
 .../messaging/storm/SoftLayerLiveTest.java      |   33 -
 .../storm/StormAbstractCloudLiveTest.java       |  200 ----
 .../messaging/storm/StormEc2LiveTest.java       |   58 -
 .../messaging/storm/StormGceLiveTest.java       |   51 -
 .../storm/topologies/ExclamationBolt.java       |   51 -
 .../zookeeper/ZooKeeperEc2LiveTest.java         |   48 -
 .../zookeeper/ZooKeeperEnsembleLiveTest.java    |  127 --
 .../messaging/activemq/ActiveMQEc2LiveTest.java |  117 ++
 .../activemq/ActiveMQGoogleComputeLiveTest.java |  117 ++
 .../activemq/ActiveMQIntegrationTest.java       |  258 +++++
 .../messaging/kafka/KafkaIntegrationTest.java   |  142 +++
 .../entity/messaging/kafka/KafkaLiveTest.java   |   68 ++
 .../entity/messaging/kafka/KafkaSupport.java    |  109 ++
 .../entity/messaging/qpid/QpidEc2LiveTest.java  |   46 +
 .../messaging/qpid/QpidIntegrationTest.java     |  254 ++++
 .../messaging/rabbit/RabbitEc2LiveTest.java     |   98 ++
 .../messaging/rabbit/RabbitIntegrationTest.java |  189 +++
 .../messaging/storm/LocalhostLiveTest.java      |   32 +
 .../messaging/storm/SoftLayerLiveTest.java      |   33 +
 .../storm/StormAbstractCloudLiveTest.java       |  200 ++++
 .../messaging/storm/StormEc2LiveTest.java       |   58 +
 .../messaging/storm/StormGceLiveTest.java       |   51 +
 .../storm/topologies/ExclamationBolt.java       |   51 +
 .../zookeeper/ZooKeeperEc2LiveTest.java         |   48 +
 .../zookeeper/ZooKeeperEnsembleLiveTest.java    |  127 ++
 .../entity/monitoring/monit/MonitNode.java      |    2 +-
 .../entity/network/bind/BindDnsServer.java      |    4 +-
 .../nosql/cassandra/CassandraDatacenter.java    |    2 +-
 .../cassandra/CassandraDatacenterImpl.java      |    4 +-
 .../entity/nosql/cassandra/CassandraNode.java   |    4 +-
 .../nosql/cassandra/CassandraNodeDriver.java    |    3 +-
 .../nosql/cassandra/CassandraNodeImpl.java      |    4 +-
 .../nosql/cassandra/CassandraNodeSshDriver.java |    8 +-
 .../nosql/couchbase/CouchbaseCluster.java       |    2 +-
 .../nosql/couchbase/CouchbaseClusterImpl.java   |   10 +-
 .../entity/nosql/couchbase/CouchbaseNode.java   |    2 +-
 .../nosql/couchbase/CouchbaseNodeImpl.java      |    8 +-
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |   12 +-
 .../nosql/couchbase/CouchbaseSyncGateway.java   |    2 +-
 .../entity/nosql/couchdb/CouchDBCluster.java    |    2 +-
 .../entity/nosql/couchdb/CouchDBNode.java       |    2 +-
 .../entity/nosql/couchdb/CouchDBNodeImpl.java   |    2 +-
 .../elasticsearch/ElasticSearchCluster.java     |    2 +-
 .../nosql/elasticsearch/ElasticSearchNode.java  |    3 +-
 .../elasticsearch/ElasticSearchNodeImpl.java    |    4 +-
 .../nosql/mongodb/AbstractMongoDBServer.java    |    2 +-
 .../entity/nosql/mongodb/MongoDBClient.java     |    3 +-
 .../entity/nosql/mongodb/MongoDBReplicaSet.java |    2 +-
 .../entity/nosql/mongodb/MongoDBServer.java     |    2 +-
 .../sharding/CoLocatedMongoDBRouter.java        |    2 +-
 .../sharding/MongoDBShardedDeployment.java      |    2 +-
 .../brooklyn/entity/nosql/redis/RedisSlave.java |    2 +-
 .../brooklyn/entity/nosql/redis/RedisStore.java |    2 +-
 .../brooklyn/entity/nosql/riak/RiakCluster.java |    2 +-
 .../entity/nosql/riak/RiakClusterImpl.java      |    2 +-
 .../brooklyn/entity/nosql/riak/RiakNode.java    |    2 +-
 .../entity/nosql/riak/RiakNodeImpl.java         |    2 +-
 .../entity/nosql/riak/RiakNodeSshDriver.java    |    4 +-
 .../brooklyn/entity/nosql/solr/SolrServer.java  |    4 +-
 .../entity/nosql/solr/SolrServerSshDriver.java  |    2 +-
 .../cassandra/CassandraDatacenterTest.java      |    4 +-
 .../ElasticSearchClusterIntegrationTest.java    |    4 +-
 .../ElasticSearchNodeIntegrationTest.java       |    5 +-
 .../entity/osgi/karaf/KarafContainer.java       |    2 +-
 .../entity/dns/AbstractGeoDnsServiceImpl.java   |    2 +-
 .../dns/geoscaling/GeoscalingDnsService.java    |    2 +-
 .../geoscaling/GeoscalingDnsServiceImpl.java    |    4 +-
 .../geoscaling/GeoscalingScriptGenerator.java   |    3 +-
 .../dns/geoscaling/GeoscalingWebClient.java     |    2 +-
 .../entity/proxy/AbstractController.java        |    2 +-
 .../entity/proxy/AbstractControllerImpl.java    |    2 +-
 .../brooklyn/entity/proxy/LoadBalancer.java     |    2 +-
 .../brooklyn/entity/proxy/ProxySslConfig.java   |    5 +-
 .../entity/proxy/nginx/NginxController.java     |    2 +-
 .../entity/proxy/nginx/NginxControllerImpl.java |    8 +-
 .../entity/proxy/nginx/NginxSshDriver.java      |    8 +-
 .../nginx/NginxTemplateConfigGenerator.java     |    4 +-
 .../brooklyn/entity/proxy/nginx/UrlMapping.java |    2 +-
 .../webapp/ControlledDynamicWebAppCluster.java  |    2 +-
 .../entity/webapp/DynamicWebAppClusterImpl.java |    8 +-
 .../entity/webapp/JavaWebAppService.java        |    2 +-
 .../entity/webapp/JavaWebAppSshDriver.java      |    8 +-
 .../entity/webapp/WebAppServiceConstants.java   |    2 +-
 .../entity/webapp/jboss/JBoss6Server.java       |    2 +-
 .../entity/webapp/jboss/JBoss7Server.java       |    2 +-
 .../entity/webapp/jetty/Jetty6Server.java       |    2 +-
 .../webapp/nodejs/NodeJsWebAppService.java      |    3 +-
 .../webapp/nodejs/NodeJsWebAppSshDriver.java    |    4 +-
 .../entity/webapp/tomcat/Tomcat8Server.java     |    2 +-
 .../entity/webapp/tomcat/TomcatServer.java      |    4 +-
 .../GeoscalingScriptGeneratorTest.java          |    3 +-
 .../dns/geoscaling/GeoscalingWebClientTest.java |    2 +-
 .../entity/proxy/AbstractControllerTest.java    |    2 +-
 .../entity/proxy/ProxySslConfigTest.java        |    2 +-
 .../nginx/NginxRebindWithHaIntegrationTest.java |    4 +-
 .../AbstractWebAppFixtureIntegrationTest.java   |    4 +-
 .../entity/webapp/HttpsSslConfigTest.java       |    2 +-
 .../webapp/WebAppConcurrentDeployTest.java      |    4 +-
 .../test/entity/TestJavaWebAppEntity.java       |    2 +-
 .../test/entity/TestJavaWebAppEntityImpl.java   |    2 +-
 .../app/SampleLocalhostIntegrationTest.java     |    2 +-
 .../camp/brooklyn/YamlLauncherAbstract.java     |    2 +-
 .../BrooklynAssemblyTemplateInstantiator.java   |    4 +-
 .../BrooklynComponentTemplateResolver.java      |   10 +-
 .../BrooklynEntityDecorationResolver.java       |    2 +-
 .../creation/BrooklynYamlTypeInstantiator.java  |    2 +-
 .../spi/dsl/BrooklynDslDeferredSupplier.java    |    2 +-
 .../camp/brooklyn/spi/dsl/DslUtils.java         |    2 +-
 .../spi/dsl/methods/BrooklynDslCommon.java      |   10 +-
 .../brooklyn/spi/dsl/methods/DslComponent.java  |    4 +-
 .../camp/brooklyn/AbstractYamlRebindTest.java   |    4 +-
 .../camp/brooklyn/AbstractYamlTest.java         |    4 +-
 .../camp/brooklyn/DslAndRebindYamlTest.java     |    2 +-
 .../camp/brooklyn/EntitiesYamlTest.java         |    2 +-
 ...aWebAppWithDslYamlRebindIntegrationTest.java |    2 +-
 .../brooklyn/JavaWebAppsIntegrationTest.java    |    2 +-
 .../camp/brooklyn/JavaWebAppsMatchingTest.java  |    4 +-
 .../camp/brooklyn/MapReferenceYamlTest.java     |    2 +-
 .../brooklyn/camp/brooklyn/ObjectsYamlTest.java |    6 +-
 .../brooklyn/ReloadBrooklynPropertiesTest.java  |    2 +-
 .../camp/brooklyn/TestReferencingPolicy.java    |    2 +-
 .../TestSensorAndEffectorInitializer.java       |    2 +-
 .../catalog/AbstractCatalogXmlTest.java         |    2 +-
 .../CatalogOsgiVersionMoreEntityTest.java       |    4 +-
 .../brooklyn/catalog/CatalogYamlEntityTest.java |    2 +-
 .../org/apache/brooklyn/cli/ItemLister.java     |    4 +-
 .../main/java/org/apache/brooklyn/cli/Main.java |   15 +-
 .../apache/brooklyn/cli/lister/ClassFinder.java |    6 +-
 .../brooklyn/cli/lister/ItemDescriptors.java    |    4 +-
 .../java/org/apache/brooklyn/cli/CliTest.java   |    2 +-
 .../brooklyn/launcher/BrooklynWebServer.java    |   14 +-
 .../launcher/config/CustomResourceLocator.java  |    2 +-
 .../entity/basic/VanillaSoftwareYamlTest.java   |    2 +-
 .../brooklynnode/BrooklynNodeRestTest.java      |    6 +-
 .../database/mssql/MssqlBlueprintLiveTest.java  |    5 +-
 .../BrooklynLauncherRebindCatalogTest.java      |    2 +-
 .../launcher/BrooklynWebServerTest.java         |    4 +-
 .../blueprints/AbstractBlueprintTest.java       |    2 +-
 .../src/test/resources/opengamma-cluster.yaml   |    2 +-
 .../src/test/resources/storm-blueprint.yaml     |    2 +-
 .../qa/load/SimulatedMySqlNodeImpl.java         |    6 +-
 .../brooklyn/qa/longevity/MonitorUtils.java     |    4 +-
 .../SoftlayerObtainPrivateLiveTest.java         |    4 +-
 .../resources/AbstractBrooklynRestResource.java |    2 +-
 .../rest/resources/ApplicationResource.java     |    2 +-
 .../rest/resources/CatalogResource.java         |    2 +-
 .../rest/resources/EntityConfigResource.java    |    4 +-
 .../brooklyn/rest/resources/EntityResource.java |    2 +-
 .../rest/resources/PolicyConfigResource.java    |    5 +-
 .../brooklyn/rest/resources/PolicyResource.java |    4 +-
 .../brooklyn/rest/resources/SensorResource.java |    2 +-
 .../brooklyn/rest/resources/ServerResource.java |    6 +-
 .../rest/transform/CatalogTransformer.java      |    2 +-
 .../rest/transform/EffectorTransformer.java     |    4 +-
 .../rest/transform/LocationTransformer.java     |    2 +-
 .../rest/transform/PolicyTransformer.java       |    2 +-
 .../rest/transform/TaskTransformer.java         |    2 +-
 .../rest/util/BrooklynRestResourceUtils.java    |    6 +-
 .../rest/util/DefaultExceptionMapper.java       |    2 +-
 .../BrooklynPropertiesSecurityFilterTest.java   |    6 +-
 .../brooklyn/rest/HaMasterCheckFilterTest.java  |    4 +-
 .../rest/resources/CatalogResetTest.java        |    2 +-
 .../SensorResourceIntegrationTest.java          |    4 +-
 .../ServerResourceIntegrationTest.java          |    7 +-
 .../rest/testing/mocks/CapitalizePolicy.java    |    3 +-
 .../testing/mocks/RestMockSimpleEntity.java     |    3 +-
 .../testing/mocks/RestMockSimplePolicy.java     |    4 +-
 .../util/BrooklynRestResourceUtilsTest.java     |    2 +-
 .../json/BrooklynJacksonSerializerTest.java     |    2 +-
 .../util/jmx/jmxmp/JmxmpAgentSslTest.java       |    5 +-
 .../brooklyn/util/jmx/jmxmp/JmxmpClient.java    |    3 +-
 .../brooklyn/osgi/tests/SimpleLocation.java     |    3 +-
 .../java/brooklyn/osgi/tests/SimplePolicy.java  |    5 +-
 .../osgi/tests/more/MoreEntityImpl.java         |    3 +-
 .../brooklyn/osgi/tests/more/MorePolicy.java    |    3 +-
 .../osgi/tests/more/MoreEntityImpl.java         |    2 +-
 .../osgi/tests/more/MoreEntityImpl.java         |    2 +-
 .../brooklyn/osgi/tests/more/MorePolicy.java    |    2 +-
 1049 files changed, 38102 insertions(+), 37931 deletions(-)
----------------------------------------------------------------------



[26/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/config/ConfigBag.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/config/ConfigBag.java b/core/src/main/java/org/apache/brooklyn/core/util/config/ConfigBag.java
new file mode 100644
index 0000000..0152bb9
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/config/ConfigBag.java
@@ -0,0 +1,589 @@
+/*
+ * 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.util.config;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.ConcurrentModificationException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.config.ConfigKey.HasConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.javalang.JavaClassNames;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import com.google.common.collect.Sets;
+
+/**
+ * Stores config in such a way that usage can be tracked.
+ * Either {@link ConfigKey} or {@link String} keys can be inserted;
+ * they will be stored internally as strings.
+ * It is recommended to use {@link ConfigKey} instances to access,
+ * although in some cases (such as setting fields from flags, or copying a map)
+ * it may be necessary to mark things as used, or put, when only a string key is available.
+ * <p>
+ * This bag is order-preserving and thread-safe except where otherwise indicated,
+ * currently by synching on this instance (but that behaviour may change).
+ * <p>
+ * @author alex
+ */
+public class ConfigBag {
+
+    private static final Logger log = LoggerFactory.getLogger(ConfigBag.class);
+
+    /** an immutable, empty ConfigBag */
+    public static final ConfigBag EMPTY = new ConfigBag().setDescription("immutable empty config bag").seal();
+    
+    protected String description;
+    
+    private Map<String,Object> config;
+    private final Map<String,Object> unusedConfig;
+    private final boolean live;
+    private boolean sealed = false;
+
+    /** creates a new ConfigBag instance, empty and ready for population */
+    public static ConfigBag newInstance() {
+        return new ConfigBag();
+    }
+
+    /**
+     * Creates an instance that is backed by a "live map" (e.g. storage in a datagrid).
+     * The order-preserving nature of this class is only guaranteed if the
+     * provided storage has those properties. External modifications to the store can cause
+     * {@link ConcurrentModificationException} to be thrown, here or elsewhere. 
+     */
+    public static ConfigBag newLiveInstance(Map<String,Object> storage) {
+        return new ConfigBag(checkNotNull(storage, "storage map must be specified"));
+    }
+
+    public static ConfigBag newInstance(Map<?, ?> config) {
+        ConfigBag result = new ConfigBag();
+        result.putAll(config);
+        return result;
+    }
+
+    /** creates a new ConfigBag instance which includes all of the supplied ConfigBag's values,
+     * but which tracks usage separately (already used values are marked as such,
+     * but uses in the original set will not be marked here, and vice versa) */
+    public static ConfigBag newInstanceCopying(final ConfigBag configBag) {
+        return new ConfigBag().copy(configBag).setDescription(configBag.getDescription());
+    }
+    
+    /** creates a new ConfigBag instance which includes all of the supplied ConfigBag's values,
+     * plus an additional set of &lt;ConfigKey,Object&gt; or &lt;String,Object&gt; pairs
+     * <p>
+     * values from the original set which are used here will be marked as used in the original set
+     * (note: this applies even for values which are overridden and the overridden value is used);
+     * however subsequent uses in the original set will not be marked here
+     */
+    @Beta
+    public static ConfigBag newInstanceExtending(final ConfigBag parentBag) {
+        return new ConfigBagExtendingParent(parentBag);
+    }
+
+    /** @see #newInstanceExtending(ConfigBag) */
+    private static class ConfigBagExtendingParent extends ConfigBag {
+        ConfigBag parentBag;
+        private ConfigBagExtendingParent(ConfigBag parentBag) {
+            this.parentBag = parentBag;
+            copy(parentBag);
+        }
+        @Override
+        public void markUsed(String key) {
+            super.markUsed(key);
+            if (parentBag!=null)
+                parentBag.markUsed(key);
+        }
+    }
+    
+    /** As {@link #newInstanceExtending(ConfigBag)} but also putting the supplied values. */
+    @Beta
+    public static ConfigBag newInstanceExtending(final ConfigBag configBag, Map<?,?> optionalAdditionalValues) {
+        return newInstanceExtending(configBag).putAll(optionalAdditionalValues);
+    }
+
+    /** @deprecated since 0.7.0, not used; kept only for rebind compatibility where the inner class is used 
+     * (now replaced by a static class above) */
+    @Beta @Deprecated
+    public static ConfigBag newInstanceWithInnerClass(final ConfigBag configBag, Map<?,?> optionalAdditionalValues) {
+        return new ConfigBag() {
+            @Override
+            public void markUsed(String key) {
+                super.markUsed(key);
+                configBag.markUsed(key);
+            }
+        }.copy(configBag).putAll(optionalAdditionalValues);
+    }
+
+    public ConfigBag() {
+        config = new LinkedHashMap<String,Object>();
+        unusedConfig = new LinkedHashMap<String,Object>();
+        live = false;
+    }
+    
+    private ConfigBag(Map<String,Object> storage) {
+        this.config = storage;
+        unusedConfig = new LinkedHashMap<String,Object>();
+        live = true;
+    }
+    
+    public ConfigBag setDescription(String description) {
+        if (sealed) 
+            throw new IllegalStateException("Cannot set description to '"+description+"': this config bag has been sealed and is now immutable.");
+        this.description = description;
+        return this;
+    }
+    
+    /** optional description used to provide context for operations */
+    public String getDescription() {
+        return description;
+    }
+    
+    /** current values for all entries 
+     * @return non-modifiable map of strings to object */
+    public synchronized Map<String,Object> getAllConfig() {
+        return MutableMap.copyOf(config).asUnmodifiable();
+    }
+
+    /** current values for all entries in a map where the keys are converted to {@link ConfigKey} instances */
+    public synchronized Map<ConfigKey<?>, ?> getAllConfigAsConfigKeyMap() {
+        Map<ConfigKey<?>,Object> result = MutableMap.of();
+        for (Map.Entry<String,Object> entry: config.entrySet()) {
+            result.put(ConfigKeys.newConfigKey(Object.class, entry.getKey()), entry.getValue());
+        }
+        return result;
+    }
+
+    /** Returns the internal map containing the current values for all entries;
+     * for use where the caller wants to modify this directly and knows it is safe to do so 
+     * <p>
+     * Accesses to the returned map must be synchronized on this bag if the 
+     * thread-safe behaviour is required. */ 
+    public Map<String,Object> getAllConfigMutable() {
+        if (live) {
+            // TODO sealed no longer works as before, because `config` is the backing storage map.
+            // Therefore returning it is dangerous! Even if we were to replace our field with an immutable copy,
+            // the underlying datagrid's map would still be modifiable. We need a way to switch the returned
+            // value's behaviour to sealable (i.e. wrapping the returned map).
+            return (sealed) ? MutableMap.copyOf(config).asUnmodifiable() : config;
+        } else {
+            return config;
+        }
+    }
+
+    /** current values for all entries which have not yet been used 
+     * @return non-modifiable map of strings to object */
+    public synchronized Map<String,Object> getUnusedConfig() {
+        return MutableMap.copyOf(unusedConfig).asUnmodifiable();
+    }
+
+    /** Returns the internal map containing the current values for all entries which have not yet been used;
+     * for use where the caller wants to modify this directly and knows it is safe to do so 
+     * <p>
+     * Accesses to the returned map must be synchronized on this bag if the 
+     * thread-safe behaviour is required. */ 
+    public Map<String,Object> getUnusedConfigMutable() {
+        return unusedConfig;
+    }
+
+    public ConfigBag putAll(Map<?,?> addlConfig) {
+        if (addlConfig==null) return this;
+        for (Map.Entry<?,?> e: addlConfig.entrySet()) {
+            putAsStringKey(e.getKey(), e.getValue());
+        }
+        return this;
+    }
+    
+    public ConfigBag putAll(ConfigBag addlConfig) {
+        return putAll(addlConfig.getAllConfig());
+    }
+    
+    public <T> ConfigBag putIfAbsent(ConfigKey<T> key, T value) {
+        return putIfAbsent(MutableMap.of(key, value));
+    }
+
+    public ConfigBag putAsStringKeyIfAbsent(Object key, Object value) {
+        return putIfAbsent(MutableMap.of(key, value));
+    }
+
+    public synchronized ConfigBag putIfAbsent(Map<?, ?> propertiesToSet) {
+        if (propertiesToSet==null)
+            return this;
+        for (Map.Entry<?, ?> entry: propertiesToSet.entrySet()) {
+            Object key = entry.getKey();
+            if (key instanceof HasConfigKey<?>)
+                key = ((HasConfigKey<?>)key).getConfigKey();
+            if (key instanceof ConfigKey<?>) {
+                if (!containsKey((ConfigKey<?>)key))
+                    putAsStringKey(key, entry.getValue());
+            } else if (key instanceof String) {
+                if (!containsKey((String)key))
+                    putAsStringKey(key, entry.getValue());
+            } else {
+                logInvalidKey(key);
+            }
+        }
+        return this;
+    }
+
+    public ConfigBag putIfAbsent(ConfigBag addlConfig) {
+        return putIfAbsent(addlConfig.getAllConfig());
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public <T> T put(ConfigKey<T> key, T value) {
+        return (T) putStringKey(key.getName(), value);
+    }
+    
+    public <T> ConfigBag putIfNotNull(ConfigKey<T> key, T value) {
+        if (value!=null) put(key, value);
+        return this;
+    }
+
+    public <T> ConfigBag putIfAbsentAndNotNull(ConfigKey<T> key, T value) {
+        if (value!=null) putIfAbsent(key, value);
+        return this;
+    }
+
+    /** as {@link #put(ConfigKey, Object)} but returning this ConfigBag for fluent-style coding */
+    public <T> ConfigBag configure(ConfigKey<T> key, T value) {
+        putStringKey(key.getName(), value);
+        return this;
+    }
+    
+    public <T> ConfigBag configureStringKey(String key, T value) {
+        putStringKey(key, value);
+        return this;
+    }
+    
+    protected synchronized void putAsStringKey(Object key, Object value) {
+        if (key instanceof HasConfigKey<?>) key = ((HasConfigKey<?>)key).getConfigKey();
+        if (key instanceof ConfigKey<?>) key = ((ConfigKey<?>)key).getName();
+        if (key instanceof String) {
+            putStringKey((String)key, value);
+        } else {
+            logInvalidKey(key);
+        }
+    }
+
+    protected void logInvalidKey(Object key) {
+        String message = (key == null ? "Invalid key 'null'" : "Invalid key type "+key.getClass().getCanonicalName()+" ("+key+")") +
+                " being used for configuration, ignoring";
+        log.debug(message, new Throwable("Source of "+message));
+        log.warn(message);
+    }
+    
+    /** recommended to use {@link #put(ConfigKey, Object)} but there are times
+     * (e.g. when copying a map) where we want to put a string key directly 
+     */
+    public synchronized Object putStringKey(String key, Object value) {
+        if (sealed) 
+            throw new IllegalStateException("Cannot insert "+key+"="+value+": this config bag has been sealed and is now immutable.");
+        boolean isNew = !config.containsKey(key);
+        boolean isUsed = !isNew && !unusedConfig.containsKey(key);
+        Object old = config.put(key, value);
+        if (!isUsed) 
+            unusedConfig.put(key, value);
+        //if (!isNew && !isUsed) log.debug("updating config value which has already been used");
+        return old;
+    }
+    public Object putStringKeyIfHasValue(String key, Maybe<?> value) {
+        if (value.isPresent())
+            return putStringKey(key, value.get());
+        return null;
+    }
+    public Object putStringKeyIfNotNull(String key, Object value) {
+        if (value!=null)
+            return putStringKey(key, value);
+        return null;
+    }
+
+    public boolean containsKey(HasConfigKey<?> key) {
+        return containsKey(key.getConfigKey());
+    }
+
+    public boolean containsKey(ConfigKey<?> key) {
+        return containsKey(key.getName());
+    }
+
+    public synchronized boolean containsKey(String key) {
+        return config.containsKey(key);
+    }
+
+    /** returns the value of this config key, falling back to its default (use containsKey to see whether it was contained);
+     * also marks it as having been used (use peek to prevent marking as used)
+     */
+    public <T> T get(ConfigKey<T> key) {
+        return get(key, true);
+    }
+
+    /** gets a value from a string-valued key or null; ConfigKey is preferred, but this is useful in some contexts (e.g. setting from flags) */
+    public Object getStringKey(String key) {
+        return getStringKeyMaybe(key).orNull();
+    }
+    /** gets a {@link Maybe}-wrapped value from a string-valued key; ConfigKey is preferred, but this is useful in some contexts (e.g. setting from flags) */
+    public @Nonnull Maybe<Object> getStringKeyMaybe(String key) {
+        return getStringKeyMaybe(key, true);
+    }
+
+    /** gets a {@link Maybe}-wrapped value from a key, inferring the type of that key (e.g. {@link ConfigKey} or {@link String}) */
+    @Beta
+    public Maybe<Object> getObjKeyMaybe(Object key) {
+        if (key instanceof HasConfigKey<?>) key = ((HasConfigKey<?>)key).getConfigKey();
+        if (key instanceof ConfigKey<?>) key = ((ConfigKey<?>)key).getName();
+        if (key instanceof String) {
+            return getStringKeyMaybe((String)key, true);
+        } else {
+            logInvalidKey(key);
+            return Maybe.absent();
+        }
+    }
+
+    /** like get, but without marking it as used */
+    public <T> T peek(ConfigKey<T> key) {
+        return get(key, false);
+    }
+
+    /** returns the first key in the list for which a value is explicitly set, then defaulting to defaulting value of preferred key */
+    public synchronized <T> T getFirst(ConfigKey<T> preferredKey, ConfigKey<T> ...otherCurrentKeysInOrderOfPreference) {
+        if (containsKey(preferredKey)) 
+            return get(preferredKey);
+        for (ConfigKey<T> key: otherCurrentKeysInOrderOfPreference) {
+            if (containsKey(key)) 
+                return get(key);
+        }
+        return get(preferredKey);
+    }
+
+    /** convenience for @see #getWithDeprecation(ConfigKey[], ConfigKey...) */
+    public Object getWithDeprecation(ConfigKey<?> key, ConfigKey<?> ...deprecatedKeys) {
+        return getWithDeprecation(new ConfigKey[] { key }, deprecatedKeys);
+    }
+
+    /** returns the value for the first key in the list for which a value is set,
+     * warning if any of the deprecated keys have a value which is different to that set on the first set current key
+     * (including warning if a deprecated key has a value but no current key does) */
+    public synchronized Object getWithDeprecation(ConfigKey<?>[] currentKeysInOrderOfPreference, ConfigKey<?> ...deprecatedKeys) {
+        // Get preferred key (or null)
+        ConfigKey<?> preferredKeyProvidingValue = null;
+        Object result = null;
+        boolean found = false;
+        for (ConfigKey<?> key: currentKeysInOrderOfPreference) {
+            if (containsKey(key)) {
+                preferredKeyProvidingValue = key;
+                result = get(preferredKeyProvidingValue);
+                found = true;
+                break;
+            }
+        }
+        
+        // Check if any deprecated keys are set
+        ConfigKey<?> deprecatedKeyProvidingValue = null;
+        Object deprecatedResult = null;
+        boolean foundDeprecated = false;
+        for (ConfigKey<?> deprecatedKey: deprecatedKeys) {
+            Object x = null;
+            boolean foundX = false;
+            if (containsKey(deprecatedKey)) {
+                x = get(deprecatedKey);
+                foundX = true;
+            }
+            if (foundX) {
+                if (found) {
+                    if (!Objects.equal(result, x)) {
+                        log.warn("Conflicting value from deprecated key " +deprecatedKey+", value "+x+
+                                "; using preferred key "+preferredKeyProvidingValue+" value "+result);
+                    } else {
+                        log.info("Deprecated key " +deprecatedKey+" ignored; has same value as preferred key "+preferredKeyProvidingValue+" ("+result+")");
+                    }
+                } else if (foundDeprecated) {
+                    if (!Objects.equal(result, x)) {
+                        log.warn("Conflicting values from deprecated keys: using " +deprecatedKeyProvidingValue+" instead of "+deprecatedKey+
+                                " (value "+deprecatedResult+" instead of "+x+")");
+                    } else {
+                        log.info("Deprecated key " +deprecatedKey+" ignored; has same value as other deprecated key "+preferredKeyProvidingValue+" ("+deprecatedResult+")");
+                    }
+                } else {
+                    // new value, from deprecated key
+                    log.warn("Deprecated key " +deprecatedKey+" detected (supplying value "+x+"), "+
+                            "; recommend changing to preferred key '"+currentKeysInOrderOfPreference[0]+"'; this will not be supported in future versions");
+                    deprecatedResult = x;
+                    deprecatedKeyProvidingValue = deprecatedKey;
+                    foundDeprecated = true;
+                }
+            }
+        }
+        
+        if (found) {
+            return result;
+        } else if (foundDeprecated) {
+            return deprecatedResult;
+        } else {
+            return currentKeysInOrderOfPreference[0].getDefaultValue();
+        }
+    }
+
+    protected <T> T get(ConfigKey<T> key, boolean markUsed) {
+        // TODO for now, no evaluation -- maps / closure content / other smart (self-extracting) keys are NOT supported
+        // (need a clean way to inject that behaviour, as well as desired TypeCoercions)
+        // this method, and the coercion, is not synchronized, nor does it need to be, because the "get" is synchronized. 
+        return coerceFirstNonNullKeyValue(key, getStringKey(key.getName(), markUsed));
+    }
+
+    /** returns the first non-null value to be the type indicated by the key, or the keys default value if no non-null values are supplied */
+    public static <T> T coerceFirstNonNullKeyValue(ConfigKey<T> key, Object ...values) {
+        for (Object o: values)
+            if (o!=null) return TypeCoercions.coerce(o, key.getTypeToken());
+        return TypeCoercions.coerce(key.getDefaultValue(), key.getTypeToken());
+    }
+
+    protected Object getStringKey(String key, boolean markUsed) {
+        return getStringKeyMaybe(key, markUsed).orNull();
+    }
+    protected synchronized Maybe<Object> getStringKeyMaybe(String key, boolean markUsed) {
+        if (config.containsKey(key)) {
+            if (markUsed) markUsed(key);
+            return Maybe.of(config.get(key));
+        }
+        return Maybe.absent();
+    }
+
+    /** indicates that a string key in the config map has been accessed */
+    public synchronized void markUsed(String key) {
+        unusedConfig.remove(key);
+    }
+
+    public synchronized void clear() {
+        if (sealed) 
+            throw new IllegalStateException("Cannot clear this config bag has been sealed and is now immutable.");
+        config.clear();
+        unusedConfig.clear();
+    }
+    
+    public ConfigBag removeAll(ConfigKey<?> ...keys) {
+        for (ConfigKey<?> key: keys) remove(key);
+        return this;
+    }
+
+    public synchronized void remove(ConfigKey<?> key) {
+        remove(key.getName());
+    }
+
+    public ConfigBag removeAll(Iterable<String> keys) {
+        for (String key: keys) remove(key);
+        return this;
+    }
+
+    public synchronized void remove(String key) {
+        if (sealed) 
+            throw new IllegalStateException("Cannot remove "+key+": this config bag has been sealed and is now immutable.");
+        config.remove(key);
+        unusedConfig.remove(key);
+    }
+
+    public ConfigBag copy(ConfigBag other) {
+        // ensure locks are taken in a canonical order to prevent deadlock
+        if (other==null) {
+            synchronized (this) {
+                return copyWhileSynched(other);
+            }
+        }
+        if (System.identityHashCode(other) < System.identityHashCode(this)) {
+            synchronized (other) {
+                synchronized (this) {
+                    return copyWhileSynched(other);
+                }
+            }
+        } else {
+            synchronized (this) {
+                synchronized (other) {
+                    return copyWhileSynched(other);
+                }
+            }
+        }
+    }
+    
+    protected ConfigBag copyWhileSynched(ConfigBag other) {
+        if (sealed) 
+            throw new IllegalStateException("Cannot copy "+other+" to "+this+": this config bag has been sealed and is now immutable.");
+        putAll(other.getAllConfig());
+        markAll(Sets.difference(other.getAllConfig().keySet(), other.getUnusedConfig().keySet()));
+        setDescription(other.getDescription());
+        return this;
+    }
+
+    public synchronized int size() {
+        return config.size();
+    }
+    
+    public synchronized boolean isEmpty() {
+        return config.isEmpty();
+    }
+    
+    public ConfigBag markAll(Iterable<String> usedFlags) {
+        for (String flag: usedFlags)
+            markUsed(flag);
+        return this;
+    }
+
+    public synchronized boolean isUnused(ConfigKey<?> key) {
+        return unusedConfig.containsKey(key.getName());
+    }
+    
+    /** makes this config bag immutable; any attempts to change subsequently 
+     * (apart from marking fields as used) will throw an exception
+     * <p>
+     * copies will be unsealed however
+     * <p>
+     * returns this for convenience (fluent usage) */
+    public ConfigBag seal() {
+        sealed = true;
+        if (live) {
+            // TODO How to ensure sealed?!
+        } else {
+            config = getAllConfig();
+        }
+        return this;
+    }
+
+    // TODO why have both this and mutable
+    /** @see #getAllConfigMutable() */
+    public Map<String, Object> getAllConfigRaw() {
+        return getAllConfigMutable();
+    }
+    
+    @Override
+    public String toString() {
+        return JavaClassNames.simpleClassName(this)+"["+getAllConfigRaw()+"]";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/crypto/FluentKeySigner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/crypto/FluentKeySigner.java b/core/src/main/java/org/apache/brooklyn/core/util/crypto/FluentKeySigner.java
new file mode 100644
index 0000000..1d0b030
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/crypto/FluentKeySigner.java
@@ -0,0 +1,192 @@
+/*
+ * 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.util.crypto;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.brooklyn.core.internal.BrooklynInitialization;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.jce.X509Principal;
+
+import brooklyn.util.exceptions.Exceptions;
+
+/** A fluent API which simplifies generating certificates (signed keys) */
+/* NB - re deprecation - we use deprecated X509V3CertificateGenerator still
+ * because the official replacement, X509v3CertificateBuilder, 
+ * drags in an add'l dependency (bcmail) and is harder to use. */
+public class FluentKeySigner {
+
+    static { BrooklynInitialization.initSecureKeysBouncyCastleProvider(); }
+
+    protected X500Principal issuerPrincipal;
+    protected KeyPair issuerKey;
+
+    protected SecureRandom srand = new SecureRandom();
+    
+    protected Date validityStartDate, validityEndDate;
+    protected BigInteger serialNumber;
+    
+    protected String signatureAlgorithm = "MD5WithRSAEncryption";
+    protected AuthorityKeyIdentifier authorityKeyIdentifier;
+    protected X509Certificate authorityCertificate;
+
+    public FluentKeySigner(X500Principal issuerPrincipal, KeyPair issuerKey) {
+        this.issuerPrincipal = issuerPrincipal;
+        this.issuerKey = issuerKey;
+        validFromDaysAgo(7);
+        validForYears(10);
+    }
+    public FluentKeySigner(String issuerCommonName, KeyPair issuerKey) {
+        this(SecureKeys.getX500PrincipalWithCommonName(issuerCommonName), issuerKey);
+    }
+    
+    public FluentKeySigner(String issuerCommonName) {
+        this(issuerCommonName, SecureKeys.newKeyPair());
+    }
+
+    public FluentKeySigner(X509Certificate caCert, KeyPair caKey) {
+        this(caCert.getIssuerX500Principal(), caKey);
+        authorityCertificate(caCert);
+    }
+    
+    public KeyPair getKey() {
+        return issuerKey;
+    }
+    
+    public X500Principal getPrincipal() {
+        return issuerPrincipal;
+    }
+    
+    @SuppressWarnings("deprecation")
+    public String getCommonName() {
+//        TODO see deprecation note at top of file
+        // for modernising, would RFC4519Style.cn work ?
+        return (String) new X509Principal(issuerPrincipal.getName()).getValues(org.bouncycastle.asn1.x509.X509Name.CN).elementAt(0);
+    }
+    
+    public X509Certificate getAuthorityCertificate() {
+        return authorityCertificate;
+    }
+    
+    public FluentKeySigner validFromDaysAgo(long days) {
+        return validFrom(new Date( (System.currentTimeMillis() / (1000L*60*60*24) - days) * 1000L*60*60*24));            
+    }
+
+    public FluentKeySigner validFrom(Date d) {
+        validityStartDate = d;
+        return this;
+    }
+
+    public FluentKeySigner validForYears(long years) {
+        return validUntil(new Date( (System.currentTimeMillis() / (1000L*60*60*24) + 365*years) * 1000L*60*60*24));            
+    }
+
+    public FluentKeySigner validUntil(Date d) {
+        validityEndDate = d;
+        return this;
+    }
+
+    /** use a hard-coded serial number; or make one up, if null */
+    public FluentKeySigner serialNumber(BigInteger serialNumber) {
+        this.serialNumber = serialNumber;
+        return this;
+    }
+
+    public FluentKeySigner signatureAlgorithm(String signatureAlgorithm) {
+        this.signatureAlgorithm = signatureAlgorithm;
+        return this;
+    }
+
+    @SuppressWarnings("deprecation")
+    public FluentKeySigner authorityCertificate(X509Certificate certificate) {
+        try {
+            authorityKeyIdentifier(new org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure(certificate));
+            this.authorityCertificate = certificate;
+            return this;
+        } catch (CertificateParsingException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    public FluentKeySigner authorityKeyIdentifier(AuthorityKeyIdentifier authorityKeyIdentifier) {
+        this.authorityKeyIdentifier = authorityKeyIdentifier;
+        return this;
+    }
+    
+    public FluentKeySigner selfsign() {
+        if (authorityCertificate!=null) throw new IllegalStateException("Signer already has certificate");
+        authorityCertificate(newCertificateFor(getCommonName(), getKey()));
+        return this;
+    }
+
+    // TODO see note re deprecation at start of file
+    @SuppressWarnings("deprecation")
+    public X509Certificate newCertificateFor(X500Principal subject, PublicKey keyToCertify) {
+        try {
+            org.bouncycastle.x509.X509V3CertificateGenerator v3CertGen = new org.bouncycastle.x509.X509V3CertificateGenerator();
+
+            v3CertGen.setSerialNumber(
+                    serialNumber != null ? serialNumber :
+                        // must be positive
+                        BigInteger.valueOf(srand.nextLong()).abs().add(BigInteger.ONE));  
+            v3CertGen.setIssuerDN(issuerPrincipal);  
+            v3CertGen.setNotBefore(validityStartDate);  
+            v3CertGen.setNotAfter(validityEndDate);
+            v3CertGen.setSignatureAlgorithm(signatureAlgorithm);   
+
+            v3CertGen.setSubjectDN(subject);  
+            v3CertGen.setPublicKey(keyToCertify);  
+
+            v3CertGen.addExtension(X509Extension.subjectKeyIdentifier, false,
+                    new org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure(keyToCertify));
+
+            if (authorityKeyIdentifier!=null)
+                v3CertGen.addExtension(X509Extension.authorityKeyIdentifier, false,
+                        authorityKeyIdentifier);
+
+            X509Certificate pkCertificate = v3CertGen.generate(issuerKey.getPrivate(), "BC");
+            return pkCertificate;
+            
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    public X509Certificate newCertificateFor(String commonName, PublicKey key) {
+//        SecureKeys.getX509PrincipalWithCommonName(commonName)
+        return newCertificateFor(
+                SecureKeys.getX500PrincipalWithCommonName(commonName)
+//                new X509Principal("CN=" + commonName + ", OU=None, O=None, L=None, C=None")
+                , key);
+    }
+
+    public X509Certificate newCertificateFor(String commonName, KeyPair key) {
+        return newCertificateFor(commonName, key.getPublic());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/crypto/SecureKeys.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/crypto/SecureKeys.java b/core/src/main/java/org/apache/brooklyn/core/util/crypto/SecureKeys.java
new file mode 100644
index 0000000..5e630a8
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/crypto/SecureKeys.java
@@ -0,0 +1,186 @@
+/*
+ * 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.util.crypto;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+
+import org.apache.brooklyn.core.internal.BrooklynInitialization;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMDecryptorProvider;
+import org.bouncycastle.openssl.PEMEncryptedKeyPair;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.PEMWriter;
+import org.bouncycastle.openssl.PasswordFinder;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.crypto.AuthorizedKeysParser;
+import brooklyn.util.crypto.SecureKeysWithoutBouncyCastle;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.stream.Streams;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Throwables;
+
+/**
+ * Utility methods for generating and working with keys,
+ * extending the parent class with useful things provided by BouncyCastle crypto library.
+ * (Parent class is in a different project where BC is not included as a dependency.)
+ */
+public class SecureKeys extends SecureKeysWithoutBouncyCastle {
+
+    private static final Logger log = LoggerFactory.getLogger(SecureKeys.class);
+    
+    static { BrooklynInitialization.initSecureKeysBouncyCastleProvider(); }
+    
+    public static void initBouncyCastleProvider() {
+        Security.addProvider(new BouncyCastleProvider());
+    }
+    
+    public static class PassphraseProblem extends IllegalStateException {
+        private static final long serialVersionUID = -3382824813899223447L;
+        public PassphraseProblem(String message) { super("Passphrase problem with this key: "+message); }
+        public PassphraseProblem(String message, Exception cause) { super("Passphrase problem with this key: "+message, cause); }
+    }
+    
+    private SecureKeys() {}
+    
+    /** RFC1773 order, with None for other values. Normally prefer X500Principal. */
+    public static X509Principal getX509PrincipalWithCommonName(String commonName) {
+        return new X509Principal("" + "C=None," + "L=None," + "O=None," + "OU=None," + "CN=" + commonName);
+    }
+
+    /** reads RSA or DSA / pem style private key files (viz {@link #toPem(KeyPair)}), extracting also the public key if possible
+     * @throws IllegalStateException on errors, in particular {@link PassphraseProblem} if that is the problem */
+    public static KeyPair readPem(InputStream input, final String passphrase) {
+        // TODO cache is only for fallback "reader" strategy (2015-01); delete when Parser confirmed working
+        byte[] cache = Streams.readFully(input);
+        input = new ByteArrayInputStream(cache);
+
+        try {
+            PEMParser pemParser = new PEMParser(new InputStreamReader(input));
+
+            Object object = pemParser.readObject();
+            pemParser.close();
+
+            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
+            KeyPair kp = null;
+            if (object==null) {
+                throw new IllegalStateException("PEM parsing failed: missing or invalid data");
+            } else if (object instanceof PEMEncryptedKeyPair) {
+                if (passphrase==null) throw new PassphraseProblem("passphrase required");
+                try {
+                    PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(passphrase.toCharArray());
+                    kp = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));
+                } catch (Exception e) {
+                    Exceptions.propagateIfFatal(e);
+                    throw new PassphraseProblem("wrong passphrase", e);
+                }
+            } else  if (object instanceof PEMKeyPair) {
+                kp = converter.getKeyPair((PEMKeyPair) object);
+            } else if (object instanceof PrivateKeyInfo) {
+                PrivateKey privKey = converter.getPrivateKey((PrivateKeyInfo) object);
+                kp = new KeyPair(null, privKey);
+            } else {
+                throw new IllegalStateException("PEM parser support missing for: "+object);
+            }
+
+            return kp;
+
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+
+            // older code relied on PEMReader, now deprecated
+            // replaced with above based on http://stackoverflow.com/questions/14919048/bouncy-castle-pemreader-pemparser
+            // passes the same tests (Jan 2015) but leaving the old code as a fallback for the time being 
+
+            input = new ByteArrayInputStream(cache);
+            try {
+                Security.addProvider(new BouncyCastleProvider());
+                @SuppressWarnings("deprecation")
+                org.bouncycastle.openssl.PEMReader pr = new org.bouncycastle.openssl.PEMReader(new InputStreamReader(input), new PasswordFinder() {
+                    public char[] getPassword() {
+                        return passphrase!=null ? passphrase.toCharArray() : new char[0];
+                    }
+                });
+                @SuppressWarnings("deprecation")
+                KeyPair result = (KeyPair) pr.readObject();
+                pr.close();
+                if (result==null)
+                    throw Exceptions.propagate(e);
+                
+                log.warn("PEMParser failed when deprecated PEMReader succeeded, with "+result+"; had: "+e);
+
+                return result;
+
+            } catch (Exception e2) {
+                Exceptions.propagateIfFatal(e2);
+                throw Exceptions.propagate(e);
+            }
+        }
+    }
+
+    /** because KeyPair.equals is not implemented :( */
+    public static boolean equal(KeyPair k1, KeyPair k2) {
+        return Objects.equal(k2.getPrivate(), k1.getPrivate()) && Objects.equal(k2.getPublic(), k1.getPublic());
+    }
+
+    /** returns the PEM (base64, ie for id_rsa) string for the private key / key pair;
+     * this starts -----BEGIN PRIVATE KEY----- and ends similarly, like id_rsa.
+     * also see {@link #readPem(InputStream, String)} */
+    public static String toPem(KeyPair key) {
+        return stringPem(key);
+    }
+
+    /** returns id_rsa.pub style file, of public key */
+    public static String toPub(KeyPair key) {
+        return AuthorizedKeysParser.encodePublicKey(key.getPublic());
+    }
+    
+    /** opposite of {@link #toPub(KeyPair)}, given text */
+    public static PublicKey fromPub(String pubText) {
+        return AuthorizedKeysParser.decodePublicKey(pubText);
+    }
+
+    /** @deprecated since 0.7.0, use {@link #toPem(KeyPair)} */ @Deprecated
+    public static String stringPem(KeyPair key) {
+        try {
+            StringWriter sw = new StringWriter();
+            PEMWriter w = new PEMWriter(sw);
+            w.writeObject(key);
+            w.close();
+            return sw.toString();
+        } catch (IOException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveBuilder.java b/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveBuilder.java
new file mode 100644
index 0000000..069f10b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveBuilder.java
@@ -0,0 +1,424 @@
+/*
+ * 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.util.file;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.Map;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.brooklyn.core.util.file.ArchiveUtils.ArchiveType;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.os.Os;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.common.io.Files;
+
+/**
+ * Build a Zip or Jar archive.
+ * <p>
+ * Supports creating temporary archives that will be deleted on exit, if no name is
+ * specified. The created file must be a Java archive type, with the extension {@code .zip},
+ * {@code .jar}, {@code .war} or {@code .ear}.
+ * <p>
+ * Example:
+ * <pre> File zip = ArchiveBuilder.archive("data/archive.zip")
+ *         .addAt(new File("./pom.xml"), "")
+ *         .addDirContentsAt(new File("./src"), "src/")
+ *         .addAt(new File("/tmp/Extra.java"), "src/main/java/")
+ *         .addDirContentsAt(new File("/tmp/overlay/"), "")
+ *         .create();
+ * </pre>
+ * <p>
+ */
+@Beta
+public class ArchiveBuilder {
+
+    /**
+     * Create an {@link ArchiveBuilder} for an archive with the given name.
+     */
+    public static ArchiveBuilder archive(String archive) {
+        return new ArchiveBuilder(archive);
+    }
+
+    /**
+     * Create an {@link ArchiveBuilder} for a {@link ArchiveType#ZIP Zip} format archive.
+     */
+    public static ArchiveBuilder zip() {
+        return new ArchiveBuilder(ArchiveType.ZIP);
+    }
+
+    /**
+     * Create an {@link ArchiveBuilder} for a {@link ArchiveType#JAR Jar} format archive.
+     */
+    public static ArchiveBuilder jar() {
+        return new ArchiveBuilder(ArchiveType.JAR);
+    }
+
+    // TODO would be nice to support TAR and TGZ
+    // e.g. using commons-compress
+    // TarArchiveOutputStream out = new TarArchiveOutputStream(new GZIPOutputStream(bytes));
+    // but I think the way entries are done is slightly different so we'd need a bit of refactoring
+    
+    private final ArchiveType type;
+    private File archive;
+    private Manifest manifest;
+    private Multimap<String, File> entries = LinkedHashMultimap.create();
+
+    private ArchiveBuilder() {
+        this(ArchiveType.ZIP);
+    }
+
+    private ArchiveBuilder(String filename) {
+        this(ArchiveType.of(filename));
+
+        named(filename);
+    }
+
+    private ArchiveBuilder(ArchiveType type) {
+        checkNotNull(type);
+        checkArgument(ArchiveType.ZIP_ARCHIVES.contains(type));
+
+        this.type = type;
+        this.manifest = new Manifest();
+    }
+
+    /**
+     * Set the location of the generated archive file.
+     */
+    public ArchiveBuilder named(String name) {
+        checkNotNull(name);
+        String ext = Files.getFileExtension(name);
+        if (ext.isEmpty()) {
+            name = name + "." + type.toString();
+        } else if (type != ArchiveType.of(name)) {
+            throw new IllegalArgumentException(String.format("Extension for '%s' did not match archive type of %s", ext, type));
+        }
+        this.archive = new File(Os.tidyPath(name));
+        return this;
+    }
+
+    /**
+     * @see #named(String)
+     */
+    public ArchiveBuilder named(File file) {
+        checkNotNull(file);
+        return named(file.getPath());
+    }
+
+    /**
+     * Add a manifest entry with the given {@code key} and {@code value}.
+     */
+    public ArchiveBuilder manifest(Object key, Object value) {
+        checkNotNull(key, "key");
+        checkNotNull(value, "value");
+        manifest.getMainAttributes().put(key, value);
+        return this;
+    }
+
+    /**
+     * Add the file located at the {@code filePath} to the archive, 
+     * with some complicated base-name strategies.
+     *
+     * @deprecated since 0.7.0 use one of the other add methods which makes the strategy explicit */ @Deprecated
+    public ArchiveBuilder add(String filePath) {
+        checkNotNull(filePath, "filePath");
+        return add(new File(Os.tidyPath(filePath)));
+    }
+
+    /**
+     * Add the {@code file} to the archive.
+     * <p>
+     * If the file path is absolute, or points to a file above the current directory,
+     * the file is added to the archive as a top-level entry, using the file name only.
+     * For relative {@code filePath}s below the current directory, the file is added
+     * using the path given and is assumed to be located relative to the current
+     * working directory.
+     * <p>
+     * No checks for file existence are made at this stage.
+     *
+     * @see #entry(String, File)
+     * @deprecated since 0.7.0 use one of the other add methods which makes the strategy explicit */ @Deprecated
+    public ArchiveBuilder add(File file) {
+        checkNotNull(file, "file");
+        String filePath = Os.tidyPath(file.getPath());
+        if (file.isAbsolute() || filePath.startsWith("../")) {
+            return entry(Os.mergePaths(".", file.getName()), file);
+        } else {
+            return entry(Os.mergePaths(".", filePath), file);
+        }
+    }
+
+    /**
+     * Add the file located at the {@code fileSubPath}, relative to the {@code baseDir} on the local system,
+     * to the archive.
+     * <p>
+     * Uses the {@code fileSubPath} as the name of the file in the archive. Note that the
+     * file is found by concatenating the two path components using {@link Os#mergePaths(String...)},
+     * thus {@code fileSubPath} should not be absolute or point to a location above the current directory.
+     * <p>
+     * Use {@link #entry(String, String)} directly or {@link #entries(Map)} for complete
+     * control over file locations and names in the archive.
+     *
+     * @see #entry(String, String)
+     */
+    public ArchiveBuilder addFromLocalBaseDir(File baseDir, String fileSubPath) {
+        checkNotNull(baseDir, "baseDir");
+        checkNotNull(fileSubPath, "filePath");
+        return entry(Os.mergePaths(".", fileSubPath), Os.mergePaths(baseDir.getPath(), fileSubPath));
+    }
+    /** @deprecated since 0.7.0 use {@link #addFromLocalBaseDir(File, String)}, or
+     * one of the other add methods if adding relative to baseDir was not intended */ @Deprecated
+    public ArchiveBuilder addFromLocalBaseDir(String baseDir, String fileSubPath) {
+        return addFromLocalBaseDir(new File(baseDir), fileSubPath);
+    }
+    /** @deprecated since 0.7.0 use {@link #addFromLocalBaseDir(File, String)}, or
+     * one of the other add methods if adding relative to baseDir was not intended */ @Deprecated
+    public ArchiveBuilder add(String baseDir, String fileSubPath) {
+        return addFromLocalBaseDir(baseDir, fileSubPath);
+    }
+     
+    /** adds the given file to the archive, preserving its name but putting under the given directory in the archive (may be <code>""</code> or <code>"./"</code>) */
+    public ArchiveBuilder addAt(File file, String archiveParentDir) {
+        checkNotNull(archiveParentDir, "archiveParentDir");
+        checkNotNull(file, "file");
+        return entry(Os.mergePaths(archiveParentDir, file.getName()), file);
+    }
+
+    /**
+     * Add the contents of the directory named {@code dirName} to the archive.
+     *
+     * @see #addDir(File)
+     * @deprecated since 0.7.0 use {@link #addDirContentsAt(File, String) */ @Deprecated
+    public ArchiveBuilder addDir(String dirName) {
+        checkNotNull(dirName, "dirName");
+        return addDir(new File(Os.tidyPath(dirName)));
+    }
+
+    /**
+     * Add the contents of the directory {@code dir} to the archive.
+     * The directory's name is not included; use {@link #addAtRoot(File)} if you want that behaviour. 
+     * <p>
+     * Uses {@literal .} as the parent directory name for the contents.
+     *
+     * @see #entry(String, File)
+     */
+    public ArchiveBuilder addDirContentsAt(File dir, String archiveParentDir) {
+        checkNotNull(dir, "dir");
+        if (!dir.isDirectory()) throw new IllegalArgumentException(dir+" is not a directory; cannot add contents to archive");
+        return entry(archiveParentDir, dir);
+    }
+    /**
+     * As {@link #addDirContentsAt(File, String)}, 
+     * using {@literal .} as the parent directory name for the contents.
+     * 
+     * @deprecated since 0.7.0 use {@link #addDirContentsAt(File, String)
+     * to clarify API, argument types, and be explicit about where it should be installed,
+     * because JARs seem to require <code>""<code> whereas ZIPs might want <code>"./"</code>. */ @Deprecated
+    public ArchiveBuilder addDir(File dir) {
+        return addDirContentsAt(dir, ".");
+    }
+
+    /**
+     * Add the collection of {@code files} to the archive.
+     *
+     * @see #add(String)
+     * @deprecated since 0.7.0 use one of the other add methods if keeping this file's path was not intended */ @Deprecated
+    public ArchiveBuilder add(Iterable<String> files) {
+        checkNotNull(files, "files");
+        for (String filePath : files) {
+            add(filePath);
+        }
+        return this;
+    }
+
+    /**
+     * Add the collection of {@code files}, relative to the {@code baseDir}, to
+     * the archive.
+     *
+     * @see #add(String, String)
+     * @deprecated since 0.7.0 use one of the other add methods if keeping this file's path was not intended */ @Deprecated
+    public ArchiveBuilder add(String baseDir, Iterable<String> files) {
+        checkNotNull(baseDir, "baseDir");
+        checkNotNull(files, "files");
+        for (String filePath : files) {
+            add(baseDir, filePath);
+        }
+        return this;
+    }
+
+    /**
+     * Add the {@code file} to the archive with the path {@code entryPath}.
+     *
+     * @see #entry(String, File)
+     */
+    public ArchiveBuilder entry(String entryPath, String filePath) {
+        checkNotNull(entryPath, "entryPath");
+        checkNotNull(filePath, "filePath");
+        return entry(entryPath, new File(filePath));
+    }
+
+    /**
+     * Add the {@code file} to the archive with the path {@code entryPath}.
+     */
+    public ArchiveBuilder entry(String entryPath, File file) {
+        checkNotNull(entryPath, "entryPath");
+        checkNotNull(file, "file");
+        this.entries.put(entryPath, file);
+        return this;
+    }
+
+    /**
+     * Add a {@link Map} of entries to the archive.
+     * <p>
+     * The keys should be the names of the file entries to be added to the archive and
+     * the value should point to the actual {@link File} to be added.
+     * <p>
+     * This allows complete control over the directory structure of the eventual archive,
+     * as the entry names do not need to bear any relationship to the name or location
+     * of the files on the filesystem.
+     */
+    public ArchiveBuilder entries(Map<String, File> entries) {
+        checkNotNull(entries, "entries");
+        for (Map.Entry<String, File> entry: entries.entrySet())
+            this.entries.put(entry.getKey(), entry.getValue());
+        return this;
+    }
+
+    /**
+     * Generates the archive and outputs it to the given stream, ignoring any file name.
+     * <p>
+     * This will add a manifest file if the type is a Jar archive.
+     */
+    public void stream(OutputStream output) {
+        try {
+            ZipOutputStream target;
+            if (type == ArchiveType.ZIP) {
+                target = new ZipOutputStream(output);
+            } else {
+                manifest(Attributes.Name.MANIFEST_VERSION, "1.0");
+                target = new JarOutputStream(output, manifest);
+            }
+            for (String entry : entries.keySet()) {
+                addToArchive(entry, entries.get(entry), target);
+            }
+            target.close();
+        } catch (IOException ioe) {
+            throw Exceptions.propagate(ioe);
+        }
+    }
+
+    /**
+     * Generates the archive, saving it with the given name.
+     */
+    public File create(String archiveFile) {
+        return named(archiveFile).create();
+    }
+
+    /**
+     * Generates the archive.
+     * <p>
+     * If no name has been specified, the archive will be created as a temporary file with
+     * a unique name, that is deleted on exit. Otherwise, the given name will be used.
+     */
+    public File create() {
+        if (archive == null) {
+            File temp = Os.newTempFile("brooklyn-archive", type.toString());
+            temp.deleteOnExit();
+            named(temp);
+        }
+        try {
+            OutputStream output = new FileOutputStream(archive);
+            stream(output);
+            output.close();
+        } catch (IOException ioe) {
+            throw Exceptions.propagate(ioe);
+        }
+        return archive;
+    }
+
+    /**
+     * Recursively add files to the archive.
+     * <p>
+     * Code adapted from this <a href="http://stackoverflow.com/questions/1281229/how-to-use-jaroutputstream-to-create-a-jar-file">example</a>
+     * <p>
+     * <strong>Note</strong> {@link File} provides no support for symbolic links, and as such there is
+     * no way to ensure that a symbolic link to a directory is not followed when traversing the
+     * tree. In this case, iterables created by this traverser could contain files that are
+     * outside of the given directory or even be infinite if there is a symbolic link loop.
+     */
+    private void addToArchive(String path, Iterable<File> sources, ZipOutputStream target) throws IOException {
+        int size = Iterables.size(sources);
+        if (size==0) return;
+        boolean isDirectory;
+        if (size>1) {
+            // it must be directories if we are putting multiple things here 
+            isDirectory = true;
+        } else {
+            isDirectory = Iterables.getOnlyElement(sources).isDirectory();
+        }
+        
+        String name = path.replace("\\", "/");
+        if (isDirectory) {
+            name += "/";
+            JarEntry entry = new JarEntry(name);
+            
+            long lastModified=-1;
+            for (File source: sources)
+                if (source.lastModified()>lastModified)
+                    lastModified = source.lastModified();
+            
+            entry.setTime(lastModified);
+            target.putNextEntry(entry);
+            target.closeEntry();
+
+            for (File source: sources) {
+                if (!source.isDirectory()) {
+                    throw new IllegalStateException("Cannot add multiple items at a path in archive unless they are directories: "+sources+" at "+path+" is not valid.");
+                }
+                Iterable<File> children = Files.fileTreeTraverser().children(source);
+                for (File child : children) {
+                    addToArchive(Os.mergePaths(path, child.getName()), Collections.singleton(child), target);
+                }
+            }
+            return;
+        }
+
+        File source = Iterables.getOnlyElement(sources);
+        JarEntry entry = new JarEntry(name);
+        entry.setTime(source.lastModified());
+        target.putNextEntry(entry);
+        Files.asByteSource(source).copyTo(target);
+        target.closeEntry();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveTasks.java b/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveTasks.java
new file mode 100644
index 0000000..b58359a
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveTasks.java
@@ -0,0 +1,58 @@
+/*
+ * 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.util.file;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.net.Urls;
+
+public class ArchiveTasks {
+
+    /** as {@link #deploy(ResourceUtils, Map, String, SshMachineLocation, String, String, String)} with the most common parameters */
+    public static TaskFactory<?> deploy(final ResourceUtils optionalResolver, final String archiveUrl, final SshMachineLocation machine, final String destDir) {
+        return deploy(optionalResolver, null, archiveUrl, machine, destDir, false, null, null);
+    }
+    
+    /** returns a task which installs and unpacks the given archive, as per {@link ArchiveUtils#deploy(ResourceUtils, Map, String, SshMachineLocation, String, String, String)};
+     * if allowNonarchivesOrKeepArchiveAfterDeploy is false, this task will fail if the item is not an archive;
+     * in cases where the download type is not clear in the URL but is known by the caller, supply a optionalDestFile including the appropriate file extension */
+    public static TaskFactory<?> deploy(final ResourceUtils resolver, final Map<String, ?> props, final String archiveUrl, final SshMachineLocation machine, final String destDir, final boolean allowNonarchivesOrKeepArchiveAfterDeploy, final String optionalTmpDir, final String optionalDestFile) {
+        return new TaskFactory<TaskAdaptable<?>>() {
+            @Override
+            public TaskAdaptable<?> newTask() {
+                return Tasks.<Void>builder().name("deploying "+Urls.getBasename(archiveUrl)).description("installing "+archiveUrl+" and unpacking to "+destDir).body(new Runnable() {
+                    @Override
+                    public void run() {
+                        boolean unpacked = ArchiveUtils.deploy(resolver, props, archiveUrl, machine, destDir, allowNonarchivesOrKeepArchiveAfterDeploy, optionalTmpDir, optionalDestFile);
+                        if (!unpacked && !allowNonarchivesOrKeepArchiveAfterDeploy) {
+                            throw new IllegalStateException("Unable to unpack archive from "+archiveUrl+"; not able to infer archive type");
+                        }
+                    }
+                }).build();
+            }
+        };
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveUtils.java b/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveUtils.java
new file mode 100644
index 0000000..8277a0d
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/file/ArchiveUtils.java
@@ -0,0 +1,351 @@
+/*
+ * 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.util.file;
+
+import static java.lang.String.format;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.javalang.StackTraceSimplifier;
+import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
+import com.google.common.io.Files;
+
+public class ArchiveUtils {
+
+    private static final Logger log = LoggerFactory.getLogger(ArchiveUtils.class);
+
+    // TODO Make this a ConfigKey on the machine location
+    /** Number of attempts when copying a file to a remote server. */
+    public static final int NUM_RETRIES_FOR_COPYING = 5;
+
+    /**
+     * The types of archive that are supported by Brooklyn.
+     */
+    public static enum ArchiveType {
+        TAR,
+        TGZ,
+        TBZ,
+        ZIP,
+        JAR,
+        WAR,
+        EAR,
+        UNKNOWN;
+
+        /**
+         * Zip format archives used by Java.
+         */
+        public static Set<ArchiveType> ZIP_ARCHIVES = EnumSet.of(ArchiveType.ZIP, ArchiveType.JAR, ArchiveType.WAR, ArchiveType.EAR);
+
+        public static ArchiveUtils.ArchiveType of(String filename) {
+            if (filename == null) return null;
+            String ext = Files.getFileExtension(filename);
+            try {
+                return valueOf(ext.toUpperCase());
+            } catch (IllegalArgumentException iae) {
+                if (filename.toLowerCase().endsWith(".tar.gz")) {
+                    return TGZ;
+                } else if (filename.toLowerCase().endsWith(".tar.bz") ||
+                        filename.toLowerCase().endsWith(".tar.bz2") ||
+                        filename.toLowerCase().endsWith(".tar.xz")) {
+                    return TBZ;
+                } else {
+                    return UNKNOWN;
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            if (UNKNOWN.equals(this)) {
+                return "";
+            } else {
+                return name().toLowerCase();
+            }
+        }
+    }
+
+    /**
+     * Returns the list of commands used to install support for an archive with the given name.
+     */
+    public static List<String> installCommands(String fileName) {
+        List<String> commands = new LinkedList<String>();
+        switch (ArchiveType.of(fileName)) {
+            case TAR:
+            case TGZ:
+            case TBZ:
+                commands.add(BashCommands.INSTALL_TAR);
+                break;
+            case ZIP:
+                commands.add(BashCommands.INSTALL_UNZIP);
+                break;
+            case JAR:
+            case WAR:
+            case EAR:
+            case UNKNOWN:
+                break;
+        }
+        return commands;
+    }
+
+    /**
+     * Returns the list of commands used to extract the contents of the archive with the given name.
+     * <p>
+     * Optionally, Java archives of type
+     *
+     * @see #extractCommands(String, String)
+     */
+    public static List<String> extractCommands(String fileName, String sourceDir, String targetDir, boolean extractJar) {
+        return extractCommands(fileName, sourceDir, targetDir, extractJar, true);
+    }
+    
+    /** as {@link #extractCommands(String, String, String, boolean)}, but also with option to keep the original */
+    public static List<String> extractCommands(String fileName, String sourceDir, String targetDir, boolean extractJar, boolean keepOriginal) {
+        List<String> commands = new LinkedList<String>();
+        commands.add("cd " + targetDir);
+        String sourcePath = Os.mergePathsUnix(sourceDir, fileName);
+        switch (ArchiveType.of(fileName)) {
+            case TAR:
+                commands.add("tar xvf " + sourcePath);
+                break;
+            case TGZ:
+                commands.add("tar xvfz " + sourcePath);
+                break;
+            case TBZ:
+                commands.add("tar xvfj " + sourcePath);
+                break;
+            case ZIP:
+                commands.add("unzip " + sourcePath);
+                break;
+            case JAR:
+            case WAR:
+            case EAR:
+                if (extractJar) {
+                    commands.add("jar -xvf " + sourcePath);
+                    break;
+                }
+            case UNKNOWN:
+                if (!sourcePath.equals(Urls.mergePaths(targetDir, fileName))) {
+                    commands.add("cp " + sourcePath + " " + targetDir);
+                } else {
+                    keepOriginal = true;
+                    // else we'd just end up deleting it!
+                    // this branch will often lead to errors in any case, see the allowNonarchivesOrKeepArchiveAfterDeploy parameter 
+                    // in ArchiveTasks which calls through to here and then fails in the case corresponding to this code branch
+                }
+                break;
+        }
+        if (!keepOriginal && !commands.isEmpty())
+            commands.add("rm "+sourcePath);
+        return commands;
+    }
+
+    /**
+     * Returns the list of commands used to extract the contents of the archive with the given name.
+     * <p>
+     * The archive will be extracted in its current directory unless it is a Java archive of type {@code .jar},
+     * {@code .war} or {@code .ear}, which will be left as is.
+     *
+     * @see #extractCommands(String, String, String, boolean)
+     */
+    public static List<String> extractCommands(String fileName, String sourceDir) {
+        return extractCommands(fileName, sourceDir, ".", false);
+    }
+
+    /**
+     * Deploys an archive file to a remote machine and extracts the contents.
+     */
+    public static void deploy(String archiveUrl, SshMachineLocation machine, String destDir) {
+        deploy(MutableMap.<String, Object>of(), archiveUrl, machine, destDir);
+    }
+
+    /**
+     * Deploys an archive file to a remote machine and extracts the contents.
+     * <p>
+     * Copies the archive file from the given URL to the destination directory and extracts
+     * the contents. If the URL is a local directory, the contents are packaged as a Zip archive first.
+     *
+     * @see #deploy(String, SshMachineLocation, String, String)
+     * @see #deploy(Map, String, SshMachineLocation, String, String, String)
+     */
+    public static void deploy(Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String destDir) {
+        if (Urls.isDirectory(archiveUrl)) {
+            File zipFile = ArchiveBuilder.zip().entry(".", Urls.toFile(archiveUrl)).create();
+            archiveUrl = zipFile.getAbsolutePath();
+        }
+
+        // Determine filename
+        String destFile = archiveUrl.contains("?") ? archiveUrl.substring(0, archiveUrl.indexOf('?')) : archiveUrl;
+        destFile = destFile.substring(destFile.lastIndexOf('/') + 1);
+
+        deploy(props, archiveUrl, machine, destDir, destFile);
+    }
+
+    /**
+     * Deploys an archive file to a remote machine and extracts the contents.
+     * <p>
+     * Copies the archive file from the given URL to a file in the destination directory and extracts
+     * the contents.
+     *
+     * @see #deploy(String, SshMachineLocation, String)
+     * @see #deploy(Map, String, SshMachineLocation, String, String, String)
+     */
+    public static void deploy(String archiveUrl, SshMachineLocation machine, String destDir, String destFile) {
+        deploy(MutableMap.<String, Object>of(), archiveUrl, machine, destDir, destDir, destFile);
+    }
+    public static void deploy(Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String destDir, String destFile) {
+        deploy(props, archiveUrl, machine, destDir, destDir, destFile);
+    }
+    public static void deploy(Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String tmpDir, String destDir, String destFile) {
+        deploy(null, props, archiveUrl, machine, destDir, true, tmpDir, destFile);
+    }
+    
+    /**
+     * Deploys an archive file to a remote machine and extracts the contents.
+     * <p>
+     * Copies the archive file from the given URL to a file in a temporary directory and extracts
+     * the contents in the destination directory. For Java archives of type {@code .jar},
+     * {@code .war} or {@code .ear} the file is simply copied.
+     * 
+     * @return true if the archive is downloaded AND unpacked; false if it is downloaded but not unpacked; 
+     * throws if there was an error downloading or, for known archive types, unpacking.
+     *
+     * @see #deploy(String, SshMachineLocation, String)
+     * @see #deploy(Map, String, SshMachineLocation, String, String, String)
+     * @see #install(SshMachineLocation, String, String, int)
+     */
+    public static boolean deploy(ResourceUtils resolver, Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String destDir, boolean keepArchiveAfterUnpacking, String optionalTmpDir, String optionalDestFile) {
+        String destFile = optionalDestFile;
+        if (destFile==null) destFile = Urls.getBasename(Preconditions.checkNotNull(archiveUrl, "archiveUrl"));
+        if (Strings.isBlank(destFile)) 
+            throw new IllegalStateException("Not given filename and cannot infer archive type from '"+archiveUrl+"'");
+        
+        String tmpDir = optionalTmpDir;
+        if (tmpDir==null) tmpDir=Preconditions.checkNotNull(destDir, "destDir");
+        if (props==null) props = MutableMap.of();
+        String destPath = Os.mergePaths(tmpDir, destFile);
+
+        // Use the location mutex to prevent package manager locking issues
+        machine.acquireMutex("installing", "installing archive");
+        try {
+            int result = install(resolver, props, machine, archiveUrl, destPath, NUM_RETRIES_FOR_COPYING);
+            if (result != 0) {
+                throw new IllegalStateException(format("Unable to install archive %s to %s", archiveUrl, machine));
+            }
+
+            // extract, now using task if available
+            MutableList<String> commands = MutableList.copyOf(installCommands(destFile))
+                    .appendAll(extractCommands(destFile, tmpDir, destDir, false, keepArchiveAfterUnpacking));
+            if (DynamicTasks.getTaskQueuingContext()!=null) {
+                result = DynamicTasks.queue(SshTasks.newSshExecTaskFactory(machine, commands.toArray(new String[0])).summary("extracting archive").requiringExitCodeZero()).get();
+            } else {
+                result = machine.execCommands(props, "extracting content", commands);
+            }
+            if (result != 0) {
+                throw new IllegalStateException(format("Failed to expand archive %s on %s", archiveUrl, machine));
+            }
+            return ArchiveType.of(destFile)!=ArchiveType.UNKNOWN;
+        } finally {
+            machine.releaseMutex("installing");
+        }
+    }
+
+    /**
+     * Installs a URL onto a remote machine.
+     *
+     * @see #install(Map, SshMachineLocation, String, String, int)
+     */
+    public static int install(SshMachineLocation machine, String urlToInstall, String target) {
+        return install(MutableMap.<String, Object>of(), machine, urlToInstall, target, NUM_RETRIES_FOR_COPYING);
+    }
+
+    /**
+     * Installs a URL onto a remote machine.
+     *
+     * @see #install(SshMachineLocation, String, String)
+     * @see SshMachineLocation#installTo(Map, String, String)
+     */
+    public static int install(Map<String, ?> props, SshMachineLocation machine, String urlToInstall, String target, int numAttempts) {
+        return install(null, props, machine, urlToInstall, target, numAttempts);
+    }
+    
+    public static int install(ResourceUtils resolver, Map<String, ?> props, SshMachineLocation machine, String urlToInstall, String target, int numAttempts) {
+        if (resolver==null) resolver = ResourceUtils.create(machine);
+        Exception lastError = null;
+        int retriesRemaining = numAttempts;
+        int attemptNum = 0;
+        do {
+            attemptNum++;
+            try {
+                Tasks.setBlockingDetails("Installing "+urlToInstall+" at "+machine);
+                // TODO would be nice to have this in a task (and the things within it!)
+                return machine.installTo(resolver, props, urlToInstall, target);
+            } catch (Exception e) {
+                Exceptions.propagateIfFatal(e);
+                lastError = e;
+                String stack = StackTraceSimplifier.toString(e);
+                if (stack.contains("net.schmizz.sshj.sftp.RemoteFile.write")) {
+                    log.warn("Failed to transfer "+urlToInstall+" to "+machine+", retryable error, attempt "+attemptNum+"/"+numAttempts+": "+e);
+                    continue;
+                }
+                log.warn("Failed to transfer "+urlToInstall+" to "+machine+", not a retryable error so failing: "+e);
+                throw Exceptions.propagate(e);
+            } finally {
+                Tasks.resetBlockingDetails();
+            }
+        } while (retriesRemaining --> 0);
+        throw Exceptions.propagate(lastError);
+    }
+
+    /**
+     * Copies the entire contents of a file to a String.
+     *
+     * @see com.google.common.io.Files#toString(File, java.nio.charset.Charset)
+     */
+    public static String readFullyString(File sourceFile) {
+        try {
+            return Files.toString(sourceFile, Charsets.UTF_8);
+        } catch (IOException ioe) {
+            throw Exceptions.propagate(ioe);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/flags/ClassCoercionException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/flags/ClassCoercionException.java b/core/src/main/java/org/apache/brooklyn/core/util/flags/ClassCoercionException.java
new file mode 100644
index 0000000..72c8698
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/flags/ClassCoercionException.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.util.flags;
+
+/**
+ * Thrown to indicate that {@link TypeCoercions} could not cast an object from one
+ * class to another.
+ */
+public class ClassCoercionException extends ClassCastException {
+    public ClassCoercionException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>ClassCoercionException</code> with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public ClassCoercionException(String s) {
+        super(s);
+    }
+}


[45/64] incubator-brooklyn git commit: brooklyn-software-messaging: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.java
deleted file mode 100644
index e6b6db5..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.java
+++ /dev/null
@@ -1,258 +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 brooklyn.entity.messaging.activemq;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
-import javax.jms.Connection;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-import javax.jms.Queue;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-
-import org.apache.activemq.ActiveMQConnectionFactory;
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.test.entity.TestApplication;
-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 brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.java.UsesJmx;
-import brooklyn.entity.java.UsesJmx.JmxAgentModes;
-import brooklyn.entity.trait.Startable;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-/**
- * Test the operation of the {@link ActiveMQBroker} class.
- */
-public class ActiveMQIntegrationTest {
-    private static final Logger log = LoggerFactory.getLogger(ActiveMQIntegrationTest.class);
-
-    private TestApplication app;
-    private Location testLocation;
-    private ActiveMQBroker activeMQ;
-
-    @BeforeMethod(alwaysRun = true)
-    public void setup() throws Exception {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        testLocation = app.newLocalhostProvisioningLocation();
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void shutdown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    /**
-     * Test that the broker starts up and sets SERVICE_UP correctly.
-     */
-    @Test(groups = "Integration")
-    public void canStartupAndShutdown() throws Exception {
-        activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class));
-
-        activeMQ.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ, Startable.SERVICE_UP, true);
-        log.info("JMX URL is "+activeMQ.getAttribute(UsesJmx.JMX_URL));
-        activeMQ.stop();
-        assertFalse(activeMQ.getAttribute(Startable.SERVICE_UP));
-    }
-
-    /**
-     * Test that the broker starts up and sets SERVICE_UP correctly,
-     * when a jmx port is supplied
-     */
-    @Test(groups = "Integration")
-    public void canStartupAndShutdownWithCustomJmx() throws Exception {
-        activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class)
-            .configure("jmxPort", "11099+"));
-       
-        activeMQ.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ, Startable.SERVICE_UP, true);
-        log.info("JMX URL is "+activeMQ.getAttribute(UsesJmx.JMX_URL));
-        activeMQ.stop();
-        assertFalse(activeMQ.getAttribute(Startable.SERVICE_UP));
-    }
-
-    @Test(groups = "Integration")
-    public void canStartupAndShutdownWithCustomBrokerName() throws Exception {
-        activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class)
-            .configure("jmxPort", "11099+")
-            .configure("brokerName", "bridge"));
-
-        activeMQ.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ, Startable.SERVICE_UP, true);
-        log.info("JMX URL is "+activeMQ.getAttribute(UsesJmx.JMX_URL));
-        activeMQ.stop();
-        assertFalse(activeMQ.getAttribute(Startable.SERVICE_UP));
-    }
-
-    
-    @Test(groups = "Integration")
-    public void canStartTwo() throws Exception {
-        ActiveMQBroker activeMQ1 = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class));
-        ActiveMQBroker activeMQ2 = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class));
-
-        activeMQ1.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ1, Startable.SERVICE_UP, true);
-        log.info("JMX URL is "+activeMQ1.getAttribute(UsesJmx.JMX_URL));
-
-        activeMQ2.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ2, Startable.SERVICE_UP, true);
-        log.info("JMX URL is "+activeMQ2.getAttribute(UsesJmx.JMX_URL));
-    }
-
-    /**
-     * Test that setting the 'queue' property causes a named queue to be created.
-     */
-    @Test(groups = "Integration")
-    public void testCreatingQueuesDefault() throws Exception {
-        String url = testCreatingQueuesInternal(null);
-        // localhost default is jmxmp
-        Assert.assertTrue(url.contains("jmxmp"), "url="+url);
-    }
-
-    @Test(groups = "Integration")
-    public void testCreatingQueuesRmi() throws Exception {
-        String url = testCreatingQueuesInternal(JmxAgentModes.JMX_RMI_CUSTOM_AGENT);
-        Assert.assertTrue(url.contains("rmi://"), "url="+url);
-        Assert.assertFalse(url.contains("rmi:///jndi"), "url="+url);
-        Assert.assertFalse(url.contains("jmxmp"), "url="+url);
-    }
-
-    @Test(groups = "Integration")
-    public void testCreatingQueuesJmxmp() throws Exception {
-        String url = testCreatingQueuesInternal(JmxAgentModes.JMXMP);
-        // localhost default is rmi
-        Assert.assertTrue(url.contains("jmxmp"), "url="+url);
-        Assert.assertFalse(url.contains("rmi"), "url="+url);
-    }
-
-    @Test(groups = "Integration")
-    public void testCreatingQueuesNoAgent() throws Exception {
-        String url = testCreatingQueuesInternal(JmxAgentModes.NONE);
-        // localhost default is rmi
-        Assert.assertTrue(url.contains("service:jmx:rmi"), "url="+url);
-        Assert.assertFalse(url.contains("jmxmp"), "url="+url);
-    }
-
-    public String testCreatingQueuesInternal(JmxAgentModes mode) throws Exception {
-        String queueName = "testQueue";
-        int number = 20;
-        String content = "01234567890123456789012345678901";
-
-        // Start broker with a configured queue
-        // FIXME Not yet using app.createAndManageChild because later in test do activeMQ.queueNames,
-        // which is not on interface
-        activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class)
-            .configure("queue", queueName)
-            .configure(UsesJmx.JMX_AGENT_MODE, mode));
-        
-        activeMQ.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ, Startable.SERVICE_UP, true);
-
-        String jmxUrl = activeMQ.getAttribute(UsesJmx.JMX_URL);
-        log.info("JMX URL ("+mode+") is "+jmxUrl);
-        
-        try {
-            // Check queue created
-            assertFalse(activeMQ.getQueueNames().isEmpty());
-            assertEquals(activeMQ.getQueueNames().size(), 1);
-            assertTrue(activeMQ.getQueueNames().contains(queueName));
-            assertEquals(activeMQ.getChildren().size(), 1);
-            assertFalse(activeMQ.getQueues().isEmpty());
-            assertEquals(activeMQ.getQueues().size(), 1);
-
-            // Get the named queue entity
-            ActiveMQQueue queue = activeMQ.getQueues().get(queueName);
-            assertNotNull(queue);
-            assertEquals(queue.getName(), queueName);
-
-            // Connect to broker using JMS and send messages
-            Connection connection = getActiveMQConnection(activeMQ);
-            clearQueue(connection, queueName);
-            EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, 0);
-            sendMessages(connection, number, queueName, content);
-            // Check messages arrived
-            EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, number);
-
-            // Clear the messages
-            assertEquals(clearQueue(connection, queueName), number);
-
-            // Check messages cleared
-            EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, 0);
-
-            connection.close();
-
-            // Close the JMS connection
-        } finally {
-            // Stop broker
-            activeMQ.stop();
-        }
-        
-        return jmxUrl;
-    }
-
-    private Connection getActiveMQConnection(ActiveMQBroker activeMQ) throws Exception {
-        int port = activeMQ.getAttribute(ActiveMQBroker.OPEN_WIRE_PORT);
-        String address = activeMQ.getAttribute(ActiveMQBroker.ADDRESS);
-        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://"+address+":"+port);
-        Connection connection = factory.createConnection("admin", "activemq");
-        connection.start();
-        return connection;
-    }
-
-    private void sendMessages(Connection connection, int count, String queueName, String content) throws Exception {
-        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-        Queue destination = session.createQueue(queueName);
-        MessageProducer messageProducer = session.createProducer(destination);
-
-        for (int i = 0; i < count; i++) {
-            TextMessage message = session.createTextMessage(content);
-            messageProducer.send(message);
-        }
-
-        session.close();
-    }
-
-    private int clearQueue(Connection connection, String queueName) throws Exception {
-        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-        Queue destination = session.createQueue(queueName);
-        MessageConsumer messageConsumer = session.createConsumer(destination);
-
-        int received = 0;
-        while (messageConsumer.receive(500) != null) received++;
-
-        session.close();
-        
-        return received;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaIntegrationTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaIntegrationTest.java
deleted file mode 100644
index 39d3e59..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaIntegrationTest.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 brooklyn.entity.messaging.kafka;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.location.LocationSpec;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.test.entity.TestApplication;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.messaging.activemq.ActiveMQBroker;
-import brooklyn.entity.trait.Startable;
-
-import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-
-import brooklyn.test.Asserts;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.time.Duration;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-/**
- * Test the operation of the {@link ActiveMQBroker} class.
- *
- * TODO test that sensors update.
- */
-public class KafkaIntegrationTest {
-
-    private TestApplication app;
-    private Location testLocation;
-
-    @BeforeMethod(alwaysRun = true)
-    public void setup() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        LocationSpec<LocalhostMachineProvisioningLocation> locationSpec = LocationSpec.create(LocalhostMachineProvisioningLocation.class);
-        testLocation = app.getManagementContext().getLocationManager().createLocation(locationSpec);
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void shutdown() {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    /**
-     * Test that we can start a zookeeper.
-     */
-    @Test(groups = "Integration")
-    public void testZookeeper() {
-        final KafkaZooKeeper zookeeper = app.createAndManageChild(EntitySpec.create(KafkaZooKeeper.class));
-
-        zookeeper.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 60*1000), zookeeper, Startable.SERVICE_UP, true);
-
-        zookeeper.stop();
-        assertFalse(zookeeper.getAttribute(Startable.SERVICE_UP));
-    }
-
-    /**
-     * Test that we can start a  broker and zookeeper together.
-     */
-    @Test(groups = "Integration")
-    public void testBrokerPlusZookeeper() {
-        final KafkaZooKeeper zookeeper = app.createAndManageChild(EntitySpec.create(KafkaZooKeeper.class));
-        final KafkaBroker broker = app.createAndManageChild(EntitySpec.create(KafkaBroker.class).configure(KafkaBroker.ZOOKEEPER, zookeeper));
-
-        zookeeper.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 60*1000), zookeeper, Startable.SERVICE_UP, true);
-
-        broker.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 60*1000), broker, Startable.SERVICE_UP, true);
-
-        zookeeper.stop();
-        assertFalse(zookeeper.getAttribute(Startable.SERVICE_UP));
-
-        broker.stop();
-        assertFalse(broker.getAttribute(Startable.SERVICE_UP));
-    }
-
-    /**
-     * Test that we can start a cluster with zookeeper and one broker.
-     *
-     * Connects to the zookeeper controller and tests sending and receiving messages on a topic.
-     */
-    @Test(groups = "Integration")
-    public void testTwoBrokerCluster() throws InterruptedException {
-        final KafkaCluster cluster = app.createAndManageChild(EntitySpec.create(KafkaCluster.class)
-                .configure(KafkaCluster.INITIAL_SIZE, 2));
-
-        cluster.start(ImmutableList.of(testLocation));
-        Asserts.succeedsEventually(MutableMap.of("timeout", Duration.TWO_MINUTES), new Callable<Void>() {
-            @Override
-            public Void call() {
-                assertTrue(cluster.getAttribute(Startable.SERVICE_UP));
-                assertTrue(cluster.getZooKeeper().getAttribute(Startable.SERVICE_UP));
-                assertEquals(cluster.getCurrentSize().intValue(), 2);
-                return null;
-            }
-        });
-
-        Entities.dumpInfo(cluster);
-
-        final KafkaSupport support = new KafkaSupport(cluster);
-
-        support.sendMessage("brooklyn", "TEST_MESSAGE");
-
-        Asserts.succeedsEventually(MutableMap.of("timeout", Duration.FIVE_SECONDS), new Runnable() {
-            @Override
-            public void run() {
-                String message = support.getMessage("brooklyn");
-                assertEquals(message, "TEST_MESSAGE");
-            }
-        });
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaLiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaLiveTest.java
deleted file mode 100644
index 7d122c6..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaLiveTest.java
+++ /dev/null
@@ -1,68 +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 brooklyn.entity.messaging.kafka;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.trait.Startable;
-import brooklyn.test.Asserts;
-import brooklyn.util.collections.MutableMap;
-
-import com.google.common.collect.ImmutableList;
-
-public class KafkaLiveTest extends AbstractEc2LiveTest {
-
-    /**
-     * Test that can install, start and use a Kafka cluster with two brokers.
-     */
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        final KafkaCluster cluster = app.createAndManageChild(EntitySpec.create(KafkaCluster.class)
-                .configure("startTimeout", 300) // 5 minutes
-                .configure("initialSize", 2));
-        app.start(ImmutableList.of(loc));
-
-        Asserts.succeedsEventually(MutableMap.of("timeout", 300000l), new Callable<Void>() {
-            @Override
-            public Void call() {
-                assertTrue(cluster.getAttribute(Startable.SERVICE_UP));
-                assertTrue(cluster.getZooKeeper().getAttribute(Startable.SERVICE_UP));
-                assertEquals(cluster.getCurrentSize().intValue(), 2);
-                return null;
-            }
-        });
-
-        Entities.dumpInfo(cluster);
-
-        KafkaSupport support = new KafkaSupport(cluster);
-
-        support.sendMessage("brooklyn", "TEST_MESSAGE");
-        String message = support.getMessage("brooklyn");
-        assertEquals(message, "TEST_MESSAGE");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaSupport.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaSupport.java b/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaSupport.java
deleted file mode 100644
index 179f76e..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/kafka/KafkaSupport.java
+++ /dev/null
@@ -1,109 +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 brooklyn.entity.messaging.kafka;
-
-import brooklyn.entity.basic.EntityPredicates;
-import brooklyn.entity.zookeeper.ZooKeeperNode;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.kafka.clients.consumer.KafkaConsumer;
-import org.apache.kafka.clients.producer.KafkaProducer;
-import org.apache.kafka.clients.producer.Producer;
-import org.apache.kafka.clients.producer.ProducerRecord;
-
-import java.security.InvalidParameterException;
-import java.util.Properties;
-
-import static java.lang.String.format;
-
-/**
- * Kafka test framework for integration and live tests, using the Kafka Java API.
- */
-public class KafkaSupport {
-
-    private final KafkaCluster cluster;
-
-    public KafkaSupport(KafkaCluster cluster) {
-        this.cluster = cluster;
-    }
-
-    /**
-     * Send a message to the {@link KafkaCluster} on the given topic.
-     */
-    public void sendMessage(String topic, String message) {
-        Optional<Entity> anyBrokerNodeInCluster = Iterables.tryFind(cluster.getCluster().getChildren(), Predicates.and(
-                Predicates.instanceOf(KafkaBroker.class),
-                EntityPredicates.attributeEqualTo(KafkaBroker.SERVICE_UP, true)));
-        if (anyBrokerNodeInCluster.isPresent()) {
-            KafkaBroker broker = (KafkaBroker)anyBrokerNodeInCluster.get();
-
-            Properties props = new Properties();
-
-            props.put("metadata.broker.list", format("%s:%d", broker.getAttribute(KafkaBroker.HOSTNAME), broker.getKafkaPort()));
-            props.put("bootstrap.servers", format("%s:%d", broker.getAttribute(KafkaBroker.HOSTNAME), broker.getKafkaPort()));
-            props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
-            props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
-
-            Producer<String, String> producer = new KafkaProducer<>(props);
-            ((KafkaZooKeeper)cluster.getZooKeeper()).createTopic(topic);
-
-            ProducerRecord<String, String> data = new ProducerRecord<>(topic, message);
-            producer.send(data);
-            producer.close();
-        } else {
-            throw new InvalidParameterException("No kafka broker node found");
-        }
-    }
-
-    /**
-     * Retrieve the next message on the given topic from the {@link KafkaCluster}.
-     */
-    public String getMessage(String topic) {
-        ZooKeeperNode zookeeper = cluster.getZooKeeper();
-        Optional<Entity> anyBrokerNodeInCluster = Iterables.tryFind(cluster.getCluster().getChildren(), Predicates.and(
-                Predicates.instanceOf(KafkaBroker.class),
-                EntityPredicates.attributeEqualTo(KafkaBroker.SERVICE_UP, true)));
-        if (anyBrokerNodeInCluster.isPresent()) {
-            KafkaBroker broker = (KafkaBroker)anyBrokerNodeInCluster.get();
-
-            Properties props = new Properties();
-
-            props.put("bootstrap.servers", format("%s:%d", broker.getAttribute(KafkaBroker.HOSTNAME), broker.getKafkaPort()));
-            props.put("zookeeper.connect", format(zookeeper.getHostname(), zookeeper.getZookeeperPort()));
-            props.put("group.id", "brooklyn");
-            props.put("partition.assignment.strategy", "RoundRobin");
-            props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
-            props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
-
-            KafkaConsumer consumer = new KafkaConsumer(props);
-
-            consumer.subscribe(topic);
-            // FIXME unimplemented KafkaConsumer.poll
-//            Object consumerRecords = consumer.poll(Duration.seconds(3).toMilliseconds()).get(topic);
-            return "TEST_MESSAGE";
-        } else {
-            throw new InvalidParameterException("No kafka broker node found");
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidEc2LiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidEc2LiveTest.java
deleted file mode 100644
index 06af482..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidEc2LiveTest.java
+++ /dev/null
@@ -1,46 +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 brooklyn.entity.messaging.qpid;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-
-import com.google.common.collect.ImmutableList;
-
-public class QpidEc2LiveTest extends AbstractEc2LiveTest {
-
-    // TODO Also check can connect (e.g. to send/receive messages)
-    
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        QpidBroker qpid = app.createAndManageChild(EntitySpec.create(QpidBroker.class)
-                .configure("jmxPort", "9909+")
-                .configure("rmiRegistryPort", "9910+"));
-        
-        qpid.start(ImmutableList.of(loc));
-        EntityTestUtils.assertAttributeEqualsEventually(qpid, QpidBroker.SERVICE_UP, true);
-    }
-    
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidIntegrationTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidIntegrationTest.java
deleted file mode 100644
index 7346297..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/qpid/QpidIntegrationTest.java
+++ /dev/null
@@ -1,254 +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 brooklyn.entity.messaging.qpid;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Map;
-
-import javax.jms.Connection;
-import javax.jms.JMSException;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-import javax.jms.Queue;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.test.HttpTestUtils;
-import org.apache.brooklyn.test.entity.TestApplication;
-import org.apache.qpid.client.AMQConnectionFactory;
-import org.apache.qpid.configuration.ClientProperties;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.trait.Startable;
-import brooklyn.test.Asserts;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Test the operation of the {@link QpidBroker} class.
- */
-public class QpidIntegrationTest {
-    private static final Logger log = LoggerFactory.getLogger(QpidIntegrationTest.class);
-
-    private TestApplication app;
-    private Location testLocation;
-    private QpidBroker qpid;
-
-    @BeforeMethod(groups = "Integration")
-    public void setup() {
-        String workingDir = System.getProperty("user.dir");
-        log.info("Qpid working dir: {}", workingDir);
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        testLocation = app.newLocalhostProvisioningLocation();
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void shutdown() {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    /**
-     * Test that the broker starts up with JMX and RMI ports configured, and sets SERVICE_UP correctly.
-     */
-    @Test(groups = "Integration")
-    public void canStartupAndShutdown() {
-        qpid = app.createAndManageChild(EntitySpec.create(QpidBroker.class)
-                .configure("jmxPort", "9909+")
-                .configure("rmiRegistryPort", "9910+"));
-        qpid.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(qpid, Startable.SERVICE_UP, true);
-        qpid.stop();
-        assertFalse(qpid.getAttribute(Startable.SERVICE_UP));
-    }
-
-    /**
-     * Test that the broker starts up with HTTP management enabled, and we can connect to the URL.
-     */
-    @Test(groups = "Integration")
-    public void canStartupAndShutdownWithHttpManagement() {
-        qpid = app.createAndManageChild(EntitySpec.create(QpidBroker.class)
-                .configure("httpManagementPort", "8888+"));
-        qpid.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(qpid, Startable.SERVICE_UP, true);
-        String httpUrl = "http://"+qpid.getAttribute(QpidBroker.HOSTNAME)+":"+qpid.getAttribute(QpidBroker.HTTP_MANAGEMENT_PORT)+"/management";
-        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(httpUrl, 200);
-        // TODO check actual REST output
-        qpid.stop();
-        assertFalse(qpid.getAttribute(Startable.SERVICE_UP));
-    }
-
-    /**
-     * Test that the broker starts up and sets SERVICE_UP correctly when plugins are configured.
-     * 
-     * FIXME the custom plugin was written against qpid 0.14, so that's the version we need to run
-     * this test against. However, v0.14 is no longer available from the download site.
-     * We should update this plugin so it works with the latest qpid.
-     */
-    @Test(enabled = false, groups = "Integration")
-    public void canStartupAndShutdownWithPlugin() {
-        Map<String,String> qpidRuntimeFiles = MutableMap.<String,String>builder()
-                .put("classpath://qpid-test-config.xml", "etc/config.xml")
-                .put("http://developers.cloudsoftcorp.com/brooklyn/repository-test/0.7.0/QpidBroker/qpid-test-plugin.jar", "lib/plugins/sample-plugin.jar")
-                .build();
-        qpid = app.createAndManageChild(EntitySpec.create(QpidBroker.class)
-                .configure(SoftwareProcess.RUNTIME_FILES, qpidRuntimeFiles)
-                .configure(QpidBroker.SUGGESTED_VERSION, "0.14"));
-        qpid.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(qpid, Startable.SERVICE_UP, true);
-        qpid.stop();
-        assertFalse(qpid.getAttribute(Startable.SERVICE_UP));
-    }
-
-    /**
-     * Test that setting the 'queue' property causes a named queue to be created.
-     *
-     * This test is disabled, pending further investigation. Issue with AMQP 0-10 queue names.
-     * 
-     * FIXME disabled becausing failing in jenkins CI (in QpidIntegrationTest.getQpidConnection()).
-     *     url=amqp://admin:********@brooklyn/localhost?brokerlist='tcp://localhost:5672'
-     * Was previously enabled, dispite comment above about "test is disabled".	
-     */
-    @Test(enabled = false, groups = { "Integration", "WIP" })
-    public void testCreatingQueues() {
-        final String queueName = "testQueue";
-        final int number = 20;
-        final String content = "01234567890123456789012345678901";
-
-        // Start broker with a configured queue
-        // FIXME Can't use app.createAndManageChild, because of QpidDestination reffing impl directly
-        qpid = app.createAndManageChild(EntitySpec.create(QpidBroker.class)
-                .configure("queue", queueName));
-        qpid.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(qpid, Startable.SERVICE_UP, true);
-
-        try {
-            // Check queue created
-            assertFalse(qpid.getQueueNames().isEmpty());
-            assertEquals(qpid.getQueueNames().size(), 1);
-            assertTrue(qpid.getQueueNames().contains(queueName));
-            assertEquals(qpid.getChildren().size(), 1);
-            assertFalse(qpid.getQueues().isEmpty());
-            assertEquals(qpid.getQueues().size(), 1);
-
-            // Get the named queue entity
-            final QpidQueue queue = qpid.getQueues().get(queueName);
-            assertNotNull(queue);
-
-            // Connect to broker using JMS and send messages
-            Connection connection = getQpidConnection(qpid);
-            clearQueue(connection, queue.getQueueName());
-            Asserts.succeedsEventually(new Runnable() {
-                @Override
-                public void run() {
-                    assertEquals(queue.getAttribute(QpidQueue.QUEUE_DEPTH_MESSAGES), Integer.valueOf(0));
-                }
-            });
-            sendMessages(connection, number, queue.getQueueName(), content);
-
-            // Check messages arrived
-            Asserts.succeedsEventually(new Runnable() {
-                @Override
-                public void run() {
-                    assertEquals(queue.getAttribute(QpidQueue.QUEUE_DEPTH_MESSAGES), Integer.valueOf(number));
-                    assertEquals(queue.getAttribute(QpidQueue.QUEUE_DEPTH_BYTES), Integer.valueOf(number * content.length()));
-                }
-            });
-
-            //TODO clearing the queue currently returns 0
-//            // Clear the messages -- should get 20
-//            assertEquals clearQueue(connection, queue.queueName), 20
-//
-//            // Check messages cleared
-//            executeUntilSucceeds {
-//                assertEquals queue.getAttribute(QpidQueue.QUEUE_DEPTH_MESSAGES), 0
-//                assertEquals queue.getAttribute(QpidQueue.QUEUE_DEPTH_BYTES), 0
-//            }
-
-            // Close the JMS connection
-            connection.close();
-        } catch (JMSException jmse) {
-            log.warn("JMS exception caught", jmse);
-            throw Exceptions.propagate(jmse);
-        } finally {
-            // Stop broker
-            qpid.stop();
-            qpid = null;
-            app = null;
-        }
-    }
-
-    private Connection getQpidConnection(QpidBroker qpid) {
-        int port = qpid.getAttribute(Attributes.AMQP_PORT);
-        System.setProperty(ClientProperties.AMQP_VERSION, "0-10");
-        System.setProperty(ClientProperties.DEST_SYNTAX, "ADDR");
-        String connectionUrl = String.format("amqp://admin:admin@brooklyn/localhost?brokerlist='tcp://localhost:%d'", port);
-        try {
-            AMQConnectionFactory factory = new AMQConnectionFactory(connectionUrl);
-            Connection connection = factory.createConnection();
-            connection.start();
-            return connection;
-        } catch (Exception e) {
-            log.error(String.format("Error connecting to qpid: %s", connectionUrl), e);
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    private void sendMessages(Connection connection, int count, String queueName, String content) throws JMSException {
-        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-        Queue destination = session.createQueue(queueName);
-        MessageProducer messageProducer = session.createProducer(destination);
-
-        for (int i = 0; i < count; i++) {
-            TextMessage message = session.createTextMessage(content);
-            messageProducer.send(message);
-        }
-
-        session.close();
-    }
-
-    private int clearQueue(Connection connection, String queueName) throws JMSException {
-        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-        Queue destination = session.createQueue(queueName);
-        MessageConsumer messageConsumer = session.createConsumer(destination);
-
-        int received = 0;
-        while (messageConsumer.receive(500) != null) received++;
-
-        session.close();
-
-        return received;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitEc2LiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitEc2LiveTest.java
deleted file mode 100644
index 8eaa991..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitEc2LiveTest.java
+++ /dev/null
@@ -1,98 +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 brooklyn.entity.messaging.rabbit;
-
-import static org.testng.Assert.assertEquals;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.SkipException;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-import brooklyn.entity.messaging.MessageBroker;
-import brooklyn.entity.messaging.amqp.AmqpExchange;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Maps;
-import com.rabbitmq.client.Channel;
-import com.rabbitmq.client.Connection;
-import com.rabbitmq.client.ConnectionFactory;
-import com.rabbitmq.client.QueueingConsumer;
-
-public class RabbitEc2LiveTest extends AbstractEc2LiveTest {
-
-    private static final Logger LOG = LoggerFactory.getLogger(RabbitEc2LiveTest.class);
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        RabbitBroker rabbit = app.createAndManageChild(EntitySpec.create(RabbitBroker.class));
-        rabbit.start(ImmutableList.of(loc));
-        EntityTestUtils.assertAttributeEqualsEventually(rabbit, RabbitBroker.SERVICE_UP, true);
-
-        byte[] content = "MessageBody".getBytes(Charsets.UTF_8);
-        String queue = "queueName";
-        Channel producer = null;
-        Channel consumer = null;
-        try {
-            producer = getAmqpChannel(rabbit);
-            consumer = getAmqpChannel(rabbit);
-
-            producer.queueDeclare(queue, true, false, false, Maps.<String,Object>newHashMap());
-            producer.queueBind(queue, AmqpExchange.DIRECT, queue);
-            producer.basicPublish(AmqpExchange.DIRECT, queue, null, content);
-            
-            QueueingConsumer queueConsumer = new QueueingConsumer(consumer);
-            consumer.basicConsume(queue, true, queueConsumer);
-        
-            QueueingConsumer.Delivery delivery = queueConsumer.nextDelivery();
-            assertEquals(delivery.getBody(), content);
-        } finally {
-            if (producer != null) producer.close();
-            if (consumer != null) consumer.close();
-        }
-    }
-
-    private Channel getAmqpChannel(RabbitBroker rabbit) throws Exception {
-        String uri = rabbit.getAttribute(MessageBroker.BROKER_URL);
-        LOG.warn("connecting to rabbit {}", uri);
-        ConnectionFactory factory = new ConnectionFactory();
-        factory.setUri(uri);
-        Connection conn = factory.newConnection();
-        Channel channel = conn.createChannel();
-        return channel;
-    }
-
-    @Override
-    public void test_CentOS_5() throws SkipException {
-        // Not supported. The EPEL repository described here at [1] does not contain erlang, and the
-        // Erlang repository at [1] requires old versions of rpmlib. Additionally, [2] suggests that
-        // Centos 5 is not supported
-        // [1]:http://www.rabbitmq.com/install-rpm.html
-        // [2]: https://www.erlang-solutions.com/downloads/download-erlang-otp
-        throw new SkipException("Centos 5 is not supported");
-    }
-
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.java
deleted file mode 100644
index c5f6f22..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.java
+++ /dev/null
@@ -1,189 +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 brooklyn.entity.messaging.rabbit;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-
-import java.io.IOException;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.test.entity.TestApplication;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.messaging.MessageBroker;
-import brooklyn.entity.messaging.amqp.AmqpExchange;
-import brooklyn.entity.trait.Startable;
-
-import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.rabbitmq.client.Channel;
-import com.rabbitmq.client.Connection;
-import com.rabbitmq.client.ConnectionFactory;
-import com.rabbitmq.client.QueueingConsumer;
-
-/**
- * Test the operation of the {@link RabbitBroker} class.
- * 
- * TODO If you're having problems running this test successfully, here are a few tips:
- * 
- *  - Is `erl` on your path for a non-interactive ssh session?
- *    Look in rabbit's $RUN_DIR/console-err.log (e.g. /tmp/brooklyn-aled/apps/someappid/entities/RabbitBroker_2.8.7_JROYTcSL/console-err.log)
- *    I worked around that by adding to my ~/.brooklyn/brooklyn.properties:
- *      brooklyn.ssh.config.scriptHeader=#!/bin/bash -e\nif [ -f ~/.bashrc ] ; then . ~/.bashrc ; fi\nif [ -f ~/.profile ] ; then . ~/.profile ; fi\necho $PATH > /tmp/mypath.txt
- *    
- *  - Is the hostname resolving properly?
- *    Look in $RUN_DIR/console-out.log; is there a message like:
- *      ERROR: epmd error for host "Aleds-MacBook-Pro": timeout (timed out establishing tcp connection)
- *    I got around that with disabling my wifi and running when not connected to the internet.
- */
-public class RabbitIntegrationTest {
-    private static final Logger log = LoggerFactory.getLogger(RabbitIntegrationTest.class);
-
-    private TestApplication app;
-    private Location testLocation;
-    private RabbitBroker rabbit;
-
-    @BeforeMethod(groups = "Integration")
-    public void setup() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        testLocation = new LocalhostMachineProvisioningLocation();
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void shutdown() {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    /**
-     * Test that the broker starts up and sets SERVICE_UP correctly.
-     */
-    @Test(groups = {"Integration", "WIP"})
-    public void canStartupAndShutdown() throws Exception {
-        rabbit = app.createAndManageChild(EntitySpec.create(RabbitBroker.class));
-        rabbit.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(rabbit, Startable.SERVICE_UP, true);
-        rabbit.stop();
-        assertFalse(rabbit.getAttribute(Startable.SERVICE_UP));
-    }
-
-    /**
-     * Test that an AMQP client can connect to and use the broker.
-     */
-    @Test(groups = {"Integration", "WIP"})
-    public void testClientConnection() throws Exception {
-        rabbit = app.createAndManageChild(EntitySpec.create(RabbitBroker.class));
-        rabbit.start(ImmutableList.of(testLocation));
-        EntityTestUtils.assertAttributeEqualsEventually(rabbit, Startable.SERVICE_UP, true);
-
-        byte[] content = "MessageBody".getBytes(Charsets.UTF_8);
-        String queue = "queueName";
-        Channel producer = null;
-        Channel consumer = null;
-        try {
-            producer = getAmqpChannel(rabbit);
-            consumer = getAmqpChannel(rabbit);
-
-            producer.queueDeclare(queue, true, false, false, ImmutableMap.<String,Object>of());
-            producer.queueBind(queue, AmqpExchange.DIRECT, queue);
-            producer.basicPublish(AmqpExchange.DIRECT, queue, null, content);
-            
-            QueueingConsumer queueConsumer = new QueueingConsumer(consumer);
-            consumer.basicConsume(queue, true, queueConsumer);
-        
-            QueueingConsumer.Delivery delivery = queueConsumer.nextDelivery(60 * 1000l); // one minute timeout
-            assertEquals(delivery.getBody(), content);
-        } finally {
-            closeSafely(producer, 10*1000);
-            closeSafely(consumer, 10*1000);
-        }
-    }
-
-    /**
-     * Closes the channel, guaranteeing the call won't hang this thread forever!
-     * 
-     * Saw this during jenkins testing:
-     * "main" prio=10 tid=0x00007f69c8008000 nid=0x5d70 in Object.wait() [0x00007f69d1318000]
-     *         java.lang.Thread.State: WAITING (on object monitor)
-     *         at java.lang.Object.wait(Native Method)
-     *         - waiting on <0x00000000e0947cf8> (a com.rabbitmq.utility.BlockingValueOrException)
-     *         at java.lang.Object.wait(Object.java:502)
-     *         at com.rabbitmq.utility.BlockingCell.get(BlockingCell.java:50)
-     *         - locked <0x00000000e0947cf8> (a com.rabbitmq.utility.BlockingValueOrException)
-     *         at com.rabbitmq.utility.BlockingCell.get(BlockingCell.java:65)
-     *         - locked <0x00000000e0947cf8> (a com.rabbitmq.utility.BlockingValueOrException)
-     *         at com.rabbitmq.utility.BlockingCell.uninterruptibleGet(BlockingCell.java:111)
-     *         - locked <0x00000000e0947cf8> (a com.rabbitmq.utility.BlockingValueOrException)
-     *         at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:37)
-     *         at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:349)
-     *         at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:543)
-     *         at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:480)
-     *         at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:473)
-     *         at com.rabbitmq.client.Channel$close.call(Unknown Source)
-     *         at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
-     *         at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
-     *         at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
-     *         at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callSafe(AbstractCallSite.java:75)
-     *         at brooklyn.entity.messaging.rabbit.RabbitIntegrationTest.testClientConnection(RabbitIntegrationTest.groovy:107)
-     */
-    private void closeSafely(final Channel channel, int timeoutMs) throws InterruptedException {
-        if (channel == null) return;
-        Thread t = new Thread(new Runnable() {
-                @Override public void run() {
-                    try {
-                        channel.close();
-                    } catch (IOException e) {
-                        log.error("Error closing RabbitMQ Channel; continuing", e);
-                    }
-                }});
-        try {
-            t.start();
-            t.join(timeoutMs);
-            
-            if (t.isAlive()) {
-                log.error("Timeout when closing RabbitMQ Channel "+channel+"; aborting close and continuing");
-            }
-        } finally {
-            t.interrupt();
-            t.join(1*1000);
-            if (t.isAlive()) t.stop();
-        }
-    }
-    
-    private Channel getAmqpChannel(RabbitBroker rabbit) throws Exception {
-        String uri = rabbit.getAttribute(MessageBroker.BROKER_URL);
-        log.warn("connecting to rabbit {}", uri);
-        ConnectionFactory factory = new ConnectionFactory();
-        factory.setUri(uri);
-        Connection conn = factory.newConnection();
-        Channel channel = conn.createChannel();
-        return channel;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/storm/LocalhostLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/LocalhostLiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/storm/LocalhostLiveTest.java
deleted file mode 100644
index 8254dea..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/LocalhostLiveTest.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 brooklyn.entity.messaging.storm;
-
-import org.testng.annotations.Test;
-
-@Test(groups="Live")
-public class LocalhostLiveTest extends StormAbstractCloudLiveTest {
-
-    private static final String NAMED_LOCATION = "localhost";
-
-    public String getLocation() {
-        return NAMED_LOCATION;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/storm/SoftLayerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/SoftLayerLiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/storm/SoftLayerLiveTest.java
deleted file mode 100644
index a6c1a3c..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/SoftLayerLiveTest.java
+++ /dev/null
@@ -1,33 +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 brooklyn.entity.messaging.storm;
-
-import org.testng.annotations.Test;
-
-@Test(groups="Live")
-public class SoftLayerLiveTest extends StormAbstractCloudLiveTest {
-
-    private static final String NAMED_LOCATION = "softlayer";
-
-    @Override
-    public String getLocation() {
-        return NAMED_LOCATION;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
deleted file mode 100644
index d79b2da..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.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 brooklyn.entity.messaging.storm;
-
-import static brooklyn.entity.messaging.storm.Storm.NIMBUS_HOSTNAME;
-import static brooklyn.entity.messaging.storm.Storm.ZOOKEEPER_ENSEMBLE;
-import static brooklyn.entity.messaging.storm.Storm.Role.NIMBUS;
-import static brooklyn.entity.messaging.storm.Storm.Role.SUPERVISOR;
-import static brooklyn.entity.messaging.storm.Storm.Role.UI;
-import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady;
-
-import java.io.File;
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.core.management.internal.LocalManagementContext;
-import org.apache.brooklyn.core.util.ResourceUtils;
-import org.apache.brooklyn.core.util.file.ArchiveBuilder;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import backtype.storm.Config;
-import backtype.storm.StormSubmitter;
-import backtype.storm.generated.AlreadyAliveException;
-import backtype.storm.generated.InvalidTopologyException;
-import backtype.storm.generated.StormTopology;
-import backtype.storm.testing.TestWordSpout;
-import backtype.storm.topology.TopologyBuilder;
-import brooklyn.entity.BrooklynAppLiveTestSupport;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.messaging.storm.topologies.ExclamationBolt;
-import brooklyn.entity.trait.Startable;
-import brooklyn.entity.zookeeper.ZooKeeperEnsemble;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.os.Os;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-
-public abstract class StormAbstractCloudLiveTest extends BrooklynAppLiveTestSupport {
-
-    protected static final Logger log = LoggerFactory
-            .getLogger(StormAbstractCloudLiveTest.class);
-    private Location location;
-    private ZooKeeperEnsemble zooKeeperEnsemble;
-    private Storm nimbus;
-    private Storm supervisor;
-    private Storm ui;
-
-    @BeforeClass(alwaysRun = true)
-    public void beforeClass() throws Exception {
-        mgmt = new LocalManagementContext();
-        location = mgmt.getLocationRegistry()
-                .resolve(getLocation(), getFlags());
-        super.setUp();
-    }
-
-    @AfterClass(alwaysRun = true)
-    public void afterClass() throws Exception {
-        // Entities.destroyAll(mgmt);
-    }
-
-    public abstract String getLocation();
-
-    public Map<String, ?> getFlags() {
-        return MutableMap.of();
-    }
-
-    @Test(groups = {"Live","WIP"})  // needs repair to avoid hard dependency on Andrea's environment
-    public void deployStorm() throws Exception {
-        try {
-            zooKeeperEnsemble = app.createAndManageChild(EntitySpec.create(
-                    ZooKeeperEnsemble.class).configure(
-                    ZooKeeperEnsemble.INITIAL_SIZE, 3));
-            nimbus = app.createAndManageChild(EntitySpec
-                    .create(Storm.class)
-                    .configure(Storm.ROLE, NIMBUS)
-                    .configure(NIMBUS_HOSTNAME, "localhost")
-                    .configure(ZOOKEEPER_ENSEMBLE, zooKeeperEnsemble)
-                    );
-            supervisor = app.createAndManageChild(EntitySpec
-                    .create(Storm.class)
-                    .configure(Storm.ROLE, SUPERVISOR)
-                    .configure(ZOOKEEPER_ENSEMBLE, zooKeeperEnsemble)
-                    .configure(NIMBUS_HOSTNAME,
-                            attributeWhenReady(nimbus, Attributes.HOSTNAME)));
-            ui = app.createAndManageChild(EntitySpec
-                    .create(Storm.class)
-                    .configure(Storm.ROLE, UI)
-                    .configure(ZOOKEEPER_ENSEMBLE, zooKeeperEnsemble)
-                    .configure(NIMBUS_HOSTNAME,
-                            attributeWhenReady(nimbus, Attributes.HOSTNAME)));
-            log.info("Started Storm deployment on '" + getLocation() + "'");
-            app.start(ImmutableList.of(location));
-            Entities.dumpInfo(app);
-            EntityTestUtils.assertAttributeEqualsEventually(app, Startable.SERVICE_UP, true);
-            EntityTestUtils.assertAttributeEqualsEventually(zooKeeperEnsemble, Startable.SERVICE_UP, true);
-            EntityTestUtils.assertAttributeEqualsEventually(nimbus, Startable.SERVICE_UP, true);
-            EntityTestUtils.assertAttributeEqualsEventually(supervisor, Startable.SERVICE_UP, true);
-            EntityTestUtils.assertAttributeEqualsEventually(ui, Startable.SERVICE_UP, true);
-            
-            StormTopology stormTopology = createTopology();
-            submitTopology(stormTopology, "myExclamation", 3, true, 60000);
-        } catch (Exception e) {
-            log.error("Failed to deploy Storm", e);
-            Assert.fail();
-            throw e;
-        }
-    }
-
-    private StormTopology createTopology()
-            throws AlreadyAliveException, InvalidTopologyException {
-        TopologyBuilder builder = new TopologyBuilder();
-
-        builder.setSpout("word", new TestWordSpout(), 10);
-        builder.setBolt("exclaim1", new ExclamationBolt(), 3).shuffleGrouping("word");
-        builder.setBolt("exclaim2", new ExclamationBolt(), 2).shuffleGrouping("exclaim1");
-        
-        return builder.createTopology();
-    }
-
-    public boolean submitTopology(StormTopology stormTopology, String topologyName, int numOfWorkers, boolean debug, long timeoutMs) {
-        if (log.isDebugEnabled()) log.debug("Connecting to NimbusClient: {}", nimbus.getConfig(Storm.NIMBUS_HOSTNAME));
-        Config conf = new Config();
-        conf.setDebug(debug);
-        conf.setNumWorkers(numOfWorkers);
-
-        // TODO - confirm this creats the JAR correctly
-        String jar = createJar(
-            new File(Os.mergePaths(ResourceUtils.create(this).getClassLoaderDir(), "brooklyn/entity/messaging/storm/topologies")),
-            "brooklyn/entity/messaging/storm/");
-        System.setProperty("storm.jar", jar);
-        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) Time.sleep(Duration.ONE_SECOND);
-            if (log.isTraceEnabled()) log.trace("trying connection to {} at time {}", nimbus.getConfig(Storm.NIMBUS_HOSTNAME), currentTime);
-
-            try {
-                StormSubmitter.submitTopology(topologyName, conf, stormTopology);
-                return true;
-            } catch (Exception e) {
-                if (shouldRetryOn(e)) {
-                    if (log.isDebugEnabled()) log.debug("Attempt {} failed connecting to {} ({})", new Object[] {attempt + 1, nimbus.getConfig(Storm.NIMBUS_HOSTNAME), e.getMessage()});
-                    lastError = e;
-                } else {
-                    throw Throwables.propagate(e);
-                }
-            }
-            attempt++;
-        }
-        log.warn("unable to connect to Nimbus client: ", lastError);
-        Assert.fail();
-        return false;
-    }
-    
-    private boolean shouldRetryOn(Exception e) {
-        if (e.getMessage().equals("org.apache.thrift7.transport.TTransportException: java.net.ConnectException: Connection refused"))  return true;
-        return false;
-    }
-    
-    private String createJar(File dir, String parentDirInJar) {
-        if (dir.isDirectory()) {
-            File jarFile = ArchiveBuilder.jar().addAt(dir, parentDirInJar).create(Os.newTempDir(getClass())+"/topologies.jar");
-            return jarFile.getAbsolutePath();
-        } else {
-            return dir.getAbsolutePath(); // An existing Jar archive?
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormEc2LiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormEc2LiveTest.java
deleted file mode 100644
index d949450..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormEc2LiveTest.java
+++ /dev/null
@@ -1,58 +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 brooklyn.entity.messaging.storm;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.trait.Startable;
-import brooklyn.entity.zookeeper.ZooKeeperNode;
-
-import com.google.common.collect.ImmutableList;
-
-public class StormEc2LiveTest extends AbstractEc2LiveTest {
-
-    /**
-     * Test that can install, start and use a Storm cluster: 1 nimbus, 1 zookeeper, 1 supervisor (worker node).
-     */
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        ZooKeeperNode zookeeper = app.createAndManageChild(EntitySpec.create(ZooKeeperNode.class));
-        Storm nimbus = app.createAndManageChild(EntitySpec.create(Storm.class).configure("storm.role",
-                Storm.Role.NIMBUS));
-        Storm supervisor = app.createAndManageChild(EntitySpec.create(Storm.class).configure("storm.role",
-                Storm.Role.SUPERVISOR));
-        Storm ui = app.createAndManageChild(EntitySpec.create(Storm.class).configure("storm.role",
-                Storm.Role.UI));        
-        app.start(ImmutableList.of(loc));
-        Entities.dumpInfo(app);
-        
-        EntityTestUtils.assertAttributeEqualsEventually(zookeeper, Startable.SERVICE_UP, true);
-        EntityTestUtils.assertAttributeEqualsEventually(nimbus, Startable.SERVICE_UP, true);
-        EntityTestUtils.assertAttributeEqualsEventually(supervisor, Startable.SERVICE_UP, true);
-        EntityTestUtils.assertAttributeEqualsEventually(ui, Startable.SERVICE_UP, true);
-    }
-
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormGceLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormGceLiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormGceLiveTest.java
deleted file mode 100644
index 1504a56..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormGceLiveTest.java
+++ /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 brooklyn.entity.messaging.storm;
-
-import java.util.Map;
-
-import org.testng.annotations.Test;
-
-import brooklyn.util.collections.MutableMap;
-
-@Test(groups="Live")
-public class StormGceLiveTest extends StormAbstractCloudLiveTest {
-
-    private static final String NAMED_LOCATION = "gce-europe-west1";
-    private static final String LOCATION_ID = "gce-europe-west1-a";
-    private static final String URI = "https://www.googleapis.com/compute/v1beta15/projects/google/global/images/centos-6-v20130325";
-    private static final String IMAGE_ID = "centos-6-v20130325";
-
-    @Override
-    public String getLocation() {
-        return NAMED_LOCATION;
-    }
-
-    @Override
-    public Map<String, ?> getFlags() {
-        return MutableMap.of(
-                "locationId", LOCATION_ID,
-                "imageId", IMAGE_ID,
-                "uri", URI + IMAGE_ID,
-                "groupId", "storm-test",
-                "stopIptables", "true"
-        );
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/storm/topologies/ExclamationBolt.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/topologies/ExclamationBolt.java b/software/messaging/src/test/java/brooklyn/entity/messaging/storm/topologies/ExclamationBolt.java
deleted file mode 100644
index d7f1d9e..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/topologies/ExclamationBolt.java
+++ /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 brooklyn.entity.messaging.storm.topologies;
-
-import java.util.Map;
-
-import backtype.storm.task.OutputCollector;
-import backtype.storm.task.TopologyContext;
-import backtype.storm.topology.IRichBolt;
-import backtype.storm.topology.OutputFieldsDeclarer;
-import backtype.storm.topology.base.BaseRichBolt;
-import backtype.storm.tuple.Fields;
-import backtype.storm.tuple.Tuple;
-import backtype.storm.tuple.Values;
-
-public class ExclamationBolt extends BaseRichBolt {
-    OutputCollector _collector;
-
-    @Override
-    public void prepare(Map conf, TopologyContext context,
-            OutputCollector collector) {
-        _collector = collector;
-    }
-
-    @Override
-    public void execute(Tuple tuple) {
-        _collector.emit(tuple, new Values(tuple.getString(0) + "!!!"));
-        _collector.ack(tuple);
-    }
-
-    @Override
-    public void declareOutputFields(OutputFieldsDeclarer declarer) {
-        declarer.declare(new Fields("word"));
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/zookeeper/ZooKeeperEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/zookeeper/ZooKeeperEc2LiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/zookeeper/ZooKeeperEc2LiveTest.java
deleted file mode 100644
index a6c7d2b..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/zookeeper/ZooKeeperEc2LiveTest.java
+++ /dev/null
@@ -1,48 +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 brooklyn.entity.messaging.zookeeper;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.trait.Startable;
-import brooklyn.entity.zookeeper.ZooKeeperNode;
-
-import com.google.common.collect.ImmutableList;
-
-public class ZooKeeperEc2LiveTest extends AbstractEc2LiveTest {
-
-    /**
-     * Test that can install, start and use a Zookeeper instance.
-     */
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        ZooKeeperNode zookeeper = app.createAndManageChild(EntitySpec.create(ZooKeeperNode.class).configure("jmxPort", "31001+"));
-        app.start(ImmutableList.of(loc));
-        Entities.dumpInfo(zookeeper);
-        EntityTestUtils.assertAttributeEqualsEventually(zookeeper, Startable.SERVICE_UP, true);
-    }
-    
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/zookeeper/ZooKeeperEnsembleLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/zookeeper/ZooKeeperEnsembleLiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/zookeeper/ZooKeeperEnsembleLiveTest.java
deleted file mode 100644
index cb21c18..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/zookeeper/ZooKeeperEnsembleLiveTest.java
+++ /dev/null
@@ -1,127 +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 brooklyn.entity.messaging.zookeeper;
-
-import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.trait.Startable;
-import brooklyn.entity.zookeeper.ZooKeeperEnsemble;
-import brooklyn.entity.zookeeper.ZooKeeperNode;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-import com.google.common.util.concurrent.Uninterruptibles;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.test.entity.TestApplication;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import java.net.Socket;
-import java.util.concurrent.TimeUnit;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-/**
- * A live test of the {@link brooklyn.entity.zookeeper.ZooKeeperEnsemble} entity.
- *
- * Tests that a 3 node cluster can be started on Amazon EC2 and data written on one {@link brooklyn.entity.zookeeper.ZooKeeperEnsemble}
- * can be read from another, using the Astyanax API.
- */
-public class ZooKeeperEnsembleLiveTest {
-
-    private static final Logger log = LoggerFactory.getLogger(ZooKeeperEnsembleLiveTest.class);
-    
-    private String provider = 
-            "gce-europe-west1";
-//            "aws-ec2:eu-west-1";
-//            "named:hpcloud-compute-at";
-//            "localhost";
-
-    protected TestApplication app;
-    protected Location testLocation;
-    protected ZooKeeperEnsemble cluster;
-
-    @BeforeMethod(alwaysRun = true)
-    public void setup() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-        testLocation = app.getManagementContext().getLocationRegistry().resolve(provider);
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void shutdown() {
-        Entities.destroyAll(app.getManagementContext());
-    }
-
-    /**
-     * Test that a two node cluster starts up and allows access through both nodes.
-     */
-    @Test(groups = "Live")
-    public void testStartUpConnectAndResize() throws Exception {
-        try {
-            cluster = app.createAndManageChild(EntitySpec.create(ZooKeeperEnsemble.class)
-                    .configure("initialSize", 3)
-                    .configure("clusterName", "ZooKeeperEnsembleLiveTest"));
-            assertEquals(cluster.getCurrentSize().intValue(), 0);
-
-            app.start(ImmutableList.of(testLocation));
-
-            EntityTestUtils.assertAttributeEqualsEventually(cluster, ZooKeeperEnsemble.GROUP_SIZE, 3);
-            Entities.dumpInfo(app);
-
-            EntityTestUtils.assertAttributeEqualsEventually(cluster, Startable.SERVICE_UP, true);
-            for(Entity zkNode : cluster.getMembers()) {
-                assertTrue(isSocketOpen((ZooKeeperNode) zkNode));
-            }
-            cluster.resize(1);
-            EntityTestUtils.assertAttributeEqualsEventually(cluster, ZooKeeperEnsemble.GROUP_SIZE, 1);
-            Entities.dumpInfo(app);
-            EntityTestUtils.assertAttributeEqualsEventually(cluster, Startable.SERVICE_UP, true);
-            for (Entity zkNode : cluster.getMembers()) {
-                assertTrue(isSocketOpen((ZooKeeperNode) zkNode));
-            }
-        } catch (Throwable e) {
-            throw Throwables.propagate(e);
-        }
-    }
-
-    protected static boolean isSocketOpen(ZooKeeperNode node) {
-        int attempt = 0, maxAttempts = 20;
-        while(attempt < maxAttempts) {
-            try {
-                Socket s = new Socket(node.getAttribute(Attributes.HOSTNAME), node.getZookeeperPort());
-                s.close();
-                return true;
-            } catch (Exception e) {
-                attempt++;
-            }
-            Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
-        }
-        return false;
-    }
-    
-}


[55/64] incubator-brooklyn git commit: brooklyn-software-database: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/crate/crate.yaml
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/crate/crate.yaml b/software/database/src/main/resources/org/apache/brooklyn/entity/database/crate/crate.yaml
new file mode 100644
index 0000000..42fcee5
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/crate/crate.yaml
@@ -0,0 +1,28 @@
+# The Crate distribution comes with comprehensive instructions on available
+# configuration. Select sections are reproduced here.
+
+
+############################## Network And HTTP ###############################
+
+# Crate, by default, binds itself to the 0.0.0.0 address, and listens
+# on port [4200-4300] for HTTP traffic and on port [4300-4400] for node-to-node
+# communication. (the range means that if the port is busy, it will automatically
+# try the next port).
+
+# Set both 'bind_host' and 'publish_host':
+network.host: ${driver.subnetHostname}
+
+# Set a custom port for the node to node communication (4300 by default):
+transport.tcp.port: ${entity.port?c}
+
+# Set a custom port to listen for HTTP traffic:
+http.port: ${entity.httpPort?c}
+
+
+#################################### Paths ####################################
+
+# Path to directory where to store table data allocated for this node.
+path.data: ${driver.dataLocation}
+
+# Path to log files:
+path.logs: ${driver.runDir}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mariadb/my.cnf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mariadb/my.cnf b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mariadb/my.cnf
new file mode 100644
index 0000000..d78f88e
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mariadb/my.cnf
@@ -0,0 +1,19 @@
+[client]
+port            = ${driver.port?c}
+socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
+user            = root
+password        = ${entity.password}
+
+# Here follows entries for some specific programs
+
+# The MariaDB server, which (confusingly) uses MySQL terminology for backwards compatibility
+[mysqld]
+port            = ${driver.port?c}
+socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
+basedir         = ${driver.baseDir}
+datadir         = ${driver.dataDir}
+bind-address    = 0.0.0.0
+# skip-networking
+
+# Custom configuration options
+${driver.mariaDbServerOptionsString}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/ConfigurationFile.ini
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/ConfigurationFile.ini b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/ConfigurationFile.ini
new file mode 100644
index 0000000..ee437ac
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/ConfigurationFile.ini
@@ -0,0 +1,390 @@
+;SQL Server 2012 Configuration File
+
+
+[OPTIONS]
+
+
+
+; Specifies a Setup work flow, like INSTALL, UNINSTALL, or UPGRADE. This is a required parameter. 
+
+
+
+ACTION="Install"
+
+; Detailed help for command line argument ROLE has not been defined yet.
+
+ROLE="AllFeatures_WithDefaults"
+
+
+; Detailed help for command line argument ENU has not been defined yet. 
+
+
+
+ENU="True"
+
+
+
+; Setup will not display any user interface. 
+
+
+
+QUIET="True"
+
+ 
+
+; Setup will display progress only, without any user interaction. 
+
+
+
+QUIETSIMPLE="False"
+
+
+
+; Specify whether SQL Server Setup should discover and include product updates. The valid values are True and False or 1 and 0. By default SQL Server Setup will include updates that are found. 
+
+
+
+UpdateEnabled="False"
+
+
+
+; Specifies features to install, uninstall, or upgrade. The list of top-level features include SQL, AS, RS, IS, MDS, and Tools. The SQL feature will install the Database Engine, Replication, Full-Text, and Data Quality Services (DQS) server. The Tools feature will install Management Tools, Books online components, SQL Server Data Tools, and other shared components. 
+
+
+
+FEATURES="${config['mssql.features']}"
+
+
+
+; Specify the location where SQL Server Setup will obtain product updates. The valid values are "MU" to search Microsoft Update, a valid folder path, a relative path such as .\MyUpdates or a UNC share. By default SQL Server Setup will search Microsoft Update or a Windows Update service through the Window Server Update Services. 
+
+
+
+UpdateSource="MU"
+
+
+
+; Displays the command line parameters usage 
+
+
+
+HELP="False"
+
+
+
+; Specifies that the detailed Setup log should be piped to the console. 
+
+
+
+INDICATEPROGRESS="True"
+
+
+
+; Specifies that Setup should install into WOW64. This command line argument is not supported on an IA64 or a 32-bit system. 
+
+
+
+X86="False"
+
+
+
+; Specify the root installation directory for shared components.  This directory remains unchanged after shared components are already installed. 
+
+
+
+INSTALLSHAREDDIR="C:\Program Files\Microsoft SQL Server"
+
+
+
+; Specify the root installation directory for the WOW64 shared components.  This directory remains unchanged after WOW64 shared components are already installed. 
+
+
+
+INSTALLSHAREDWOWDIR="C:\Program Files (x86)\Microsoft SQL Server"
+
+
+
+; Specify a default or named instance. MSSQLSERVER is the default instance for non-Express editions and SQLExpress for Express editions. This parameter is required when installing the SQL Server Database Engine (SQL), Analysis Services (AS), or Reporting Services (RS). 
+
+
+
+INSTANCENAME="MSSQLSERVER"
+
+
+
+; Specify the Instance ID for the SQL Server features you have specified. SQL Server directory structure, registry structure, and service names will incorporate the instance ID of the SQL Server instance. 
+
+
+
+INSTANCEID="MSSQLSERVER"
+
+
+
+; Specify that SQL Server feature usage data can be collected and sent to Microsoft. Specify 1 or True to enable and 0 or False to disable this feature. 
+
+
+
+SQMREPORTING="False"
+
+
+; The account used by the Distributed Replay Controller service.
+
+CTLRSVCACCOUNT="NT Service\SQL Server Distributed Replay Controller"
+
+; The startup type for the Distributed Replay Controller service.
+
+CTLRSTARTUPTYPE="Manual"
+
+; The account used by the Distributed Replay Client service.
+
+CLTSVCACCOUNT="NT Service\SQL Server Distributed Replay Client"
+
+; The startup type for the Distributed Replay Client service.
+
+CLTSTARTUPTYPE="Manual"
+
+; The result directory for the Distributed Replay Client service.
+
+CLTRESULTDIR="C:\Program Files (x86)\Microsoft SQL Server\DReplayClient\ResultDir"
+
+; The working directory for the Distributed Replay Client service.
+
+CLTWORKINGDIR="C:\Program Files (x86)\Microsoft SQL Server\DReplayClient\WorkingDir"
+
+; RSInputSettings_RSInstallMode_Description
+
+RSINSTALLMODE="DefaultNativeMode"
+
+; RSInputSettings_RSInstallMode_Description
+
+RSSHPINSTALLMODE="SharePointFilesOnlyMode"
+
+; Specify if errors can be reported to Microsoft to improve future SQL Server releases. Specify 1 or True to enable and 0 or False to disable this feature.
+
+
+
+; Specify if errors can be reported to Microsoft to improve future SQL Server releases. Specify 1 or True to enable and 0 or False to disable this feature. 
+
+
+
+ERRORREPORTING="False"
+
+
+
+; Specify the installation directory. 
+
+
+
+INSTANCEDIR="C:\Program Files\Microsoft SQL Server"
+
+
+
+; Agent account name 
+
+
+
+AGTSVCACCOUNT="NT Service\SQLSERVERAGENT"
+
+
+
+; Auto-start service after installation.  
+
+
+
+AGTSVCSTARTUPTYPE="Automatic"
+
+
+; Startup type for Integration Services.
+
+ISSVCSTARTUPTYPE="Automatic"
+
+; Account for Integration Services: Domain\User or system account.
+
+ISSVCACCOUNT="NT Service\MsDtsServer110"
+
+; The name of the account that the Analysis Services service runs under.
+
+ASSVCACCOUNT="NT Service\MSSQLServerOLAPService"
+
+; Controls the service startup type setting after the service has been created.
+
+ASSVCSTARTUPTYPE="Automatic"
+
+; The collation to be used by Analysis Services.
+
+ASCOLLATION="Latin1_General_CI_AS"
+
+; The location for the Analysis Services data files.
+
+ASDATADIR="C:\Program Files\Microsoft SQL Server\MSAS11.MSSQLSERVER\OLAP\Data"
+
+; The location for the Analysis Services log files.
+
+ASLOGDIR="C:\Program Files\Microsoft SQL Server\MSAS11.MSSQLSERVER\OLAP\Log"
+
+; The location for the Analysis Services backup files.
+
+ASBACKUPDIR="C:\Program Files\Microsoft SQL Server\MSAS11.MSSQLSERVER\OLAP\Backup"
+
+; The location for the Analysis Services temporary files.
+
+ASTEMPDIR="C:\Program Files\Microsoft SQL Server\MSAS11.MSSQLSERVER\OLAP\Temp"
+
+; The location for the Analysis Services configuration files.
+
+ASCONFIGDIR="C:\Program Files\Microsoft SQL Server\MSAS11.MSSQLSERVER\OLAP\Config"
+
+; Specifies whether or not the MSOLAP provider is allowed to run in process.
+
+ASPROVIDERMSOLAP="1"
+
+; Specifies the list of administrator accounts that need to be provisioned.
+
+ASSYSADMINACCOUNTS="BUILTIN\Administrators"
+
+; Specifies the server mode of the Analysis Services instance. Valid values are MULTIDIMENSIONAL and TABULAR. The default value is MULTIDIMENSIONAL.
+
+ASSERVERMODE="MULTIDIMENSIONAL"
+
+; CM brick TCP communication port 
+
+
+
+COMMFABRICPORT="0"
+
+
+
+; How matrix will use private networks 
+
+
+
+COMMFABRICNETWORKLEVEL="0"
+
+
+
+; How inter brick communication will be protected 
+
+
+
+COMMFABRICENCRYPTION="0"
+
+
+
+; TCP port used by the CM brick 
+
+
+
+MATRIXCMBRICKCOMMPORT="0"
+
+
+
+; Startup type for the SQL Server service. 
+
+
+
+SQLSVCSTARTUPTYPE="Automatic"
+
+
+
+; Level to enable FILESTREAM feature at (0, 1, 2 or 3). 
+
+
+
+FILESTREAMLEVEL="0"
+
+
+
+; Set to "1" to enable RANU for SQL Server Express. 
+
+
+
+ENABLERANU="False"
+
+
+
+; Specifies a Windows collation or an SQL collation to use for the Database Engine. 
+
+
+
+SQLCOLLATION="SQL_Latin1_General_CP1_CI_AS"
+
+
+
+; Account for SQL Server service: Domain\User or system account. 
+
+
+
+SQLSVCACCOUNT="NT Service\MSSQLSERVER"
+
+
+
+; Windows account(s) to provision as SQL Server system administrators. 
+
+
+
+SQLSYSADMINACCOUNTS="BUILTIN\Administrators"
+
+
+
+; The default is Windows Authentication. Use "SQL" for Mixed Mode Authentication. 
+
+
+
+SECURITYMODE="SQL"
+
+
+SAPWD="${config['mssql.sa.password']}"
+
+
+
+; Provision current user as a Database Engine system administrator for SQL Server 2012 Express. 
+
+
+
+ADDCURRENTUSERASSQLADMIN="False"
+
+
+
+; Specify 0 to disable or 1 to enable the TCP/IP protocol. 
+
+
+
+TCPENABLED="1"
+
+
+
+; Specify 0 to disable or 1 to enable the Named Pipes protocol. 
+
+
+
+NPENABLED="0"
+
+
+
+; Startup type for Browser Service. 
+
+
+
+BROWSERSVCSTARTUPTYPE="Disabled"
+
+
+; Specifies which account the report server NT service should execute under.  When omitted or when the value is empty string, the default built-in account for the current operating system.
+; The username part of RSSVCACCOUNT is a maximum of 20 characters long and
+; The domain part of RSSVCACCOUNT is a maximum of 254 characters long.
+
+RSSVCACCOUNT="NT Service\ReportServer"
+
+; Specifies how the startup mode of the report server NT service.  When
+; Manual - Service startup is manual mode (default).
+; Automatic - Service startup is automatic mode.
+; Disabled - Service is disabled
+
+RSSVCSTARTUPTYPE="Automatic"
+
+; Add description of input argument FTSVCACCOUNT
+
+FTSVCACCOUNT="NT Service\MSSQLFDLauncher"
+
+
+
+IAcceptSQLServerLicenseTerms="True"

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/checkrunningmssql.bat
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/checkrunningmssql.bat b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/checkrunningmssql.bat
new file mode 100644
index 0000000..34512c8
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/checkrunningmssql.bat
@@ -0,0 +1,23 @@
+[#ftl]
+@echo off
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements.  See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership.  The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License.  You may obtain a copy of the License at
+REM
+REM   http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied.  See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+set serviceName=MSSQL\$${config['mssql.instance.name']}
+
+[#noparse]
+sc query %serviceName% | find "RUNNING"

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/configuremssql.ps1
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/configuremssql.ps1 b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/configuremssql.ps1
new file mode 100644
index 0000000..06522fd
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/configuremssql.ps1
@@ -0,0 +1,22 @@
+[#ftl]
+#!ps1
+#
+# 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.
+#
+netsh advfirewall firewall add rule name=SQLPort dir=in protocol=tcp action=allow localport=1433 remoteip=any profile=any
+( Get-WmiObject -Namespace "root\Microsoft\SqlServer\ComputerManagement11" -Query "Select * from ServerNetworkProtocolProperty where ProtocolName='Tcp' and IPAddressName='IPAll' and PropertyName='TcpPort'" ).SetStringValue("1433")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/installmssql.ps1
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/installmssql.ps1 b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/installmssql.ps1
new file mode 100644
index 0000000..6c1f30b
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/installmssql.ps1
@@ -0,0 +1,49 @@
+[#ftl]
+#!ps1
+#
+# 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.
+#
+
+$Url = "${config['mssql.download.url']}"
+$Path = "C:\sql2008.iso"
+$Username = "${config['mssql.download.user']}"
+$Password = '${config['mssql.download.password']}'
+
+
+$WebClient = New-Object System.Net.WebClient
+$WebClient.Credentials = New-Object System.Net.Networkcredential($Username, $Password)
+$WebClient.DownloadFile( $url, $path )
+
+$mountResult = Mount-DiskImage $Path -PassThru
+$driveLetter = (($mountResult | Get-Volume).DriveLetter) + ":\"
+
+New-Item -ItemType Directory -Force -Path "C:\Program Files (x86)\Microsoft SQL Server\DReplayClient\ResultDir"
+New-Item -ItemType Directory -Force -Path "C:\Program Files (x86)\Microsoft SQL Server\DReplayClient\WorkingDir"
+
+Install-WindowsFeature NET-Framework-Core
+
+$pass = '${attribute['windows.password']}'
+$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
+$mycreds = New-Object System.Management.Automation.PSCredential ($($env:COMPUTERNAME + "\Administrator"), $secpasswd)
+
+Invoke-Command -ComputerName localhost -credential $mycreds -scriptblock {
+    param($driveLetter)
+    Start-Process ( $driveLetter + "setup.exe") -ArgumentList "/ConfigurationFile=C:\ConfigurationFile.ini" -RedirectStandardOutput "C:\sqlout.txt" -RedirectStandardError "C:\sqlerr.txt" -Wait
+} -Authentication CredSSP -argumentlist $driveLetter
+
+## Process complete
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/launchmssql.bat
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/launchmssql.bat b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/launchmssql.bat
new file mode 100644
index 0000000..ad0deff
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/launchmssql.bat
@@ -0,0 +1,25 @@
+[#ftl]
+@echo off
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements.  See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership.  The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License.  You may obtain a copy of the License at
+REM
+REM   http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied.  See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+set serviceName=MSSQL\$${config['mssql.instance.name']}
+
+[#noparse]
+sc stop %serviceName%
+sc config %serviceName% start=auto
+sc start %serviceName%

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/mssql.yaml
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/mssql.yaml b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/mssql.yaml
new file mode 100644
index 0000000..413ec3d
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/mssql.yaml
@@ -0,0 +1,40 @@
+name: mssql
+
+location:
+  jclouds:aws-ec2:us-west-2:
+    displayName: AWS Oregon (Windows)
+    imageId: us-west-2/ami-8fd3f9bf
+    hardwareId:  m3.medium
+    useJcloudsSshInit: false
+    templateOptions:
+      subnetId: subnet-a10e96c4
+      securityGroupIds: [['sg-a2d0c2c7']]
+      mapNewVolumeToDeviceName: ["/dev/sda1", 100, true]
+
+services:
+- type: brooklyn.entity.basic.VanillaWindowsProcess
+  brooklyn.config:
+    templates.install:
+      classpath://org/apache/brooklyn/entity/database/mssql/ConfigurationFile.ini: "C:\\ConfigurationFile.ini"
+      classpath://org/apache/brooklyn/entity/database/mssql/installmssql.ps1: "C:\\installmssql.ps1"
+      classpath://org/apache/brooklyn/entity/database/mssql/configuremssql.ps1: "C:\\configuremssql.ps1"
+      classpath://org/apache/brooklyn/entity/database/mssql/launchmssql.bat: "C:\\launchmssql.bat"
+      classpath://org/apache/brooklyn/entity/database/mssql/stopmssql.bat: "C:\\stopmssql.bat"
+    install.command: powershell -command "C:\\installmssql.ps1"
+    customize.command: powershell -command "C:\\configuremssql.ps1"
+    launch.command: "C:\\launchmssql.bat"
+    stop.command: "C:\\stopmssql.bat"
+    checkRunning.command: echo true
+
+    ## NOTE: Values must be supplied for the following
+    mssql.download.url:
+    mssql.download.user:
+    mssql.download.password:
+    mssql.sa.password:
+    mssql.instance.name:
+
+    ## The following is a list of *all* MSSQL features. Installation time and footprint can be greatly
+    ## reduced by removing unnecessary features
+    mssql.features: "SQLENGINE,REPLICATION,FULLTEXT,DQ,AS,RS,RS_SHP,DQC,BIDS,CONN,IS,BC,SDK,BOL,SSMS,ADV_SSMS,DREPLAY_CTLR,DREPLAY_CLT,SNAC_SDK"
+  provisioning.properties:
+    required.ports: 1433
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/stopmssql.bat
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/stopmssql.bat b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/stopmssql.bat
new file mode 100644
index 0000000..68358f1
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/stopmssql.bat
@@ -0,0 +1,24 @@
+[#ftl]
+@echo off
+REM Licensed to the Apache Software Foundation (ASF) under one
+REM or more contributor license agreements.  See the NOTICE file
+REM distributed with this work for additional information
+REM regarding copyright ownership.  The ASF licenses this file
+REM to you under the Apache License, Version 2.0 (the
+REM "License"); you may not use this file except in compliance
+REM with the License.  You may obtain a copy of the License at
+REM
+REM   http://www.apache.org/licenses/LICENSE-2.0
+REM
+REM Unless required by applicable law or agreed to in writing,
+REM software distributed under the License is distributed on an
+REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+REM KIND, either express or implied.  See the License for the
+REM specific language governing permissions and limitations
+REM under the License.
+
+set serviceName=MSSQL\$${config['mssql.instance.name']}
+
+[#noparse]
+sc config %serviceName% start=demand
+sc stop %serviceName%

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql.conf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql.conf b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql.conf
new file mode 100644
index 0000000..85f55ab
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql.conf
@@ -0,0 +1,19 @@
+[client]
+port            = ${driver.port?c}
+socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
+user            = root
+password        = ${entity.password}
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port            = ${driver.port?c}
+socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
+basedir         = ${driver.baseDir}
+datadir         = ${driver.dataDir}
+bind-address    = 0.0.0.0
+# skip-networking
+
+# Custom configuration options
+${driver.mySqlServerOptionsString}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql_master.conf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql_master.conf b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql_master.conf
new file mode 100644
index 0000000..791f2da
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql_master.conf
@@ -0,0 +1,26 @@
+[client]
+port            = ${driver.port?c}
+socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
+user            = root
+password        = ${entity.password}
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port            = ${driver.port?c}
+socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
+basedir         = ${driver.baseDir}
+datadir         = ${driver.dataDir}
+bind-address    = 0.0.0.0
+# skip-networking
+
+# Replication config
+server-id       = 1
+binlog-format   = mixed
+log-bin         = mysql-bin
+sync_binlog     = 1
+innodb_flush_log_at_trx_commit=1
+
+# Custom configuration options
+${driver.mySqlServerOptionsString}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql_slave.conf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql_slave.conf b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql_slave.conf
new file mode 100644
index 0000000..2e1e945
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql_slave.conf
@@ -0,0 +1,33 @@
+[#ftl]
+[client]
+port            = ${driver.port?c}
+socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
+user            = root
+password        = ${entity.password}
+
+# Here follows entries for some specific programs
+
+# The MySQL server
+[mysqld]
+port            = ${driver.port?c}
+socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
+basedir         = ${driver.baseDir}
+datadir         = ${driver.dataDir}
+bind-address    = 0.0.0.0
+# skip-networking
+
+# Replication config
+server-id       = ${config["mysql.server_id"]}
+relay-log       = mysql-slave-${config["mysql.server_id"]}-relay
+relay-log-recovery = 1
+relay-log-info-repository = TABLE
+relay-log-purge = 1
+[#if !config["mysql.slave.replicate_do_db"]??            ]#[/#if]replicate-do-db             = ${config["mysql.slave.replicate_do_db"]!}
+[#if !config["mysql.slave.replicate_ignore_db"]??        ]#[/#if]replicate-ignore-db         = ${config["mysql.slave.replicate_ignore_db"]!}
+[#if !config["mysql.slave.replicate_do_table"]??         ]#[/#if]replicate-do-table          = ${config["mysql.slave.replicate_do_table"]!}
+[#if !config["mysql.slave.replicate_ignore_table"]??     ]#[/#if]replicate-ignore-table      = ${config["mysql.slave.replicate_ignore_table"]!}
+[#if !config["mysql.slave.replicate_wild_do_table"]??    ]#[/#if]replicate-wild-do-table     = ${config["mysql.slave.replicate_wild_do_table"]!}
+[#if !config["mysql.slave.replicate_wild_ignore_table"]??]#[/#if]replicate-wild-ignore-table = ${config["mysql.slave.replicate_wild_ignore_table"]!}
+
+# Custom configuration options
+${driver.mySqlServerOptionsString}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/postgresql/postgresql.conf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/postgresql/postgresql.conf b/software/database/src/main/resources/org/apache/brooklyn/entity/database/postgresql/postgresql.conf
new file mode 100644
index 0000000..b6234c9
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/postgresql/postgresql.conf
@@ -0,0 +1,513 @@
+[#ftl]
+#
+
+# -----------------------------
+# PostgreSQL configuration file
+# -----------------------------
+#
+# This file consists of lines of the form:
+#
+#   name = value
+#
+# (The "=" is optional.)  Whitespace may be used.  Comments are introduced with
+# "#" anywhere on a line.  The complete list of parameter names and allowed
+# values can be found in the PostgreSQL documentation.
+#
+# The commented-out settings shown in this file represent the default values.
+# Re-commenting a setting is NOT sufficient to revert it to the default value;
+# you need to reload the server.
+#
+# This file is read on server startup and when the server receives a SIGHUP
+# signal.  If you edit the file on a running system, you have to SIGHUP the
+# server for the changes to take effect, or use "pg_ctl reload".  Some
+# parameters, which are marked below, require a server shutdown and restart to
+# take effect.
+#
+# Any parameter can also be given as a command-line option to the server, e.g.,
+# "postgres -c log_connections=on".  Some parameters can be changed at run time
+# with the "SET" SQL command.
+#
+# Memory units:  kB = kilobytes        Time units:  ms  = milliseconds
+#                MB = megabytes                     s   = seconds
+#                GB = gigabytes                     min = minutes
+#                                                   h   = hours
+#                                                   d   = days
+
+
+#------------------------------------------------------------------------------
+# FILE LOCATIONS
+#------------------------------------------------------------------------------
+
+# The default values of these variables are driven from the -D command-line
+# option or PGDATA environment variable.
+
+data_directory = '${driver.dataDir}'       # use data in another directory
+                    # (change requires restart)
+#hba_file = '${driver.dataDir}/pg_hba.conf' # host-based authentication file
+                    # (change requires restart)
+#ident_file = '${driver.dataDir}/pg_ident.conf' # ident configuration file
+                    # (change requires restart)
+
+# If external_pid_file is not explicitly set, no extra PID file is written.
+external_pid_file = '${driver.pidFile}'       # write an extra PID file
+                    # (change requires restart)
+
+
+#------------------------------------------------------------------------------
+# CONNECTIONS AND AUTHENTICATION
+#------------------------------------------------------------------------------
+
+# - Connection Settings -
+
+listen_addresses = '${driver.hostname}'     # what IP address(es) to listen on;
+                    # comma-separated list of addresses;
+                    # defaults to 'localhost', '*' = all
+                    # (change requires restart)
+port = ${entity.postgreSqlPort?c}                # (change requires restart)
+max_connections = ${entity.maxConnections?c}           # (change requires restart)
+# Note:  Increasing max_connections costs ~400 bytes of shared memory per 
+# connection slot, plus lock space (see max_locks_per_transaction).
+#superuser_reserved_connections = 3 # (change requires restart)
+#unix_socket_directory = ''     # (change requires restart)
+#unix_socket_group = ''         # (change requires restart)
+#unix_socket_permissions = 0777     # begin with 0 to use octal notation
+                    # (change requires restart)
+#bonjour = off              # advertise server via Bonjour
+                    # (change requires restart)
+#bonjour_name = ''          # defaults to the computer name
+                    # (change requires restart)
+
+# - Security and Authentication -
+
+#authentication_timeout = 1min      # 1s-600s
+#ssl = off              # (change requires restart)
+#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH'  # allowed SSL ciphers
+                    # (change requires restart)
+#password_encryption = on
+#db_user_namespace = off
+
+# Kerberos and GSSAPI
+#krb_server_keyfile = ''
+#krb_srvname = 'postgres'       # (Kerberos only)
+#krb_caseins_users = off
+
+# - TCP Keepalives -
+# see "man 7 tcp" for details
+
+#tcp_keepalives_idle = 0        # TCP_KEEPIDLE, in seconds;
+                    # 0 selects the system default
+#tcp_keepalives_interval = 0        # TCP_KEEPINTVL, in seconds;
+                    # 0 selects the system default
+#tcp_keepalives_count = 0       # TCP_KEEPCNT;
+                    # 0 selects the system default
+
+
+#------------------------------------------------------------------------------
+# RESOURCE USAGE (except WAL)
+#------------------------------------------------------------------------------
+
+# - Memory -
+
+shared_buffers = ${entity.sharedMemory}           # min 128kB
+                    # (change requires restart)
+#temp_buffers = 8MB         # min 800kB
+#max_prepared_transactions = 0      # zero disables the feature
+                    # (change requires restart)
+# Note:  Increasing max_prepared_transactions costs ~600 bytes of shared memory
+# per transaction slot, plus lock space (see max_locks_per_transaction).
+# It is not advisable to set max_prepared_transactions nonzero unless you
+# actively intend to use prepared transactions.
+#work_mem = 1MB             # min 64kB
+#maintenance_work_mem = 16MB        # min 1MB
+#max_stack_depth = 2MB          # min 100kB
+
+# - Kernel Resource Usage -
+
+#max_files_per_process = 1000       # min 25
+                    # (change requires restart)
+#shared_preload_libraries = ''      # (change requires restart)
+
+# - Cost-Based Vacuum Delay -
+
+#vacuum_cost_delay = 0ms        # 0-100 milliseconds
+#vacuum_cost_page_hit = 1       # 0-10000 credits
+#vacuum_cost_page_miss = 10     # 0-10000 credits
+#vacuum_cost_page_dirty = 20        # 0-10000 credits
+#vacuum_cost_limit = 200        # 1-10000 credits
+
+# - Background Writer -
+
+#bgwriter_delay = 200ms         # 10-10000ms between rounds
+#bgwriter_lru_maxpages = 100        # 0-1000 max buffers written/round
+#bgwriter_lru_multiplier = 2.0      # 0-10.0 multipler on buffers scanned/round
+
+# - Asynchronous Behavior -
+
+#effective_io_concurrency = 1       # 1-1000. 0 disables prefetching
+
+
+#------------------------------------------------------------------------------
+# WRITE AHEAD LOG
+#------------------------------------------------------------------------------
+
+# - Settings -
+
+#fsync = on             # turns forced synchronization on or off
+#synchronous_commit = on        # immediate fsync at commit
+#wal_sync_method = fsync        # the default is the first option 
+                    # supported by the operating system:
+                    #   open_datasync
+                    #   fdatasync
+                    #   fsync
+                    #   fsync_writethrough
+                    #   open_sync
+#full_page_writes = on          # recover from partial page writes
+#wal_buffers = 64kB         # min 32kB
+                    # (change requires restart)
+#wal_writer_delay = 200ms       # 1-10000 milliseconds
+
+#commit_delay = 0           # range 0-100000, in microseconds
+#commit_siblings = 5            # range 1-1000
+
+# - Checkpoints -
+
+#checkpoint_segments = 3        # in logfile segments, min 1, 16MB each
+#checkpoint_timeout = 5min      # range 30s-1h
+#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0
+#checkpoint_warning = 30s       # 0 disables
+
+# - Archiving -
+
+#archive_mode = off     # allows archiving to be done
+                # (change requires restart)
+#archive_command = ''       # command to use to archive a logfile segment
+#archive_timeout = 0        # force a logfile segment switch after this
+                # number of seconds; 0 disables
+
+
+#------------------------------------------------------------------------------
+# QUERY TUNING
+#------------------------------------------------------------------------------
+
+# - Planner Method Configuration -
+
+#enable_bitmapscan = on
+#enable_hashagg = on
+#enable_hashjoin = on
+#enable_indexscan = on
+#enable_mergejoin = on
+#enable_nestloop = on
+#enable_seqscan = on
+#enable_sort = on
+#enable_tidscan = on
+
+# - Planner Cost Constants -
+
+#seq_page_cost = 1.0            # measured on an arbitrary scale
+#random_page_cost = 4.0         # same scale as above
+#cpu_tuple_cost = 0.01          # same scale as above
+#cpu_index_tuple_cost = 0.005       # same scale as above
+#cpu_operator_cost = 0.0025     # same scale as above
+#effective_cache_size = 128MB
+
+# - Genetic Query Optimizer -
+
+#geqo = on
+#geqo_threshold = 12
+#geqo_effort = 5            # range 1-10
+#geqo_pool_size = 0         # selects default based on effort
+#geqo_generations = 0           # selects default based on effort
+#geqo_selection_bias = 2.0      # range 1.5-2.0
+#geqo_seed = 0.0            # range 0.0-1.0
+
+# - Other Planner Options -
+
+#default_statistics_target = 100    # range 1-10000
+#constraint_exclusion = partition   # on, off, or partition
+#cursor_tuple_fraction = 0.1        # range 0.0-1.0
+#from_collapse_limit = 8
+#join_collapse_limit = 8        # 1 disables collapsing of explicit 
+                    # JOIN clauses
+
+
+#------------------------------------------------------------------------------
+# ERROR REPORTING AND LOGGING
+#------------------------------------------------------------------------------
+
+# - Where to Log -
+
+#log_destination = 'stderr'     # Valid values are combinations of
+                    # stderr, csvlog, syslog and eventlog,
+                    # depending on platform.  csvlog
+                    # requires logging_collector to be on.
+
+# This is used when logging to stderr:
+#logging_collector = off        # Enable capturing of stderr and csvlog
+                    # into log files. Required to be on for
+                    # csvlogs.
+                    # (change requires restart)
+
+# These are only used if logging_collector is on:
+#log_directory = 'pg_log'       # directory where log files are written,
+                    # can be absolute or relative to PGDATA
+#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'    # log file name pattern,
+                    # can include strftime() escapes
+#log_truncate_on_rotation = off     # If on, an existing log file of the
+                    # same name as the new log file will be
+                    # truncated rather than appended to.
+                    # But such truncation only occurs on
+                    # time-driven rotation, not on restarts
+                    # or size-driven rotation.  Default is
+                    # off, meaning append to existing files
+                    # in all cases.
+#log_rotation_age = 1d          # Automatic rotation of logfiles will
+                    # happen after that time.  0 disables.
+#log_rotation_size = 10MB       # Automatic rotation of logfiles will 
+                    # happen after that much log output.
+                    # 0 disables.
+
+# These are relevant when logging to syslog:
+#syslog_facility = 'LOCAL0'
+#syslog_ident = 'postgres'
+
+#silent_mode = off          # Run server silently.
+                    # DO NOT USE without syslog or
+                    # logging_collector
+                    # (change requires restart)
+
+
+# - When to Log -
+
+#client_min_messages = notice       # values in order of decreasing detail:
+                    #   debug5
+                    #   debug4
+                    #   debug3
+                    #   debug2
+                    #   debug1
+                    #   log
+                    #   notice
+                    #   warning
+                    #   error
+
+#log_min_messages = warning     # values in order of decreasing detail:
+                    #   debug5
+                    #   debug4
+                    #   debug3
+                    #   debug2
+                    #   debug1
+                    #   info
+                    #   notice
+                    #   warning
+                    #   error
+                    #   log
+                    #   fatal
+                    #   panic
+
+#log_error_verbosity = default      # terse, default, or verbose messages
+
+#log_min_error_statement = error    # values in order of decreasing detail:
+                    #   debug5
+                    #   debug4
+                    #   debug3
+                    #   debug2
+                    #   debug1
+                    #   info
+                    #   notice
+                    #   warning
+                    #   error
+                    #   log
+                    #   fatal
+                    #   panic (effectively off)
+
+#log_min_duration_statement = -1    # -1 is disabled, 0 logs all statements
+                    # and their durations, > 0 logs only
+                    # statements running at least this number
+                    # of milliseconds
+
+
+# - What to Log -
+
+#debug_print_parse = off
+#debug_print_rewritten = off
+#debug_print_plan = off
+#debug_pretty_print = on
+#log_checkpoints = off
+#log_connections = off
+#log_disconnections = off
+#log_duration = off
+#log_hostname = off
+#log_line_prefix = ''           # special values:
+                    #   %u = user name
+                    #   %d = database name
+                    #   %r = remote host and port
+                    #   %h = remote host
+                    #   %p = process ID
+                    #   %t = timestamp without milliseconds
+                    #   %m = timestamp with milliseconds
+                    #   %i = command tag
+                    #   %e = SQL state
+                    #   %c = session ID
+                    #   %l = session line number
+                    #   %s = session start timestamp
+                    #   %v = virtual transaction ID
+                    #   %x = transaction ID (0 if none)
+                    #   %q = stop here in non-session
+                    #        processes
+                    #   %% = '%'
+                    # e.g. '<%u%%%d> '
+#log_lock_waits = off           # log lock waits >= deadlock_timeout
+#log_statement = 'none'         # none, ddl, mod, all
+#log_temp_files = -1            # log temporary files equal or larger
+                    # than the specified size in kilobytes;
+                    # -1 disables, 0 logs all temp files
+#log_timezone = unknown         # actually, defaults to TZ environment
+                    # setting
+
+
+#------------------------------------------------------------------------------
+# RUNTIME STATISTICS
+#------------------------------------------------------------------------------
+
+# - Query/Index Statistics Collector -
+
+#track_activities = on
+#track_counts = on
+#track_functions = none         # none, pl, all
+#track_activity_query_size = 1024
+#update_process_title = on
+#stats_temp_directory = 'pg_stat_tmp'
+
+
+# - Statistics Monitoring -
+
+#log_parser_stats = off
+#log_planner_stats = off
+#log_executor_stats = off
+#log_statement_stats = off
+
+
+#------------------------------------------------------------------------------
+# AUTOVACUUM PARAMETERS
+#------------------------------------------------------------------------------
+
+#autovacuum = on            # Enable autovacuum subprocess?  'on' 
+                    # requires track_counts to also be on.
+#log_autovacuum_min_duration = -1   # -1 disables, 0 logs all actions and
+                    # their durations, > 0 logs only
+                    # actions running at least this number
+                    # of milliseconds.
+#autovacuum_max_workers = 3     # max number of autovacuum subprocesses
+#autovacuum_naptime = 1min      # time between autovacuum runs
+#autovacuum_vacuum_threshold = 50   # min number of row updates before
+                    # vacuum
+#autovacuum_analyze_threshold = 50  # min number of row updates before 
+                    # analyze
+#autovacuum_vacuum_scale_factor = 0.2   # fraction of table size before vacuum
+#autovacuum_analyze_scale_factor = 0.1  # fraction of table size before analyze
+#autovacuum_freeze_max_age = 200000000  # maximum XID age before forced vacuum
+                    # (change requires restart)
+#autovacuum_vacuum_cost_delay = 20ms    # default vacuum cost delay for
+                    # autovacuum, in milliseconds;
+                    # -1 means use vacuum_cost_delay
+#autovacuum_vacuum_cost_limit = -1  # default vacuum cost limit for
+                    # autovacuum, -1 means use
+                    # vacuum_cost_limit
+
+
+#------------------------------------------------------------------------------
+# CLIENT CONNECTION DEFAULTS
+#------------------------------------------------------------------------------
+
+# - Statement Behavior -
+
+#search_path = '"[#noparse]$user[/#noparse]",public'     # schema names
+#default_tablespace = ''        # a tablespace name, '' uses the default
+#temp_tablespaces = ''          # a list of tablespace names, '' uses
+                    # only default tablespace
+#check_function_bodies = on
+#default_do_language = 'plpgsql'
+#default_transaction_isolation = 'read committed'
+#default_transaction_read_only = off
+#session_replication_role = 'origin'
+#statement_timeout = 0          # in milliseconds, 0 is disabled
+#vacuum_freeze_min_age = 50000000
+#vacuum_freeze_table_age = 150000000
+#bytea_output = 'hex'           # hex, escape
+#xmlbinary = 'base64'
+#xmloption = 'content'
+
+# - Locale and Formatting -
+
+datestyle = 'iso, mdy'
+#intervalstyle = 'postgres'
+#timezone = unknown         # actually, defaults to TZ environment
+                    # setting
+#timezone_abbreviations = 'Default'     # Select the set of available time zone
+                    # abbreviations.  Currently, there are
+                    #   Default
+                    #   Australia
+                    #   India
+                    # You can create your own file in
+                    # share/timezonesets/.
+#extra_float_digits = 0         # min -15, max 3
+#client_encoding = sql_ascii        # actually, defaults to database
+                    # encoding
+
+# These settings are initialized by initdb, but they can be changed.
+lc_messages = 'en_US.UTF-8'         # locale for system error message
+                    # strings
+lc_monetary = 'en_US.UTF-8'         # locale for monetary formatting
+lc_numeric = 'en_US.UTF-8'          # locale for number formatting
+lc_time = 'en_US.UTF-8'             # locale for time formatting
+
+# default configuration for text search
+default_text_search_config = 'pg_catalog.english'
+
+# - Other Defaults -
+
+#dynamic_library_path = '[#noparse]$libdir[/#noparse]'
+#local_preload_libraries = ''
+
+
+#------------------------------------------------------------------------------
+# LOCK MANAGEMENT
+#------------------------------------------------------------------------------
+
+#deadlock_timeout = 1s
+#max_locks_per_transaction = 64     # min 10
+                    # (change requires restart)
+# Note:  Each lock table slot uses ~270 bytes of shared memory, and there are
+# max_locks_per_transaction * (max_connections + max_prepared_transactions)
+# lock table slots.
+
+
+#------------------------------------------------------------------------------
+# VERSION/PLATFORM COMPATIBILITY
+#------------------------------------------------------------------------------
+
+# - Previous PostgreSQL Versions -
+
+#add_missing_from = off
+#array_nulls = on
+#backslash_quote = safe_encoding    # on, off, or safe_encoding
+#default_with_oids = off
+#escape_string_warning = on
+#regex_flavor = advanced        # advanced, extended, or basic
+#sql_inheritance = on
+#standard_conforming_strings = off
+#synchronize_seqscans = on
+
+# - Other Platforms and Clients -
+
+#transform_null_equals = off
+
+
+#------------------------------------------------------------------------------
+# CUSTOMIZED OPTIONS
+#------------------------------------------------------------------------------
+
+#custom_variable_classes = ''       # list of custom variable class names
+
+# Lines that pgtune has had problems parsing
+
+log_line_prefix = 'user=%u,db=%d '

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/org/apache/brooklyn/entity/database/rubyrep/rubyrep.conf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/org/apache/brooklyn/entity/database/rubyrep/rubyrep.conf b/software/database/src/main/resources/org/apache/brooklyn/entity/database/rubyrep/rubyrep.conf
new file mode 100644
index 0000000..12fed6f
--- /dev/null
+++ b/software/database/src/main/resources/org/apache/brooklyn/entity/database/rubyrep/rubyrep.conf
@@ -0,0 +1,28 @@
+[#ftl]
+#
+
+RR::Initializer::run do |config|
+config.left = {
+:adapter  => '${entity.leftDatabaseUrl.scheme}', 
+:database => '${entity.leftDatabaseName}',
+:username => '${entity.leftUsername}',
+:password => '${entity.leftPassword}',
+:host     => '${entity.leftDatabaseUrl.host}',
+:port     => ${entity.leftDatabaseUrl.port?c}
+}
+ 
+config.right ={
+:adapter  => '${entity.rightDatabaseUrl.scheme}', 
+:database => '${entity.rightDatabaseName}',
+:username => '${entity.rightUsername}',
+:password => '${entity.rightPassword}',
+:host     => '${entity.rightDatabaseUrl.host}',
+:port     => ${entity.rightDatabaseUrl.port?c}
+}
+ 
+config.include_tables /${entity.tableRegex}/
+config.options[:replication_interval] = ${entity.replicationInterval?c}
+config.options[:logged_replication_events] = [
+:all_changes, 
+:all_conflicts
+]end

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/VogellaExampleAccess.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/VogellaExampleAccess.java b/software/database/src/test/java/brooklyn/entity/database/VogellaExampleAccess.java
deleted file mode 100644
index 4916c7c..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/VogellaExampleAccess.java
+++ /dev/null
@@ -1,161 +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 brooklyn.entity.database;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.collect.Lists;
-
-import java.sql.*;
-import java.util.List;
-
-/**
- * Basic JDBC Access test Class, based on the Vogella MySQL tutorial
- * http://www.vogella.de/articles/MySQLJava/article.html
- */
-public class VogellaExampleAccess {
-    public static final Logger log = LoggerFactory.getLogger(VogellaExampleAccess.class);
-
-    private Connection connect = null;
-    private Statement statement = null;
-    private final String url;
-    private final String dbName;
-
-    public VogellaExampleAccess(String driverClass, String url) throws ClassNotFoundException {
-        this(driverClass, url, "feedback");
-    }
-    
-    public VogellaExampleAccess(String driverClass, String url, String dbName) throws ClassNotFoundException {
-        // This will load the JDBC driver, each DB has its own driver
-        Class.forName(driverClass);
-        this.url = url;
-        this.dbName = dbName;
-    }
-
-    public void readModifyAndRevertDataBase() throws Exception {
-        connect();
-        readDataBase();
-        modifyDataBase();
-        revertDatabase();
-        close();
-    }
-
-    public void connect() throws Exception {
-        try {
-            // Setup the connection with the DB
-            String jdbcUrl = "jdbc:" + url + dbName + "?" + "user=sqluser&password=sqluserpw";
-            log.info("Connecting to " + jdbcUrl);
-            connect = DriverManager.getConnection(jdbcUrl);
-
-            // Statements allow to issue SQL queries to the database
-            statement = connect.createStatement();
-        } catch (Exception ex) {
-            close();
-            throw ex;
-        }
-    }
-
-    public List<List<String>> readDataBase() throws Exception {
-        List<List<String>> results = Lists.newArrayList();
-        // Result set get the result of the SQL query
-        ResultSet resultSet = statement.executeQuery("SELECT myuser, webpage, datum, summary, COMMENTS from COMMENTS");
-        // ResultSet is initially before the first data set
-        while (resultSet.next()) {
-            List<String> row = Lists.newArrayList();
-            for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
-                row.add(resultSet.getObject(i).toString());
-            }
-            results.add(row);
-        }
-        // Should close resultsets
-        resultSet.close();
-        writeResultSet(results);
-        return results;
-    }
-
-    public void modifyDataBase() throws Exception {
-        // PreparedStatements can use variables and are more efficient
-        PreparedStatement preparedStatement = connect.prepareStatement("insert into  COMMENTS values (?, ?, ?, ?, ? , ?, ?)");
-        // "myuser, webpage, datum, summary, COMMENTS from FEEDBACK.COMMENTS");
-        // Parameters start with 1
-        preparedStatement.setInt(1, 2);
-        preparedStatement.setString(2, "Test");
-        preparedStatement.setString(3, "TestEmail");
-        preparedStatement.setString(4, "TestWebpage");
-        preparedStatement.setDate(5, new Date(new java.util.Date().getTime()));
-        preparedStatement.setString(6, "TestSummary");
-        preparedStatement.setString(7, "TestComment");
-        preparedStatement.executeUpdate();
-
-        writeResultSet(readDataBase());
-        preparedStatement.close();
-    }
-
-    // Remove again the insert comment added by modifyDataBase()
-    public void revertDatabase() throws Exception {
-        PreparedStatement preparedStatement = connect
-                .prepareStatement("delete from COMMENTS where myuser= ? ; ");
-        preparedStatement.setString(1, "Test");
-        preparedStatement.executeUpdate();
-
-        ResultSet resultSet = statement.executeQuery("select * from COMMENTS");
-        writeMetaData(resultSet);
-        // Should close resultsets
-        resultSet.close();
-    }
-
-    private void writeMetaData(ResultSet resultSet) throws SQLException {
-        // Get some metadata from the database
-        log.info("The columns in the table are: ");
-
-        log.info("Table: " + resultSet.getMetaData().getTableName(1));
-        for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
-            log.info("Column " + i + " " + resultSet.getMetaData().getColumnName(i));
-        }
-    }
-
-    private void writeResultSet(List<List<String>> resultSet) throws SQLException {
-        for (List<String> row : resultSet) {
-            String user = row.get(0);
-            String website = row.get(1);
-            String date = row.get(2);
-            String summary = row.get(3);
-            String comment = row.get(4);
-            log.info("User: " + user);
-            log.info("Website: " + website);
-            log.info("Summary: " + summary);
-            log.info("Date: " + date);
-            log.info("Comment: " + comment);
-        }
-    }
-
-    // You should always close the statement and connection
-    public void close() throws Exception {
-        if (statement != null) {
-            statement.close();
-            statement = null;
-        }
-
-        if (connect != null) {
-            connect.close();
-            connect = null;
-        }
-    }
-}    
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/crate/CrateNodeIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/crate/CrateNodeIntegrationTest.java b/software/database/src/test/java/brooklyn/entity/database/crate/CrateNodeIntegrationTest.java
deleted file mode 100644
index 3439217..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/crate/CrateNodeIntegrationTest.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 brooklyn.entity.database.crate;
-
-import static org.testng.Assert.assertFalse;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.apache.brooklyn.test.entity.TestApplication;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-
-import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.trait.Startable;
-import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-
-public class CrateNodeIntegrationTest {
-
-    private TestApplication app;
-    private LocalhostMachineProvisioningLocation localhostProvisioningLocation;
-
-    @BeforeMethod(alwaysRun = true)
-    public void setUp() throws Exception {
-        localhostProvisioningLocation = new LocalhostMachineProvisioningLocation();
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void tearDown() throws Exception {
-        if (app != null) Entities.destroyAll(app.getManagementContext());
-    }
-
-    @Test(groups = "Integration")
-    public void testCanStartAndStop() throws Exception {
-        CrateNode entity = app.createAndManageChild(EntitySpec.create(CrateNode.class));
-        app.start(ImmutableList.of(localhostProvisioningLocation));
-
-        EntityTestUtils.assertAttributeEqualsEventually(entity, Startable.SERVICE_UP, true);
-        EntityTestUtils.assertAttributeEventuallyNonNull(entity, CrateNode.SERVER_NAME);
-
-        entity.stop();
-        assertFalse(entity.getAttribute(Startable.SERVICE_UP));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbIntegrationTest.java b/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbIntegrationTest.java
deleted file mode 100644
index 1dc25df..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbIntegrationTest.java
+++ /dev/null
@@ -1,127 +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 brooklyn.entity.database.mariadb;
-
-import java.io.File;
-import java.net.InetAddress;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.apache.brooklyn.core.management.internal.LocalManagementContext;
-import org.apache.brooklyn.test.entity.TestApplication;
-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 brooklyn.config.BrooklynProperties;
-import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-
-import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.text.Strings;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Runs a slightly modified version of the popular Vogella MySQL tutorial,
- * from
- * http://www.vogella.de/articles/MySQLJava/article.html
- */
-public class MariaDbIntegrationTest {
-
-    public static final Logger log = LoggerFactory.getLogger(MariaDbIntegrationTest.class);
-    
-    protected BrooklynProperties brooklynProperties;
-    protected ManagementContext managementContext;
-    protected TestApplication tapp;
-    protected String hostname;
-    
-    @BeforeMethod(alwaysRun = true)
-    public void setUp() throws Exception {
-        // can start in AWS by running this -- or use brooklyn CLI/REST for most clouds, or programmatic/config for set of fixed IP machines
-        hostname = InetAddress.getLocalHost().getHostName();
-
-        brooklynProperties = BrooklynProperties.Factory.newDefault();
-        managementContext = new LocalManagementContext(brooklynProperties);
-        tapp = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void ensureShutDown() throws Exception {
-        Entities.destroyAllCatching(managementContext);
-    }
-
-    //from http://www.vogella.de/articles/MySQLJava/article.html
-    public static final String CREATION_SCRIPT =
-            "CREATE DATABASE feedback; " +
-            "CREATE USER 'sqluser'@'localhost' IDENTIFIED BY 'sqluserpw'; " +
-            "GRANT USAGE ON *.* TO 'sqluser'@'localhost'; " +
-            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'localhost'; " +
-            "CREATE USER 'sqluser'@'%' IDENTIFIED BY 'sqluserpw'; " +
-            "GRANT USAGE ON *.* TO 'sqluser'@'%'; " +
-            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'%'; " +
-            "CREATE USER 'sqluser'@'$hostname' IDENTIFIED BY 'sqluserpw'; " +
-            "GRANT USAGE ON *.* TO 'sqluser'@'$hostname'; " +
-            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'$hostname'; " +
-            "FLUSH PRIVILEGES; " +
-            "USE feedback; " +
-            "CREATE TABLE COMMENTS ( " +
-                    "id INT NOT NULL AUTO_INCREMENT,  " +
-                    "MYUSER VARCHAR(30) NOT NULL, " +
-                    "EMAIL VARCHAR(30),  " +
-                    "WEBPAGE VARCHAR(100) NOT NULL,  " +
-                    "DATUM DATE NOT NULL,  " +
-                    "SUMMARY VARCHAR(40) NOT NULL, " +
-                    "COMMENTS VARCHAR(400) NOT NULL, " +
-                    "PRIMARY KEY (ID) " +
-                "); " +
-            "INSERT INTO COMMENTS values (default, 'lars', 'myemail@gmail.com','http://www.vogella.de', '2009-09-14 10:33:11', 'Summary','My first comment' );";
-
-    @Test(groups = "Integration")
-    public void test_localhost() throws Exception {
-        String dataDir = "/tmp/mariadb-data-" + Strings.makeRandomId(8);
-        MariaDbNode mariadb = tapp.createAndManageChild(EntitySpec.create(MariaDbNode.class)
-                .configure(MariaDbNode.MARIADB_SERVER_CONF, MutableMap.<String, Object>of("skip-name-resolve",""))
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, CREATION_SCRIPT)
-                .configure(MariaDbNode.DATA_DIR, dataDir));
-        LocalhostMachineProvisioningLocation location = new LocalhostMachineProvisioningLocation();
-
-        tapp.start(ImmutableList.of(location));
-        log.info("MariaDB started");
-
-        new VogellaExampleAccess("com.mysql.jdbc.Driver", mariadb.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
-
-        log.info("Ran vogella MySQL example -- SUCCESS");
-
-        // Ensure the data directory was successfully overridden.
-        File dataDirFile = new File(dataDir);
-        File mariadbSubdirFile = new File(dataDirFile, "mysql");
-        Assert.assertTrue(mariadbSubdirFile.exists());
-
-        // Clean up.
-        dataDirFile.delete();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbLiveEc2Test.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbLiveEc2Test.java b/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbLiveEc2Test.java
deleted file mode 100644
index a860f1c..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbLiveEc2Test.java
+++ /dev/null
@@ -1,57 +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 brooklyn.entity.database.mariadb;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-
-import org.apache.brooklyn.location.jclouds.JcloudsLocation;
-
-import com.google.common.collect.ImmutableList;
-
-@Test(groups = { "Live" })
-public class MariaDbLiveEc2Test extends AbstractEc2LiveTest {
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        // TODO For some CentOS VMs (e.g. in AWS 6.3, us-east-1/ami-a96b01c0), currently need to turn off iptables unfortunately.
-        // Should really just open the ports in iptables.
-        MariaDbNode mariadb = app.createAndManageChild(EntitySpec.create(MariaDbNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MariaDbIntegrationTest.CREATION_SCRIPT)
-                .configure(MariaDbNode.PROVISIONING_PROPERTIES.subKey(JcloudsLocation.STOP_IPTABLES.getName()), true));
-
-        app.start(ImmutableList.of(loc));
-
-        new VogellaExampleAccess("com.mysql.jdbc.Driver", mariadb.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
-    }
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_Debian_7_2() throws Exception { } // Disabled because MariaDB not available
-
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbLiveRackspaceTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbLiveRackspaceTest.java b/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbLiveRackspaceTest.java
deleted file mode 100644
index e3c617c..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mariadb/MariaDbLiveRackspaceTest.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 brooklyn.entity.database.mariadb;
-
-import java.util.Arrays;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import org.apache.brooklyn.location.jclouds.JcloudsLocation;
-import brooklyn.util.net.Protocol;
-import brooklyn.util.ssh.IptablesCommands;
-import brooklyn.util.ssh.IptablesCommands.Chain;
-import brooklyn.util.ssh.IptablesCommands.Policy;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * The MariaDbLiveTest installs MariaDb on various operating systems like Ubuntu, CentOS, Red Hat etc. To make sure that
- * MariaDb works like expected on these Operating Systems.
- */
-public class MariaDbLiveRackspaceTest extends MariaDbIntegrationTest {
-    @Test(groups = {"Live"})
-    public void test_Debian_6() throws Exception {
-        test("Debian 6");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_Ubuntu_10_0() throws Exception {
-        test("Ubuntu 10.0");
-    }
-
-    @Test(groups = {"Live", "Live-sanity"})
-    public void test_Ubuntu_12_0() throws Exception {
-        test("Ubuntu 12.0");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_Ubuntu_13() throws Exception {
-        test("Ubuntu 13");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_CentOS_6() throws Exception {
-        test("CentOS 6");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_CentOS_5() throws Exception {
-        test("CentOS 5");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_Fedora() throws Exception {
-        test("Fedora ");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_Red_Hat_Enterprise_Linux_6() throws Exception {
-        test("Red Hat Enterprise Linux 6");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_localhost() throws Exception {
-        super.test_localhost();
-    }
-
-    public void test(String osRegex) throws Exception {
-        MariaDbNode mariadb = tapp.createAndManageChild(EntitySpec.create(MariaDbNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, CREATION_SCRIPT));
-
-        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageNameRegex", osRegex);
-        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.image-id");
-        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageId");
-        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.inboundPorts", Arrays.asList(22, 3306));
-        JcloudsLocation jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve("jclouds:rackspace-cloudservers-uk");
-
-        tapp.start(ImmutableList.of(jcloudsLocation));
-
-        SshMachineLocation l = (SshMachineLocation) mariadb.getLocations().iterator().next();
-        l.execCommands("add iptables rule", ImmutableList.of(IptablesCommands.insertIptablesRule(Chain.INPUT, Protocol.TCP, 3306, Policy.ACCEPT)));
-
-        new VogellaExampleAccess("com.mysql.jdbc.Driver", mariadb.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
-    } 
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterIntegrationTest.java b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterIntegrationTest.java
deleted file mode 100644
index 3bc12eb..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterIntegrationTest.java
+++ /dev/null
@@ -1,44 +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 brooklyn.entity.database.mysql;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.Iterables;
-
-import brooklyn.entity.BrooklynAppLiveTestSupport;
-import brooklyn.util.os.Os;
-
-public class MySqlClusterIntegrationTest extends BrooklynAppLiveTestSupport {
-
-    @Test(groups = {"Integration"})
-    public void test_localhost() throws Exception {
-        try {
-            MySqlClusterTestHelper.test(app, mgmt.getLocationRegistry().resolve("localhost"));
-        } finally {
-            for (Entity member : Iterables.getOnlyElement(app.getChildren()).getChildren()) {
-                String runDir = member.getAttribute(MySqlNode.RUN_DIR);
-                if (runDir != null) {
-                    Os.deleteRecursively(runDir);
-                }
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterLiveEc2Test.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterLiveEc2Test.java b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterLiveEc2Test.java
deleted file mode 100644
index 477f81b..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterLiveEc2Test.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 brooklyn.entity.database.mysql;
-
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-
-import org.apache.brooklyn.api.location.Location;
-
-@Test(groups = { "Live" })
-public class MySqlClusterLiveEc2Test extends AbstractEc2LiveTest {
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        MySqlClusterTestHelper.test(app, loc);
-    }
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_Debian_7_2() throws Exception { } // Disabled because MySQl not available
-
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterLiveSoftlayerTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterLiveSoftlayerTest.java b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterLiveSoftlayerTest.java
deleted file mode 100644
index 6f1556c..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterLiveSoftlayerTest.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 brooklyn.entity.database.mysql;
-
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractSoftlayerLiveTest;
-
-import org.apache.brooklyn.api.location.Location;
-
-@Test(groups = { "Live" })
-public class MySqlClusterLiveSoftlayerTest extends AbstractSoftlayerLiveTest {
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        MySqlClusterTestHelper.test(app, loc);
-    }
-
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterTestHelper.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterTestHelper.java b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterTestHelper.java
deleted file mode 100644
index 739d818..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlClusterTestHelper.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 brooklyn.entity.database.mysql;
-
-import static org.testng.Assert.assertEquals;
-
-import java.util.List;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.entity.TestApplication;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-
-import brooklyn.entity.database.VogellaExampleAccess;
-import brooklyn.test.Asserts;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-
-/**
- * Runs a slightly modified version of the popular Vogella MySQL tutorial,
- * from
- * http://www.vogella.de/articles/MySQLJava/article.html
- */
-public class MySqlClusterTestHelper {
-    public static final Logger log = LoggerFactory.getLogger(MySqlClusterTestHelper.class);
-
-    // From http://www.vogella.de/articles/MySQLJava/article.html
-    public static final String CREATION_SCRIPT = Joiner.on("\n").join(ImmutableList.of(
-            "CREATE DATABASE feedback;",
-            "CREATE USER 'sqluser'@'localhost' IDENTIFIED BY 'sqluserpw';",
-            "GRANT USAGE ON *.* TO 'sqluser'@'localhost';",
-            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'localhost';",
-            "CREATE USER 'sqluser'@'%' IDENTIFIED BY 'sqluserpw';",
-            "GRANT USAGE ON *.* TO 'sqluser'@'%';",
-            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'%';",
-            "FLUSH PRIVILEGES;",
-            "USE feedback;",
-            "CREATE TABLE COMMENTS (",
-            "        id INT NOT NULL AUTO_INCREMENT,", 
-            "        MYUSER VARCHAR(30) NOT NULL,",
-            "        EMAIL VARCHAR(30), ",
-            "        WEBPAGE VARCHAR(100) NOT NULL,", 
-            "        DATUM DATE NOT NULL, ",
-            "        SUMMARY VARCHAR(40) NOT NULL,",
-            "        COMMENTS VARCHAR(400) NOT NULL,",
-            "        PRIMARY KEY (ID)",
-            "    );",
-            "",
-            "INSERT INTO COMMENTS values (default, 'lars', 'myemail@gmail.com','http://www.vogella.de', '2009-09-14 10:33:11', 'Summary','My first comment' );"
-            ));
-
-    public static void test(TestApplication app, Location location) throws Exception {
-        MySqlCluster mysql = app.createAndManageChild(EntitySpec.create(MySqlCluster.class)
-                .configure(MySqlCluster.INITIAL_SIZE, 2)
-                .configure(MySqlNode.MYSQL_SERVER_CONF, MutableMap.<String, Object>of("skip-name-resolve","")));
-
-        app.start(ImmutableList.of(location));
-        log.info("MySQL started");
-        MySqlNode masterEntity = (MySqlNode) mysql.getAttribute(MySqlCluster.FIRST);
-        masterEntity.invoke(MySqlNode.EXECUTE_SCRIPT, ImmutableMap.of("commands", CREATION_SCRIPT)).asTask().getUnchecked();
-
-        VogellaExampleAccess masterDb = new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(MySqlNode.DATASTORE_URL));
-        VogellaExampleAccess slaveDb = new VogellaExampleAccess("com.mysql.jdbc.Driver", Iterables.getOnlyElement(mysql.getAttribute(MySqlCluster.SLAVE_DATASTORE_URL_LIST)));
-        masterDb.connect();
-        slaveDb.connect();
-
-        assertSlave(masterDb, slaveDb, 1);
-        masterDb.modifyDataBase();
-        assertSlave(masterDb, slaveDb, 2);
-        masterDb.revertDatabase();
-        assertSlave(masterDb, slaveDb, 1);
-
-        masterDb.close();
-        slaveDb.close();
-
-        log.info("Ran vogella MySQL example -- SUCCESS");
-    }
-
-    private static void assertSlave(final VogellaExampleAccess masterDb, final VogellaExampleAccess slaveDb, final int recordCnt) throws Exception {
-        Asserts.succeedsEventually(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    List<List<String>> masterResult = masterDb.readDataBase();
-                    assertEquals(masterResult.size(), recordCnt);
-                    assertEquals(masterResult, slaveDb.readDataBase());
-                } catch (Exception e) {
-                    throw Exceptions.propagate(e);
-                }
-            }
-        });
-    }
-}


[10/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveBuilderTest.java b/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveBuilderTest.java
new file mode 100644
index 0000000..0ce8298
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveBuilderTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.util.file;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.core.util.file.ArchiveBuilder;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.os.Os;
+import brooklyn.util.text.Identifiers;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.io.Files;
+
+/**
+ * Test the operation of the {@link ArchiveBuilder} class.
+ */
+@Test
+public class ArchiveBuilderTest {
+
+    private File parentDir, tmpDir, tmpDir2;
+    private Predicate<ZipEntry> isDirectory = new Predicate<ZipEntry>() {
+                @Override
+                public boolean apply(@Nullable ZipEntry input) {
+                    return input.isDirectory();
+                }
+            };
+
+    @BeforeClass
+    public void createTmpDirAndFiles() throws IOException {
+        parentDir = Os.newTempDir(getClass().getSimpleName());
+        Os.deleteOnExitRecursively(parentDir);
+        tmpDir = new File(parentDir, Identifiers.makeRandomId(4));
+        Os.mkdirs(tmpDir);
+        Files.write("abcdef", new File(tmpDir, "data01.txt"), Charsets.US_ASCII);
+        Files.write("123456", new File(tmpDir, "data02.txt"), Charsets.US_ASCII);
+        Files.write("qqqqqq", new File(tmpDir, "data03.txt"), Charsets.US_ASCII);
+        
+        tmpDir2 = new File(parentDir, Identifiers.makeRandomId(4));
+        Os.mkdirs(tmpDir2);
+        Files.write("zzzzzz", new File(tmpDir2, "data04.txt"), Charsets.US_ASCII);
+    }
+    
+    @Test
+    public void testCreateZipFromDir() throws Exception {
+        File archive = ArchiveBuilder.zip().addDirContentsAt(tmpDir, ".").create();
+        archive.deleteOnExit();
+
+        List<ZipEntry> entries = Lists.newArrayList();
+        ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
+        ZipEntry entry = input.getNextEntry();
+        while (entry != null) {
+            entries.add(entry);
+            entry = input.getNextEntry();
+        }
+        assertEquals(entries.size(), 4);
+        Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
+        Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
+        assertEquals(Iterables.size(directories), 1);
+        assertEquals(Iterables.size(files), 3);
+        String dirName = Iterables.getOnlyElement(directories).getName();
+        assertEquals(dirName, "./");
+        
+        Set<String> names = MutableSet.of();
+        for (ZipEntry file : files) {
+            assertTrue(file.getName().startsWith(dirName));
+            names.add(file.getName());
+        }
+        assertTrue(names.contains("./data01.txt"));
+        assertFalse(names.contains("./data04.txt"));
+        input.close();
+    }
+
+    @Test
+    public void testCreateZipFromTwoDirs() throws Exception {
+        File archive = ArchiveBuilder.zip().addDirContentsAt(tmpDir, ".").addDirContentsAt(tmpDir2, ".").create();
+        archive.deleteOnExit();
+
+        List<ZipEntry> entries = Lists.newArrayList();
+        ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
+        ZipEntry entry = input.getNextEntry();
+        while (entry != null) {
+            entries.add(entry);
+            entry = input.getNextEntry();
+        }
+        assertEquals(entries.size(), 5);
+        Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
+        Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
+        assertEquals(Iterables.size(directories), 1);
+        assertEquals(Iterables.size(files), 4);
+        String dirName = Iterables.getOnlyElement(directories).getName();
+        assertEquals(dirName, "./");
+        
+        Set<String> names = MutableSet.of();
+        for (ZipEntry file : files) {
+            assertTrue(file.getName().startsWith(dirName));
+            names.add(file.getName());
+        }
+        assertTrue(names.contains("./data01.txt"));
+        assertTrue(names.contains("./data04.txt"));
+        input.close();
+    }
+    @Test
+    public void testCreateZipFromFiles() throws Exception {
+        ArchiveBuilder builder = ArchiveBuilder.zip();
+        for (String fileName : Arrays.asList("data01.txt", "data02.txt", "data03.txt")) {
+            builder.addAt(new File(tmpDir, fileName), ".");
+        }
+        File archive = builder.create();
+        archive.deleteOnExit();
+
+        List<ZipEntry> entries = Lists.newArrayList();
+        ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
+        ZipEntry entry = input.getNextEntry();
+        while (entry != null) {
+            entries.add(entry);
+            entry = input.getNextEntry();
+        }
+        assertEquals(entries.size(), 3);
+        Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
+        Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
+        assertTrue(Iterables.isEmpty(directories));
+        assertEquals(Iterables.size(files), 3);
+        for (ZipEntry file : files) {
+            assertTrue(file.getName().startsWith(Os.mergePathsUnix(".", "data")));
+        }
+        input.close();
+    }
+
+    @Test
+    public void testCreateZipFromFilesWithBaseDir() throws Exception {
+        ArchiveBuilder builder = ArchiveBuilder.zip();
+        String baseDir = tmpDir.getName();
+        for (String fileName : Arrays.asList("data01.txt", "data02.txt", "data03.txt")) {
+            builder.addFromLocalBaseDir(parentDir, Os.mergePaths(baseDir, fileName));
+        }
+        File archive = builder.create();
+        archive.deleteOnExit();
+
+        List<ZipEntry> entries = Lists.newArrayList();
+        ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
+        ZipEntry entry = input.getNextEntry();
+        while (entry != null) {
+            entries.add(entry);
+            entry = input.getNextEntry();
+        }
+        assertEquals(entries.size(), 3);
+        Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
+        Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
+        assertTrue(Iterables.isEmpty(directories));
+        assertEquals(Iterables.size(files), 3);
+        for (ZipEntry file : files) {
+            assertTrue(file.getName().startsWith(Os.mergePathsUnix(".", baseDir)));
+        }
+        input.close();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveUtilsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveUtilsTest.java
new file mode 100644
index 0000000..a13ef63
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/file/ArchiveUtilsTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.util.file;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.io.File;
+import java.util.Map;
+
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.file.ArchiveBuilder;
+import org.apache.brooklyn.core.util.file.ArchiveUtils;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.os.Os;
+
+import com.google.api.client.repackaged.com.google.common.base.Joiner;
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.Files;
+
+// Test are integration, because relies on ssh/scp via SshMachineLocation
+public class ArchiveUtilsTest extends BrooklynAppUnitTestSupport {
+    
+    private SshMachineLocation machine;
+    private ResourceUtils resourceUtils;
+
+    private Map<String, String> archiveContents = ImmutableMap.of("a.txt", "mya");
+    private File destDir;
+    private File origZip;
+    private File origJar;
+
+    @BeforeClass(alwaysRun=true)
+    public void setUpClass() throws Exception {
+        origZip = newZip(archiveContents);
+        origJar = Os.newTempFile(ArchiveUtilsTest.class, ".jar");
+        Files.copy(origZip, origJar);
+    }
+    
+    @AfterClass(alwaysRun=true)
+    public void tearDownClass() throws Exception {
+        if (origZip != null) origZip.delete();
+        if (origJar != null) origJar.delete();
+    }
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        machine = app.newLocalhostProvisioningLocation().obtain();
+        resourceUtils = ResourceUtils.create(ArchiveUtilsTest.class);
+        destDir = Os.newTempDir(getClass().getSimpleName());
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        if (destDir != null) Os.deleteRecursively(destDir);
+    }
+    
+    @Test(groups="Integration")
+    public void testDeployZipWithNoOptionalArgsSupplied() throws Exception {
+        boolean result = ArchiveUtils.deploy(resourceUtils, ImmutableMap.<String, Object>of(), origZip.getAbsolutePath(), machine, destDir.getAbsolutePath(), true, null, null);
+        assertTrue(result);
+        assertFilesEqual(new File(destDir, origZip.getName()), origZip);
+        assertSubFilesEqual(destDir, archiveContents);
+    }
+    
+    @Test(groups="Integration")
+    public void testDeployZipDeletingArchiveAfterUnpack() throws Exception {
+        boolean result = ArchiveUtils.deploy(resourceUtils, ImmutableMap.<String, Object>of(), origZip.getAbsolutePath(), machine, destDir.getAbsolutePath(), false, null, null);
+        assertTrue(result);
+        assertFalse(new File(destDir, origZip.getName()).exists());
+        assertSubFilesEqual(destDir, archiveContents);
+    }
+    
+    @Test(groups="Integration")
+    public void testDeployJarNotUnpacked() throws Exception {
+        ArchiveUtils.deploy(origJar.getAbsolutePath(), machine, destDir.getAbsolutePath());
+        assertFilesEqual(new File(destDir, origJar.getName()), origJar);
+    }
+    
+    @Test(groups="Integration")
+    public void testDeployExplicitDestFile() throws Exception {
+        String destFile = "custom-destFile.jar";
+        ArchiveUtils.deploy(origJar.getAbsolutePath(), machine, destDir.getAbsolutePath(), destFile);
+        assertFilesEqual(new File(destDir, destFile), origJar);
+    }
+    
+    private File newZip(Map<String, String> files) throws Exception {
+        File parentDir = Os.newTempDir(getClass().getSimpleName()+"-archive");
+        for (Map.Entry<String, String> entry : files.entrySet()) {
+            File subFile = new File(Os.mergePaths(parentDir.getAbsolutePath(), entry.getKey()));
+            subFile.getParentFile().mkdirs();
+            Files.write(entry.getValue(), subFile, Charsets.UTF_8);
+        }
+        return ArchiveBuilder.zip().addDirContentsAt(parentDir, ".").create();
+    }
+    
+    private void assertFilesEqual(File f1, File f2) throws Exception {
+        byte[] bytes1 = Files.asByteSource(f1).read();
+        byte[] bytes2 = Files.asByteSource(f1).read();
+        assertEquals(bytes1, bytes2, "f1="+f1+"; f2="+f2);
+    }
+    
+    private void assertSubFilesEqual(File parentDir, Map<String, String> files) throws Exception {
+        for (Map.Entry<String, String> entry : archiveContents.entrySet()) {
+            File subFile = new File(Os.mergePaths(parentDir.getAbsolutePath(), entry.getKey()));
+            assertEquals(Joiner.on("\n").join(Files.readLines(subFile, Charsets.UTF_8)), entry.getValue());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/flags/MethodCoercionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/flags/MethodCoercionsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/flags/MethodCoercionsTest.java
new file mode 100644
index 0000000..2d1efa3
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/flags/MethodCoercionsTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.util.flags;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+
+import org.apache.brooklyn.core.util.flags.MethodCoercions;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import static org.testng.Assert.*;
+
+public class MethodCoercionsTest {
+
+    private Method singleParameterMethod;
+    private Method multiParameterMethod;
+    private Method singleCollectionParameterMethod;
+
+    @BeforeClass
+    public void testFixtureSetUp() {
+        try {
+            singleParameterMethod = TestClass.class.getMethod("singleParameterMethod", int.class);
+            multiParameterMethod = TestClass.class.getMethod("multiParameterMethod", boolean.class, int.class);
+            singleCollectionParameterMethod = TestClass.class.getMethod("singleCollectionParameterMethod", List.class);
+        } catch (NoSuchMethodException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    @Test
+    public void testMatchSingleParameterMethod() throws Exception {
+        Predicate<Method> predicate = MethodCoercions.matchSingleParameterMethod("singleParameterMethod", "42");
+        assertTrue(predicate.apply(singleParameterMethod));
+        assertFalse(predicate.apply(multiParameterMethod));
+        assertFalse(predicate.apply(singleCollectionParameterMethod));
+    }
+
+    @Test
+    public void testTryFindAndInvokeSingleParameterMethod() throws Exception {
+        TestClass instance = new TestClass();
+        Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleParameterMethod(instance, "singleParameterMethod", "42");
+        assertTrue(maybe.isPresent());
+        assertTrue(instance.wasSingleParameterMethodCalled());
+    }
+
+    @Test
+    public void testMatchMultiParameterMethod() throws Exception {
+        Predicate<Method> predicate = MethodCoercions.matchMultiParameterMethod("multiParameterMethod", ImmutableList.of("true", "42"));
+        assertFalse(predicate.apply(singleParameterMethod));
+        assertTrue(predicate.apply(multiParameterMethod));
+        assertFalse(predicate.apply(singleCollectionParameterMethod));
+    }
+
+    @Test
+    public void testTryFindAndInvokeMultiParameterMethod() throws Exception {
+        TestClass instance = new TestClass();
+        Maybe<?> maybe = MethodCoercions.tryFindAndInvokeMultiParameterMethod(instance, "multiParameterMethod", ImmutableList.of("true", "42"));
+        assertTrue(maybe.isPresent());
+        assertTrue(instance.wasMultiParameterMethodCalled());
+    }
+
+    @Test
+    public void testTryFindAndInvokeBestMatchingMethod() throws Exception {
+        TestClass instance = new TestClass();
+        Maybe<?> maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "singleParameterMethod", "42");
+        assertTrue(maybe.isPresent());
+        assertTrue(instance.wasSingleParameterMethodCalled());
+
+        instance = new TestClass();
+        maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "multiParameterMethod", ImmutableList.of("true", "42"));
+        assertTrue(maybe.isPresent());
+        assertTrue(instance.wasMultiParameterMethodCalled());
+
+        instance = new TestClass();
+        maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "singleCollectionParameterMethod", ImmutableList.of("fred", "joe"));
+        assertTrue(maybe.isPresent());
+        assertTrue(instance.wasSingleCollectionParameterMethodCalled());
+    }
+/*
+    @Test
+    public void testMatchSingleCollectionParameterMethod() throws Exception {
+        Predicate<Method> predicate = MethodCoercions.matchSingleCollectionParameterMethod("singleCollectionParameterMethod", ImmutableList.of("42"));
+        assertFalse(predicate.apply(singleParameterMethod));
+        assertFalse(predicate.apply(multiParameterMethod));
+        assertTrue(predicate.apply(singleCollectionParameterMethod));
+    }
+
+    @Test
+    public void testTryFindAndInvokeSingleCollectionParameterMethod() throws Exception {
+        TestClass instance = new TestClass();
+        Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleCollectionParameterMethod(instance, "singleCollectionParameterMethod", ImmutableList.of("42"));
+        assertTrue(maybe.isPresent());
+        assertTrue(instance.wasSingleCollectionParameterMethodCalled());
+    }
+*/
+    public static class TestClass {
+
+        private boolean singleParameterMethodCalled;
+        private boolean multiParameterMethodCalled;
+        private boolean singleCollectionParameterMethodCalled;
+
+        public void singleParameterMethod(int parameter) {
+            singleParameterMethodCalled = true;
+        }
+
+        public void multiParameterMethod(boolean parameter1, int parameter2) {
+            multiParameterMethodCalled = true;
+        }
+
+        public void singleCollectionParameterMethod(List<String> parameter) {
+            singleCollectionParameterMethodCalled = true;
+        }
+
+        public boolean wasSingleParameterMethodCalled() {
+            return singleParameterMethodCalled;
+        }
+
+        public boolean wasMultiParameterMethodCalled() {
+            return multiParameterMethodCalled;
+        }
+
+        public boolean wasSingleCollectionParameterMethodCalled() {
+            return singleCollectionParameterMethodCalled;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/http/BetterMockWebServer.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/http/BetterMockWebServer.java b/core/src/test/java/org/apache/brooklyn/core/util/http/BetterMockWebServer.java
new file mode 100644
index 0000000..f02689b
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/http/BetterMockWebServer.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.core.util.http;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.Proxy;
+import java.net.URL;
+
+import javax.net.ssl.SSLSocketFactory;
+
+import com.google.common.base.Throwables;
+import com.google.mockwebserver.Dispatcher;
+import com.google.mockwebserver.MockResponse;
+import com.google.mockwebserver.MockWebServer;
+import com.google.mockwebserver.RecordedRequest;
+
+/** like MockWebServer (and delegating) but:
+ * <li> allows subclassing
+ * <li> easy way to create instance which returns localhost for {@link #getHostName()}
+ *      (since otherwise you can get failures on networks which misconfigure hostname) 
+ * */
+public class BetterMockWebServer {
+
+    final MockWebServer delegate = new MockWebServer();
+    String hostname = null;
+    boolean isHttps = false;
+    
+    public static BetterMockWebServer newInstanceLocalhost() {
+        return new BetterMockWebServer().setHostName("localhost");
+    }
+    
+    /** use {@link #newInstanceLocalhost()} or subclass */
+    protected BetterMockWebServer() {}
+
+    public BetterMockWebServer setHostName(String hostname) {
+        this.hostname = hostname;
+        return this;
+    }
+
+
+    // --- delegate methods (unchanged)
+    
+    public void enqueue(MockResponse response) {
+        delegate.enqueue(response);
+    }
+
+    public boolean equals(Object obj) {
+        return delegate.equals(obj);
+    }
+
+    public String getCookieDomain() {
+        return delegate.getCookieDomain();
+    }
+
+    public String getHostName() {
+        if (hostname!=null) return hostname;
+        return delegate.getHostName();
+    }
+
+    public int getPort() {
+        return delegate.getPort();
+    }
+
+    public int getRequestCount() {
+        return delegate.getRequestCount();
+    }
+
+    public URL getUrl(String path) {
+        try {
+            return isHttps
+                ? new URL("https://" + getHostName() + ":" + getPort() + path)
+                : new URL("http://" + getHostName() + ":" + getPort() + path);
+        } catch (MalformedURLException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
+    public int hashCode() {
+        return delegate.hashCode();
+    }
+
+    public void play() throws IOException {
+        delegate.play();
+    }
+
+    public void play(int port) throws IOException {
+        delegate.play(port);
+    }
+
+    public void setBodyLimit(int maxBodyLength) {
+        delegate.setBodyLimit(maxBodyLength);
+    }
+
+    public void setDispatcher(Dispatcher dispatcher) {
+        delegate.setDispatcher(dispatcher);
+    }
+
+    public void shutdown() throws IOException {
+        delegate.shutdown();
+    }
+
+    public RecordedRequest takeRequest() throws InterruptedException {
+        return delegate.takeRequest();
+    }
+
+    public Proxy toProxyAddress() {
+        return delegate.toProxyAddress();
+    }
+
+    public String toString() {
+        return delegate.toString();
+    }
+
+    public void useHttps(SSLSocketFactory sslSocketFactory, boolean tunnelProxy) {
+        isHttps = true;
+        delegate.useHttps(sslSocketFactory, tunnelProxy);
+    }
+    
+    
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/http/HttpToolIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/http/HttpToolIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/util/http/HttpToolIntegrationTest.java
new file mode 100644
index 0000000..f557955
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/http/HttpToolIntegrationTest.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.util.http;
+
+import static org.testng.Assert.assertTrue;
+
+import java.net.URI;
+
+import org.apache.http.client.HttpClient;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
+import org.apache.brooklyn.location.basic.PortRanges;
+
+import brooklyn.test.HttpService;
+
+import com.google.common.collect.ImmutableMap;
+
+public class HttpToolIntegrationTest {
+
+    // TODO Expand test coverage for credentials etc
+    
+    private HttpService httpService;
+    private HttpService httpsService;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        httpService = new HttpService(PortRanges.fromString("9000+"), false).start();
+        httpsService = new HttpService(PortRanges.fromString("9000+"), true).start();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (httpService != null) httpService.shutdown();
+        if (httpsService != null) httpsService.shutdown();
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testHttpGet() throws Exception {
+        URI baseUri = new URI(httpService.getUrl());
+
+        HttpClient client = HttpTool.httpClientBuilder().build();
+        HttpToolResponse result = HttpTool.httpGet(client, baseUri, ImmutableMap.<String,String>of());
+        assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testHttpRedirect() throws Exception {
+        URI baseUri = new URI(httpService.getUrl() + "hello/redirectAbsolute");
+
+        HttpClient client = HttpTool.httpClientBuilder().laxRedirect(true).build();
+        HttpToolResponse result = HttpTool.httpGet(client, baseUri, ImmutableMap.<String,String>of());
+        assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testHttpPost() throws Exception {
+        URI baseUri = new URI(httpService.getUrl());
+
+        HttpClient client = HttpTool.httpClientBuilder().build();
+        HttpToolResponse result = HttpTool.httpPost(client, baseUri, ImmutableMap.<String,String>of(), new byte[0]);
+        assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testHttpsGetWithTrustAll() throws Exception {
+        URI baseUri = new URI(httpsService.getUrl());
+
+        HttpClient client = HttpTool.httpClientBuilder().https(true).trustAll().build();
+        HttpToolResponse result = HttpTool.httpGet(client, baseUri, ImmutableMap.<String,String>of());
+        assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testHttpsPostWithTrustSelfSigned() throws Exception {
+        URI baseUri = new URI(httpsService.getUrl());
+
+        HttpClient client = HttpTool.httpClientBuilder().https(true).trustSelfSigned().build();
+        HttpToolResponse result = HttpTool.httpPost(client, baseUri, ImmutableMap.<String,String>of(), new byte[0]);
+        assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/FlagUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/FlagUtilsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/FlagUtilsTest.java
new file mode 100644
index 0000000..02becf6
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/FlagUtilsTest.java
@@ -0,0 +1,314 @@
+/*
+ * 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.util.internal;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.lang.reflect.Field;
+import java.net.InetAddress;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.trait.Configurable;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.config.ConfigKey.HasConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+public class FlagUtilsTest {
+
+    public static final Logger log = LoggerFactory.getLogger(FlagUtilsTest.class);
+    
+    @Test
+    public void testGetAllFields() {
+        log.info("types {}", FlagUtils.getAllAssignableTypes(Baz.class));
+        assertEquals(FlagUtils.getAllAssignableTypes(Baz.class), ImmutableList.of(Baz.class, Foo.class, Bar.class));
+        List<Field> fs = FlagUtils.getAllFields(Baz.class);
+        for (Field f : fs) {
+            log.info("field {}    {}", f.getName(), f);
+        }
+        List<String> fsn = ImmutableList.copyOf(Iterables.transform(fs, new Function<Field, String>() {
+            @Override public String apply(Field f) {
+                return f.getName();
+            }}));
+        assertTrue(fsn.indexOf("A") >= 0);
+        assertTrue(fsn.indexOf("w") > fsn.indexOf("A")); 
+        assertTrue(fsn.indexOf("x") > fsn.indexOf("A") );
+        assertTrue(fsn.indexOf("yNotY") > fsn.indexOf("A")); 
+        assertTrue(fsn.indexOf("Z") > fsn.indexOf("yNotY") );
+    }    
+    
+    @Test
+    public void testSetFieldsFromFlags() {
+        Foo f = new Foo();
+        Map<?,?> m = MutableMap.of("w", 3, "x", 1, "y", 7, "z", 9);
+        Map<?, ?> unused = FlagUtils.setFieldsFromFlags(m, f);
+        assertEquals(f.w, 3);
+        assertEquals(f.x, 1);
+        assertEquals(f.yNotY, 7);
+        assertEquals(unused, ImmutableMap.of("z", 9));
+        Map<?,?> m2 = FlagUtils.getFieldsWithValues(f);
+        m.remove("z");
+        assertEquals(m2, m);
+    }
+    
+    @Test
+    public void testCollectionCoercionOnSetFromFlags() {
+        WithSpecialFieldTypes s = new WithSpecialFieldTypes();
+        Map<?,?> m = ImmutableMap.of("set", ImmutableSet.of(1));
+        FlagUtils.setFieldsFromFlags(m, s);
+        assertEquals(s.set, ImmutableSet.of(1));
+    }
+
+    @Test
+    public void testInetAddressCoercionOnSetFromFlags() {
+        WithSpecialFieldTypes s = new WithSpecialFieldTypes();
+        Map<?,?> m = ImmutableMap.of("inet", "127.0.0.1");
+        FlagUtils.setFieldsFromFlags(m, s);
+        assertEquals(s.inet.getHostAddress(), "127.0.0.1");
+    }
+
+    @Test
+    public void testNonImmutableField() {
+        Foo f = new Foo();
+        FlagUtils.setFieldsFromFlags(ImmutableMap.of("w", 8), f);
+        assertEquals(f.w, 8);
+        FlagUtils.setFieldsFromFlags(ImmutableMap.of("w", 9), f);
+        assertEquals(f.w, 9);
+    }
+
+    @Test
+    public void testImmutableIntField() {
+        Foo f = new Foo();
+        FlagUtils.setFieldsFromFlags(ImmutableMap.of("x", 8), f);
+        assertEquals(f.x, 8);
+        boolean succeededWhenShouldntHave = false; 
+        try {
+            FlagUtils.setFieldsFromFlags(ImmutableMap.of("x", 9), f);
+            succeededWhenShouldntHave = true;
+        } catch (IllegalStateException e) {
+            //expected
+        }
+        assertFalse(succeededWhenShouldntHave);
+        assertEquals(f.x, 8);
+    }
+
+    @Test
+    public void testImmutableObjectField() {
+        WithImmutableNonNullableObject o = new WithImmutableNonNullableObject();
+        FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a", "b", "b"), o);
+        assertEquals(o.a, "a");
+        assertEquals(o.b, "b");
+        
+        FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a2"), o);
+        assertEquals(o.a, "a2");
+        
+        boolean succeededWhenShouldntHave = false;
+        try {
+            FlagUtils.setFieldsFromFlags(ImmutableMap.of("b", "b2"), o);
+            succeededWhenShouldntHave = true;
+        } catch (IllegalStateException e) {
+            //expected
+        }
+        assertFalse(succeededWhenShouldntHave);
+        assertEquals(o.b, "b");
+    }
+
+    @Test
+    public void testNonNullable() {
+        WithImmutableNonNullableObject o = new WithImmutableNonNullableObject();
+        //allowed
+        FlagUtils.setFieldsFromFlags(MutableMap.of("a", null), o);
+        assertEquals(o.a, null);
+        assertEquals(o.b, null);
+        //not allowed
+        boolean succeededWhenShouldntHave = false;
+        try {
+            FlagUtils.setFieldsFromFlags(MutableMap.of("b", null), o);
+            succeededWhenShouldntHave = true;
+        } catch (IllegalArgumentException e) {
+            //expected
+        }
+        assertFalse(succeededWhenShouldntHave);
+        assertEquals(o.b, null);
+    }
+    
+    @Test
+    public void testGetAnnotatedFields() throws Exception {
+        Map<Field, SetFromFlag> fm = FlagUtils.getAnnotatedFields(WithImmutableNonNullableObject.class);
+        assertEquals(fm.keySet().size(), 2);
+        assertTrue(fm.get(WithImmutableNonNullableObject.class.getDeclaredField("b")).immutable());
+    }
+
+    @Test
+    public void testCheckRequired() {
+        WithImmutableNonNullableObject f = new WithImmutableNonNullableObject();
+        FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a is a"), f);
+        assertEquals(f.a, "a is a");
+        assertEquals(f.b, null);
+        int exceptions = 0;
+        try {
+            FlagUtils.checkRequiredFields(f);
+        } catch (IllegalStateException e) {
+            exceptions++;
+        }
+        assertEquals(exceptions, 1);
+    }
+
+    @Test
+    public void testSetConfigKeys() {
+        FooCK f = new FooCK();
+        Map<?,?> unused = FlagUtils.setFieldsFromFlags(ImmutableMap.of("f1", 9, "ck1", "do-set", "ck2", "dont-set", "c3", "do-set"), f);
+        assertEquals(f.bag.get(FooCK.CK1), "do-set");
+        assertEquals(f.bag.get(FooCK.CK3), "do-set");
+        assertEquals(f.f1, 9);
+        assertEquals(f.bag.containsKey(FooCK.CK2), false);
+        assertEquals(unused, ImmutableMap.of("ck2", "dont-set"));
+    }
+    
+    @Test
+    public void testSetAllConfigKeys() {
+        FooCK f = new FooCK();
+        Map<?,?> unused = FlagUtils.setAllConfigKeys(ImmutableMap.of("f1", 9, "ck1", "do-set", "ck2", "do-set-2", "c3", "do-set"), f, true);
+        assertEquals(f.bag.get(FooCK.CK1), "do-set");
+        assertEquals(f.bag.get(FooCK.CK3), "do-set");
+        assertEquals(f.bag.containsKey(FooCK.CK2), true);
+        assertEquals(f.bag.get(FooCK.CK2), "do-set-2");
+        assertEquals(unused, ImmutableMap.of("f1", 9));
+    }
+
+    @Test
+    public void testSetFromConfigKeys() {
+        FooCK f = new FooCK();
+        Map<?, ?> unused = FlagUtils.setFieldsFromFlags(ImmutableMap.of(new BasicConfigKey<Integer>(Integer.class, "f1"), 9, "ck1", "do-set", "ck2", "dont-set"), f);
+        assertEquals(f.bag.get(FooCK.CK1), "do-set");
+        assertEquals(f.f1, 9);
+        assertEquals(f.bag.containsKey(FooCK.CK2), false);
+        assertEquals(unused, ImmutableMap.of("ck2", "dont-set"));
+    }
+
+    public static class Foo {
+        @SetFromFlag
+        int w;
+        
+        @SetFromFlag(immutable=true)
+        private int x;
+        
+        @SetFromFlag("y")
+        public int yNotY;
+    }
+    
+    public static interface Bar {
+        static final String Z = "myzval";
+    }
+    
+    public static class Baz extends Foo implements Bar {
+        @SuppressWarnings("unused")  //inspected by reflection
+        private static int A;
+    }
+    
+    public static class WithImmutableNonNullableObject {
+        @SetFromFlag
+        Object a;
+        @SetFromFlag(immutable=true, nullable=false)
+        public Object b;
+    }
+    
+    public static class WithSpecialFieldTypes {
+        @SetFromFlag Set<?> set;
+        @SetFromFlag InetAddress inet;
+    }
+    
+    public static class FooCK implements Configurable {
+        @SetFromFlag
+        public static ConfigKey<String> CK1 = ConfigKeys.newStringConfigKey("ck1");
+        
+        public static ConfigKey<String> CK2 = ConfigKeys.newStringConfigKey("ck2");
+
+        @SetFromFlag("c3")
+        public static ConfigKey<String> CK3 = ConfigKeys.newStringConfigKey("ck3");
+
+        @SetFromFlag
+        int f1;
+        
+        ConfigBag bag = new ConfigBag();
+        BasicConfigurationSupport configSupport = new BasicConfigurationSupport();
+        
+        @Override
+        public ConfigurationSupport config() {
+            return configSupport;
+        }
+        
+        public <T> T setConfig(ConfigKey<T> key, T val) {
+            return config().set(key, val);
+        }
+        
+        private class BasicConfigurationSupport implements ConfigurationSupport {
+            @Override
+            public <T> T get(ConfigKey<T> key) {
+                return bag.get(key);
+            }
+
+            @Override
+            public <T> T get(HasConfigKey<T> key) {
+                return get(key.getConfigKey());
+            }
+
+            @Override
+            public <T> T set(ConfigKey<T> key, T val) {
+                T old = bag.get(key);
+                bag.configure(key, val);
+                return old;
+            }
+
+            @Override
+            public <T> T set(HasConfigKey<T> key, T val) {
+                return set(key.getConfigKey(), val);
+            }
+
+            @Override
+            public <T> T set(ConfigKey<T> key, Task<T> val) {
+                throw new UnsupportedOperationException();
+            }
+
+            @Override
+            public <T> T set(HasConfigKey<T> key, Task<T> val) {
+                return set(key.getConfigKey(), val);
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/RepeaterTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/RepeaterTest.groovy b/core/src/test/java/org/apache/brooklyn/core/util/internal/RepeaterTest.groovy
new file mode 100644
index 0000000..08ef0da
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/RepeaterTest.groovy
@@ -0,0 +1,257 @@
+/*
+ * 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.util.internal
+
+import static java.util.concurrent.TimeUnit.*
+import static org.testng.Assert.*
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit
+
+import org.apache.brooklyn.core.util.internal.Repeater;
+import org.testng.annotations.Test
+
+import brooklyn.util.internal.TimeExtras;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Stopwatch
+
+public class RepeaterTest {
+    static { TimeExtras.init() }
+
+    @Test
+    public void sanityTest() {
+        new Repeater("Sanity test")
+            .repeat()
+            .until { true }
+            .every(10 * MILLISECONDS);
+    }
+
+    @Test
+    public void sanityTestDescription() {
+        new Repeater()
+            .repeat()
+            .until { true }
+            .every(10 * MILLISECONDS);
+    }
+
+    @Test
+    public void sanityTestBuilder() {
+        Repeater.create("Sanity test")
+            .repeat()
+            .until { true }
+            .every(10 * MILLISECONDS);
+    }
+
+    @Test
+    public void sanityTestBuilderDescription() {
+        Repeater.create()
+            .repeat()
+            .until { true }
+            .every(10 * MILLISECONDS);
+    }
+
+    @Test(expectedExceptions = [ NullPointerException.class ])
+    public void repeatFailsIfClosureIsNull() {
+        new Repeater("repeatFailsIfClosureIsNull").repeat((Callable<?>)null);
+        fail "Expected exception was not thrown"
+    }
+
+    @Test
+    public void repeatSucceedsIfClosureIsNonNull() {
+        new Repeater("repeatSucceedsIfClosureIsNonNull").repeat { true };
+    }
+
+    @Test(expectedExceptions = [ NullPointerException.class ])
+    public void untilFailsIfClosureIsNull() {
+        new Repeater("untilFailsIfClosureIsNull").until(null);
+        fail "Expected exception was not thrown"
+    }
+
+    @Test
+    public void untilSucceedsIfClosureIsNonNull() {
+        new Repeater("untilSucceedsIfClosureIsNonNull").until { true };
+    }
+
+    @Test(expectedExceptions = [ IllegalArgumentException.class ])
+    public void everyFailsIfPeriodIsZero() {
+        new Repeater("everyFailsIfPeriodIsZero").every(0 * MILLISECONDS);
+        fail "Expected exception was not thrown"
+    }
+
+    @Test(expectedExceptions = [ IllegalArgumentException.class ])
+    public void everyFailsIfPeriodIsNegative() {
+        new Repeater("everyFailsIfPeriodIsNegative").every(-1 * MILLISECONDS);
+        fail "Expected exception was not thrown"
+    }
+
+    @Test(expectedExceptions = [ NullPointerException.class ])
+    public void everyFailsIfUnitsIsNull() {
+        new Repeater("everyFailsIfUnitsIsNull").every(10, null);
+        fail "Expected exception was not thrown"
+    }
+
+    @Test
+    public void everySucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
+        new Repeater("repeatSucceedsIfClosureIsNonNull").every(10 * MILLISECONDS);
+    }
+
+    @Test(expectedExceptions = [ IllegalArgumentException.class ])
+    public void limitTimeToFailsIfPeriodIsZero() {
+        new Repeater("limitTimeToFailsIfPeriodIsZero").limitTimeTo(0, TimeUnit.MILLISECONDS);
+        fail "Expected exception was not thrown"
+    }
+
+    @Test(expectedExceptions = [ IllegalArgumentException.class ])
+    public void limitTimeToFailsIfPeriodIsNegative() {
+        new Repeater("limitTimeToFailsIfPeriodIsNegative").limitTimeTo(-1, TimeUnit.MILLISECONDS);
+        fail "Expected exception was not thrown"
+    }
+
+    @Test(expectedExceptions = [ NullPointerException.class ])
+    public void limitTimeToFailsIfUnitsIsNull() {
+        new Repeater("limitTimeToFailsIfUnitsIsNull").limitTimeTo(10, null);
+        fail "Expected exception was not thrown"
+    }
+
+    @Test
+    public void limitTimeToSucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
+        new Repeater("limitTimeToSucceedsIfClosureIsNonNull").limitTimeTo(10, TimeUnit.MILLISECONDS);
+    }
+
+    @Test
+    public void everyAcceptsDuration() {
+        new Repeater("everyAcceptsDuration").every(Duration.ONE_SECOND);
+    }
+
+    @Test
+    public void everyAcceptsLong() {
+        new Repeater("everyAcceptsLong").every(1000L);
+    }
+
+    @Test
+    public void everyAcceptsTimeUnit() {
+        new Repeater("everyAcceptsTimeUnit").every(1000000L, TimeUnit.MICROSECONDS);
+    }
+
+    @Test
+    public void runReturnsTrueIfExitConditionIsTrue() {
+        assertTrue new Repeater("runReturnsTrueIfExitConditionIsTrue")
+            .repeat()
+            .every(1 * MILLISECONDS)
+            .until { true }
+            .run();
+    }
+
+    @Test
+    public void runRespectsMaximumIterationLimitAndReturnsFalseIfReached() {
+        int iterations = 0;
+        assertFalse new Repeater("runRespectsMaximumIterationLimitAndReturnsFalseIfReached")
+            .repeat { iterations++ }
+            .every(1 * MILLISECONDS)
+            .until { false }
+            .limitIterationsTo(5)
+            .run();
+        assertEquals 5, iterations;
+    }
+
+    /**
+     * Check that the {@link Repeater} will stop after a time limit.
+     *
+     * The repeater is configured to run every 100ms and never stop until the limit is reached.
+     * This is given as {@link Repeater#limitTimeTo(groovy.time.Duration)} and the execution time
+     * is then checked to ensure it is between 100% and 400% of the specified value. Due to scheduling
+     * delays and other factors in a non RTOS system it is expected that the repeater will take much
+     * longer to exit occasionally.
+     *
+     * @see #runRespectsMaximumIterationLimitAndReturnsFalseIfReached()
+     */
+    @Test(groups="Integration")
+    public void runRespectsTimeLimitAndReturnsFalseIfReached() {
+        final long LIMIT = 2000l;
+        Repeater repeater = new Repeater("runRespectsTimeLimitAndReturnsFalseIfReached")
+            .repeat()
+            .every(100 * MILLISECONDS)
+            .until { false }
+            .limitTimeTo(LIMIT, TimeUnit.MILLISECONDS);
+
+        Stopwatch stopwatch = new Stopwatch().start();
+        boolean result = repeater.run();
+        stopwatch.stop();
+
+        assertFalse result;
+
+        long difference = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+        assertTrue(difference >= LIMIT, "Difference was: " + difference);
+        assertTrue(difference < 4 * LIMIT, "Difference was: " + difference);
+    }
+
+    @Test(expectedExceptions = [ IllegalStateException.class ])
+    public void runFailsIfUntilWasNotSet() {
+        new Repeater("runFailsIfUntilWasNotSet")
+            .repeat()
+            .every(10 * MILLISECONDS)
+            .run();
+        fail "Expected exception was not thrown"
+    }
+
+    @Test(expectedExceptions = [ IllegalStateException.class ])
+    public void runFailsIfEveryWasNotSet() {
+        new Repeater("runFailsIfEveryWasNotSet")
+            .repeat()
+            .until { true }
+            .run();
+        fail "Expected exception was not thrown"
+    }
+
+    @Test(expectedExceptions = [ UnsupportedOperationException.class ])
+    public void testRethrowsException() {
+        boolean result = new Repeater("throwRuntimeException")
+            .repeat()
+            .every(10 * MILLISECONDS)
+            .until { throw new UnsupportedOperationException("fail") }
+            .rethrowException()
+            .limitIterationsTo(2)
+            .run();
+        fail "Expected exception was not thrown"
+    }
+
+    @Test
+    public void testNoRethrowsException() {
+        try {
+	        boolean result = new Repeater("throwRuntimeException")
+	            .repeat()
+	            .every(10 * MILLISECONDS)
+	            .until { throw new UnsupportedOperationException("fail") }
+	            .limitIterationsTo(2)
+	            .run();
+	        assertFalse result
+        } catch (RuntimeException re) {
+            fail "Exception should not have been thrown: " + re.getMessage()
+        }
+    }
+	
+	public void testFlags() {
+		int count=0;
+		new Repeater(period: 5*MILLISECONDS, timeout: 100*MILLISECONDS).repeat({ count++ }).until({ count>100}).run();
+		assertTrue count>10
+		assertTrue count<30
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/TypeCoercionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/TypeCoercionsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/TypeCoercionsTest.java
new file mode 100644
index 0000000..f1bb3f9
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/TypeCoercionsTest.java
@@ -0,0 +1,360 @@
+/*
+ * 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.util.internal;
+
+import static org.testng.Assert.assertEquals;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.core.util.flags.ClassCoercionException;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.codehaus.groovy.runtime.GStringImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.Lifecycle;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.text.StringPredicates;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.reflect.TypeToken;
+
+public class TypeCoercionsTest {
+
+    private static final Logger log = LoggerFactory.getLogger(TypeCoercionsTest.class);
+    
+    @Test
+    public void testCoerceCharSequenceToString() {
+        assertEquals(TypeCoercions.coerce(new StringBuilder("abc"), String.class), "abc");
+        assertEquals(TypeCoercions.coerce(new GStringImpl(new Object[0], new String[0]), String.class), "");
+    }
+    
+    @Test
+    public void testCoerceStringToPrimitive() {
+        assertEquals(TypeCoercions.coerce("1", Character.class), (Character)'1');
+        assertEquals(TypeCoercions.coerce(" ", Character.class), (Character)' ');
+        assertEquals(TypeCoercions.coerce("1", Short.class), (Short)((short)1));
+        assertEquals(TypeCoercions.coerce("1", Integer.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce("1", Long.class), (Long)1l);
+        assertEquals(TypeCoercions.coerce("1", Float.class), (Float)1f);
+        assertEquals(TypeCoercions.coerce("1", Double.class), (Double)1d);
+        assertEquals(TypeCoercions.coerce("true", Boolean.class), (Boolean)true);
+        assertEquals(TypeCoercions.coerce("False", Boolean.class), (Boolean)false);
+        assertEquals(TypeCoercions.coerce("true ", Boolean.class), (Boolean)true);
+
+        assertEquals(TypeCoercions.coerce("1", char.class), (Character)'1');
+        assertEquals(TypeCoercions.coerce("1", short.class), (Short)((short)1));
+        assertEquals(TypeCoercions.coerce("1", int.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce("1", long.class), (Long)1l);
+        assertEquals(TypeCoercions.coerce("1", float.class), (Float)1f);
+        assertEquals(TypeCoercions.coerce("1", double.class), (Double)1d);
+        assertEquals(TypeCoercions.coerce("TRUE", boolean.class), (Boolean)true);
+        assertEquals(TypeCoercions.coerce("false", boolean.class), (Boolean)false);
+    }
+
+    @Test
+    public void testCoercePrimitivesToSameType() {
+        assertEquals(TypeCoercions.coerce('1', Character.class), (Character)'1');
+        assertEquals(TypeCoercions.coerce((short)1, Short.class), (Short)((short)1));
+        assertEquals(TypeCoercions.coerce(1, Integer.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce(1l, Long.class), (Long)1l);
+        assertEquals(TypeCoercions.coerce(1f, Float.class), (Float)1f);
+        assertEquals(TypeCoercions.coerce(1d, Double.class), (Double)1d);
+        assertEquals(TypeCoercions.coerce(true, Boolean.class), (Boolean)true);
+    }
+    
+    @Test
+    public void testCastPrimitives() {
+        assertEquals(TypeCoercions.coerce(1L, Character.class), (Character)(char)1);
+        assertEquals(TypeCoercions.coerce(1L, Byte.class), (Byte)(byte)1);
+        assertEquals(TypeCoercions.coerce(1L, Short.class), (Short)(short)1);
+        assertEquals(TypeCoercions.coerce(1L, Integer.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce(1L, Long.class), (Long)(long)1);
+        assertEquals(TypeCoercions.coerce(1L, Float.class), (Float)(float)1);
+        assertEquals(TypeCoercions.coerce(1L, Double.class), (Double)(double)1);
+        
+        assertEquals(TypeCoercions.coerce(1L, char.class), (Character)(char)1);
+        assertEquals(TypeCoercions.coerce(1L, byte.class), (Byte)(byte)1);
+        assertEquals(TypeCoercions.coerce(1L, short.class), (Short)(short)1);
+        assertEquals(TypeCoercions.coerce(1L, int.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce(1L, long.class), (Long)(long)1);
+        assertEquals(TypeCoercions.coerce(1L, float.class), (Float)(float)1);
+        assertEquals(TypeCoercions.coerce(1L, double.class), (Double)(double)1);
+        
+        assertEquals(TypeCoercions.coerce((char)1, Integer.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce((byte)1, Integer.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce((short)1, Integer.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce((int)1, Integer.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce((long)1, Integer.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce((float)1, Integer.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce((double)1, Integer.class), (Integer)1);
+    }
+    
+    @Test
+    public void testCoercePrimitiveFailures() {
+        // error messages don't have to be this exactly, but they should include sufficient information...
+        assertCoercionFailsWithErrorMatching("maybe", boolean.class, StringPredicates.containsAllLiterals("String", "boolean", "maybe"));
+        assertCoercionFailsWithErrorMatching("NaN", int.class, StringPredicates.containsAllLiterals("int", "NaN"));
+        assertCoercionFailsWithErrorMatching('c', boolean.class, StringPredicates.containsAllLiterals("boolean", "(c)"));  // will say 'string' rather than 'char'
+        assertCoercionFailsWithErrorMatching(0, boolean.class, StringPredicates.containsAllLiterals("Integer", "boolean", "0"));
+    }
+    
+    protected void assertCoercionFailsWithErrorMatching(Object input, Class<?> type, Predicate<? super String> errorMessageRequirement) {
+        try {
+            Object result = TypeCoercions.coerce(input, type);
+            Assert.fail("Should have failed type coercion of "+input+" to "+type+", instead got: "+result);
+        } catch (Exception e) {
+            if (errorMessageRequirement==null || errorMessageRequirement.apply(e.toString()))
+                log.info("Primitive coercion failed as expected, with: "+e);
+            else
+                Assert.fail("Error from type coercion of "+input+" to "+type+" failed with wrong exception; expected match of "+errorMessageRequirement+" but got: "+e);
+        }
+        
+    }
+
+    @Test
+    public void testCastToNumericPrimitives() {
+        assertEquals(TypeCoercions.coerce(BigInteger.ONE, Integer.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce(BigInteger.ONE, int.class), (Integer)1);
+        assertEquals(TypeCoercions.coerce(BigInteger.valueOf(Long.MAX_VALUE), Long.class), (Long)Long.MAX_VALUE);
+        assertEquals(TypeCoercions.coerce(BigInteger.valueOf(Long.MAX_VALUE), long.class), (Long)Long.MAX_VALUE);
+        
+        assertEquals(TypeCoercions.coerce(BigDecimal.valueOf(0.5), Double.class), 0.5d, 0.00001d);
+        assertEquals(TypeCoercions.coerce(BigDecimal.valueOf(0.5), double.class), 0.5d, 0.00001d);
+    }
+
+    @Test
+    public void testCoerceStringToBigNumber() {
+    	assertEquals(TypeCoercions.coerce("0.5", BigDecimal.class), BigDecimal.valueOf(0.5));
+    	assertEquals(TypeCoercions.coerce("1", BigInteger.class), BigInteger.valueOf(1));
+    }
+
+    @Test
+    public void testCoerceStringToEnum() {
+        assertEquals(TypeCoercions.coerce("STARTING", Lifecycle.class), Lifecycle.STARTING);
+        assertEquals(TypeCoercions.coerce("Starting", Lifecycle.class), Lifecycle.STARTING);
+        assertEquals(TypeCoercions.coerce("starting", Lifecycle.class), Lifecycle.STARTING);
+        
+        assertEquals(TypeCoercions.coerce("LOWERCASE", PerverseEnum.class), PerverseEnum.lowercase);
+        assertEquals(TypeCoercions.coerce("CAMELCASE", PerverseEnum.class), PerverseEnum.camelCase);
+        assertEquals(TypeCoercions.coerce("upper", PerverseEnum.class), PerverseEnum.UPPER);
+        assertEquals(TypeCoercions.coerce("upper_with_underscore", PerverseEnum.class), PerverseEnum.UPPER_WITH_UNDERSCORE);
+        assertEquals(TypeCoercions.coerce("LOWER_WITH_UNDERSCORE", PerverseEnum.class), PerverseEnum.lower_with_underscore);
+    }
+    public static enum PerverseEnum {
+        lowercase,
+        camelCase,
+        UPPER,
+        UPPER_WITH_UNDERSCORE,
+        lower_with_underscore;
+    }
+    
+    @Test(expectedExceptions = ClassCoercionException.class)
+    public void testCoerceStringToEnumFailure() {
+        TypeCoercions.coerce("scrambled-eggs", Lifecycle.class);
+    }
+
+    @Test
+    public void testListToSetCoercion() {
+        Set<?> s = TypeCoercions.coerce(ImmutableList.of(1), Set.class);
+        Assert.assertEquals(s, ImmutableSet.of(1));
+    }
+    
+    @Test
+    public void testSetToListCoercion() {
+        List<?> s = TypeCoercions.coerce(ImmutableSet.of(1), List.class);
+        Assert.assertEquals(s, ImmutableList.of(1));
+    }
+    
+    @Test
+    public void testIterableToArrayCoercion() {
+        String[] s = TypeCoercions.coerce(ImmutableList.of("a", "b"), String[].class);
+        Assert.assertTrue(Arrays.equals(s, new String[] {"a", "b"}), "result="+Arrays.toString(s));
+        
+        Integer[] i = TypeCoercions.coerce(ImmutableList.of(1, 2), Integer[].class);
+        Assert.assertTrue(Arrays.equals(i, new Integer[] {1, 2}), "result="+Arrays.toString(i));
+        
+        int[] i2 = TypeCoercions.coerce(ImmutableList.of(1, 2), int[].class);
+        Assert.assertTrue(Arrays.equals(i2, new int[] {1, 2}), "result="+Arrays.toString(i2));
+        
+        int[] i3 = TypeCoercions.coerce(MutableSet.of("1", 2), int[].class);
+        Assert.assertTrue(Arrays.equals(i3, new int[] {1, 2}), "result="+Arrays.toString(i3));
+    }
+
+    @Test
+    public void testListEntryCoercion() {
+        List<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", "java.lang.Double"), new TypeToken<List<Class<?>>>() { });
+        Assert.assertEquals(s, ImmutableList.of(Integer.class, Double.class));
+    }
+    
+    @Test
+    public void testListEntryToSetCoercion() {
+        Set<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", "java.lang.Double"), new TypeToken<Set<Class<?>>>() { });
+        Assert.assertEquals(s, ImmutableSet.of(Integer.class, Double.class));
+    }
+    
+    @Test
+    public void testListEntryToCollectionCoercion() {
+        Collection<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", "java.lang.Double"), new TypeToken<Collection<Class<?>>>() { });
+        Assert.assertEquals(s, ImmutableList.of(Integer.class, Double.class));
+    }
+
+    @Test
+    public void testMapValueCoercion() {
+        Map<?,?> s = TypeCoercions.coerce(ImmutableMap.of("int", "java.lang.Integer", "double", "java.lang.Double"), new TypeToken<Map<String, Class<?>>>() { });
+        Assert.assertEquals(s, ImmutableMap.of("int", Integer.class, "double", Double.class));
+    }
+    
+    @Test
+    public void testMapKeyCoercion() {
+        Map<?,?> s = TypeCoercions.coerce(ImmutableMap.of("java.lang.Integer", "int", "java.lang.Double", "double"), new TypeToken<Map<Class<?>, String>>() { });
+        Assert.assertEquals(s, ImmutableMap.of(Integer.class, "int", Double.class, "double"));
+    }
+
+    @Test
+    public void testStringToListCoercion() {
+        List<?> s = TypeCoercions.coerce("a,b,c", List.class);
+        Assert.assertEquals(s, ImmutableList.of("a", "b", "c"));
+    }
+
+    @Test
+    @SuppressWarnings("serial")
+    public void testCoerceRecursivelyStringToGenericsCollection() {
+        assertEquals(TypeCoercions.coerce("1,2", new TypeToken<List<Integer>>() {}), ImmutableList.of(1, 2));
+    }
+    
+    @Test
+    public void testJsonStringToMapCoercion() {
+        Map<?,?> s = TypeCoercions.coerce("{ \"a\" : \"1\", b : 2 }", Map.class);
+        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
+    }
+
+    @Test
+    public void testJsonStringWithoutQuotesToMapCoercion() {
+        Map<?,?> s = TypeCoercions.coerce("{ a : 1 }", Map.class);
+        Assert.assertEquals(s, ImmutableMap.of("a", 1));
+    }
+
+    @Test
+    public void testJsonComplexTypesToMapCoercion() {
+        Map<?,?> s = TypeCoercions.coerce("{ a : [1, \"2\", '\"3\"'], b: { c: d, 'e': \"f\" } }", Map.class);
+        Assert.assertEquals(s, ImmutableMap.of("a", ImmutableList.<Object>of(1, "2", "\"3\""), 
+            "b", ImmutableMap.of("c", "d", "e", "f")));
+    }
+
+    @Test
+    public void testJsonStringWithoutBracesToMapCoercion() {
+        Map<?,?> s = TypeCoercions.coerce("a : 1", Map.class);
+        Assert.assertEquals(s, ImmutableMap.of("a", 1));
+    }
+
+    @Test
+    public void testJsonStringWithoutBracesWithMultipleToMapCoercion() {
+        Map<?,?> s = TypeCoercions.coerce("a : 1, b : 2", Map.class);
+        Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", 2));
+    }
+
+    @Test
+    public void testKeyEqualsValueStringToMapCoercion() {
+        Map<?,?> s = TypeCoercions.coerce("a=1,b=2", Map.class);
+        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", "2"));
+    }
+
+    @Test(expectedExceptions=IllegalArgumentException.class)
+    public void testJsonStringWithoutBracesOrSpaceDisallowedAsMapCoercion() {
+        // yaml requires spaces after the colon
+        Map<?,?> s = TypeCoercions.coerce("a:1,b:2", Map.class);
+        Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", 2));
+    }
+    
+    @Test
+    public void testEqualsInBracesMapCoercion() {
+        Map<?,?> s = TypeCoercions.coerce("{ a = 1, b = '2' }", Map.class);
+        Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", "2"));
+    }
+
+    @Test
+    public void testKeyEqualsOrColonValueWithBracesStringToMapCoercion() {
+        Map<?,?> s = TypeCoercions.coerce("{ a=1, b: 2 }", Map.class);
+        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
+    }
+
+    @Test
+    public void testKeyEqualsOrColonValueWithoutBracesStringToMapCoercion() {
+        Map<?,?> s = TypeCoercions.coerce("a=1, b: 2", Map.class);
+        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
+    }
+
+    @Test
+    public void testAs() {
+        Integer x = TypeCoercions.coerce(new WithAs("3"), Integer.class);
+        Assert.assertEquals(x, (Integer)3);
+    }
+
+    @Test
+    public void testFrom() {
+        WithFrom x = TypeCoercions.coerce("3", WithFrom.class);
+        Assert.assertEquals(x.value, 3);
+    }
+
+    @Test
+    public void testCoerceStringToNumber() {
+        assertEquals(TypeCoercions.coerce("1", Number.class), (Number) Double.valueOf(1));
+        assertEquals(TypeCoercions.coerce("1.0", Number.class), (Number) Double.valueOf(1.0));
+    }
+
+    @Test(expectedExceptions = ClassCoercionException.class)
+    public void testInvalidCoercionThrowsClassCoercionException() {
+        TypeCoercions.coerce(new Object(), TypeToken.of(Integer.class));
+    }
+
+    @Test
+    public void testCoercionFunction() {
+        assertEquals(TypeCoercions.function(Double.class).apply("1"), Double.valueOf(1));
+    }
+
+    public static class WithAs {
+        String value;
+        public WithAs(Object x) { value = ""+x; }
+        public Integer asInteger() {
+            return Integer.parseInt(value);
+        }
+    }
+
+    public static class WithFrom {
+        int value;
+        public static WithFrom fromString(String s) {
+            WithFrom result = new WithFrom();
+            result.value = Integer.parseInt(s);
+            return result;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/RecordingSshTool.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/RecordingSshTool.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/RecordingSshTool.java
new file mode 100644
index 0000000..fdf3e73
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/RecordingSshTool.java
@@ -0,0 +1,97 @@
+/*
+ * 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.util.internal.ssh;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+/** Mock tool */
+public class RecordingSshTool implements SshTool {
+    
+    public static class ExecCmd {
+        public final Map<String,?> props;
+        public final String summaryForLogging;
+        public final List<String> commands;
+        public final Map<?,?> env;
+        
+        ExecCmd(Map<String,?> props, String summaryForLogging, List<String> commands, Map env) {
+            this.props = props;
+            this.summaryForLogging = summaryForLogging;
+            this.commands = commands;
+            this.env = env;
+        }
+        
+        @Override
+        public String toString() {
+            return "ExecCmd["+summaryForLogging+": "+commands+"; "+props+"; "+env+"]";
+        }
+    }
+    
+    public static List<ExecCmd> execScriptCmds = Lists.newCopyOnWriteArrayList();
+    
+    private boolean connected;
+    
+    public RecordingSshTool(Map<?,?> props) {
+    }
+    @Override public void connect() {
+        connected = true;
+    }
+    @Override public void connect(int maxAttempts) {
+        connected = true;
+    }
+    @Override public void disconnect() {
+        connected = false;
+    }
+    @Override public boolean isConnected() {
+        return connected;
+    }
+    @Override public int execScript(Map<String, ?> props, List<String> commands, Map<String, ?> env) {
+        execScriptCmds.add(new ExecCmd(props, "", commands, env));
+        return 0;
+    }
+    @Override public int execScript(Map<String, ?> props, List<String> commands) {
+        return execScript(props, commands, ImmutableMap.<String,Object>of());
+    }
+    @Override public int execCommands(Map<String, ?> props, List<String> commands, Map<String, ?> env) {
+        execScriptCmds.add(new ExecCmd(props, "", commands, env));
+        return 0;
+    }
+    @Override public int execCommands(Map<String, ?> props, List<String> commands) {
+        return execCommands(props, commands, ImmutableMap.<String,Object>of());
+    }
+    @Override public int copyToServer(Map<String, ?> props, File localFile, String pathAndFileOnRemoteServer) {
+        return 0;
+    }
+    @Override public int copyToServer(Map<String, ?> props, InputStream contents, String pathAndFileOnRemoteServer) {
+        return 0;
+    }
+    @Override public int copyToServer(Map<String, ?> props, byte[] contents, String pathAndFileOnRemoteServer) {
+        return 0;
+    }
+    @Override public int copyFromServer(Map<String, ?> props, String pathAndFileOnRemoteServer, File local) {
+        return 0;
+    }
+}
\ No newline at end of file


[57/64] incubator-brooklyn git commit: brooklyn-software-database: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..3dc26cc
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlCluster.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.entity.database.mysql;
+
+import java.util.Collection;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.event.AttributeSensor;
+
+import com.google.common.reflect.TypeToken;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import org.apache.brooklyn.entity.database.DatastoreMixins.HasDatastoreUrl;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+
+@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")
+public interface MySqlCluster extends DynamicCluster, HasDatastoreUrl {
+    interface MySqlMaster {
+        AttributeSensor<String> MASTER_LOG_FILE = Sensors.newStringSensor("mysql.master.log_file", "The binary log file master is writing to");
+        AttributeSensor<Integer> MASTER_LOG_POSITION = Sensors.newIntegerSensor("mysql.master.log_position", "The position in the log file to start replication");
+    }
+    interface MySqlSlave {
+        AttributeSensor<Boolean> SLAVE_HEALTHY = Sensors.newBooleanSensor("mysql.slave.healthy", "Indicates that the replication state of the slave is healthy");
+        AttributeSensor<Integer> SLAVE_SECONDS_BEHIND_MASTER = Sensors.newIntegerSensor("mysql.slave.seconds_behind_master", "How many seconds behind master is the replication state on the slave");
+    }
+
+    ConfigKey<String> SLAVE_USERNAME = ConfigKeys.newStringConfigKey(
+            "mysql.slave.username", "The user name slaves will use to connect to the master", "slave");
+    ConfigKey<String> SLAVE_REPLICATE_DO_DB = ConfigKeys.newStringConfigKey(
+            "mysql.slave.replicate_do_db", "Replicate only listed DBs");
+    ConfigKey<String> SLAVE_REPLICATE_IGNORE_DB = ConfigKeys.newStringConfigKey(
+            "mysql.slave.replicate_ignore_db", "Don't replicate listed DBs");
+    ConfigKey<String> SLAVE_REPLICATE_DO_TABLE = ConfigKeys.newStringConfigKey(
+            "mysql.slave.replicate_do_table", "Replicate only listed tables");
+    ConfigKey<String> SLAVE_REPLICATE_IGNORE_TABLE = ConfigKeys.newStringConfigKey(
+            "mysql.slave.replicate_ignore_table", "Don't replicate listed tables");
+    ConfigKey<String> SLAVE_REPLICATE_WILD_DO_TABLE = ConfigKeys.newStringConfigKey(
+            "mysql.slave.replicate_wild_do_table", "Replicate only listed tables, wildcards acepted");
+    ConfigKey<String> SLAVE_REPLICATE_WILD_IGNORE_TABLE = ConfigKeys.newStringConfigKey(
+            "mysql.slave.replicate_wild_ignore_table", "Don't replicate listed tables, wildcards acepted");
+    StringAttributeSensorAndConfigKey SLAVE_PASSWORD = new StringAttributeSensorAndConfigKey(
+            "mysql.slave.password", "The password slaves will use to connect to the master. Will be auto-generated by default.");
+    @SuppressWarnings("serial")
+    AttributeSensor<Collection<String>> SLAVE_DATASTORE_URL_LIST = Sensors.newSensor(new TypeToken<Collection<String>>() {},
+            "mysql.slave.datastore.url", "List of all slave's DATASTORE_URL sensors");
+    AttributeSensor<Double> QUERIES_PER_SECOND_FROM_MYSQL_PER_NODE = Sensors.newDoubleSensor("mysql.queries.perSec.fromMysql.perNode");
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..5bf6e88
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java
@@ -0,0 +1,445 @@
+/*
+ * 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.entity.database.mysql;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+
+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.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.reflect.TypeToken;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.enricher.Enrichers;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.basic.EntityPredicates;
+import brooklyn.entity.basic.ServiceStateLogic.ServiceNotUpLogic;
+import brooklyn.entity.group.DynamicClusterImpl;
+import brooklyn.event.basic.DependentConfiguration;
+import brooklyn.event.basic.Sensors;
+import brooklyn.event.feed.function.FunctionFeed;
+import brooklyn.event.feed.function.FunctionPollConfig;
+import brooklyn.util.collections.CollectionFunctionals;
+import brooklyn.util.guava.Functionals;
+import brooklyn.util.guava.IfFunctions;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.StringPredicates;
+import brooklyn.util.time.Duration;
+
+// https://dev.mysql.com/doc/refman/5.7/en/replication-howto.html
+
+// TODO CREATION_SCRIPT_CONTENTS executed before replication setup so it is not replicated to slaves
+// TODO Bootstrap slave from dump for the case where the binary log is purged
+// TODO Promote slave to master
+// TODO SSL connection between master and slave
+// TODO DB credentials littered all over the place in file system
+public class MySqlClusterImpl extends DynamicClusterImpl implements MySqlCluster {
+    private static final AttributeSensor<Boolean> NODE_REPLICATION_INITIALIZED = Sensors.newBooleanSensor("mysql.replication_initialized");
+
+    private static final String MASTER_CONFIG_URL = "classpath:///org/apache/brooklyn/entity/database/mysql/mysql_master.conf";
+    private static final String SLAVE_CONFIG_URL = "classpath:///org/apache/brooklyn/entity/database/mysql/mysql_slave.conf";
+    private static final int MASTER_SERVER_ID = 1;
+    private static final Predicate<Entity> IS_MASTER = EntityPredicates.configEqualTo(MySqlNode.MYSQL_SERVER_ID, MASTER_SERVER_ID);
+
+    @SuppressWarnings("serial")
+    private static final AttributeSensor<Supplier<Integer>> SLAVE_NEXT_SERVER_ID = Sensors.newSensor(new TypeToken<Supplier<Integer>>() {},
+            "mysql.slave.next_server_id", "Returns the ID of the next slave server");
+    @SuppressWarnings("serial")
+    private static final AttributeSensor<Map<String, String>> SLAVE_ID_ADDRESS_MAPPING = Sensors.newSensor(new TypeToken<Map<String, String>>() {},
+            "mysql.slave.id_address_mapping", "Maps slave entity IDs to SUBNET_ADDRESS, so the address is known at member remove time.");
+
+    @Override
+    public void init() {
+        super.init();
+        // Set id supplier in attribute so it is serialized
+        setAttribute(SLAVE_NEXT_SERVER_ID, new NextServerIdSupplier());
+        setAttribute(SLAVE_ID_ADDRESS_MAPPING, new ConcurrentHashMap<String, String>());
+        if (getConfig(SLAVE_PASSWORD) == null) {
+            setAttribute(SLAVE_PASSWORD, Identifiers.makeRandomId(8));
+        } else {
+            setAttribute(SLAVE_PASSWORD, getConfig(SLAVE_PASSWORD));
+        }
+        initSubscriptions();
+    }
+
+    @Override
+    public void rebind() {
+        super.rebind();
+        initSubscriptions();
+    }
+
+    private void initSubscriptions() {
+        subscribeToMembers(this, MySqlNode.SERVICE_PROCESS_IS_RUNNING, new NodeRunningListener(this));
+        subscribe(this, MEMBER_REMOVED, new MemberRemovedListener());
+    }
+
+    @Override
+    protected void initEnrichers() {
+        super.initEnrichers();
+        propagateMasterAttribute(MySqlNode.HOSTNAME);
+        propagateMasterAttribute(MySqlNode.ADDRESS);
+        propagateMasterAttribute(MySqlNode.SUBNET_HOSTNAME);
+        propagateMasterAttribute(MySqlNode.SUBNET_ADDRESS);
+        propagateMasterAttribute(MySqlNode.MYSQL_PORT);
+        propagateMasterAttribute(MySqlNode.DATASTORE_URL);
+
+        addEnricher(Enrichers.builder()
+                .aggregating(MySqlNode.DATASTORE_URL)
+                .publishing(SLAVE_DATASTORE_URL_LIST)
+                .computing(Functions.<Collection<String>>identity())
+                .entityFilter(Predicates.not(IS_MASTER))
+                .fromMembers()
+                .build());
+
+        addEnricher(Enrichers.builder()
+                .aggregating(MySqlNode.QUERIES_PER_SECOND_FROM_MYSQL)
+                .publishing(QUERIES_PER_SECOND_FROM_MYSQL_PER_NODE)
+                .fromMembers()
+                .computingAverage()
+                .defaultValueForUnreportedSensors(0d)
+                .build());
+    }
+
+    private void propagateMasterAttribute(AttributeSensor<?> att) {
+        addEnricher(Enrichers.builder()
+                .aggregating(att)
+                .publishing(att)
+                .computing(IfFunctions.ifPredicate(CollectionFunctionals.notEmpty())
+                        .apply(CollectionFunctionals.firstElement())
+                        .defaultValue(null))
+                .entityFilter(IS_MASTER)
+                .build());
+    }
+
+    @Override
+    protected EntitySpec<?> getFirstMemberSpec() {
+        final EntitySpec<?> firstMemberSpec = super.getFirstMemberSpec();
+        if (firstMemberSpec != null) {
+            return applyDefaults(firstMemberSpec, Suppliers.ofInstance(MASTER_SERVER_ID), MASTER_CONFIG_URL, false);
+        }
+
+        final EntitySpec<?> memberSpec = super.getMemberSpec();
+        if (memberSpec != null) {
+            if (!isKeyConfigured(memberSpec, MySqlNode.TEMPLATE_CONFIGURATION_URL.getConfigKey())) {
+                return EntitySpec.create(memberSpec)
+                        .configure(MySqlNode.MYSQL_SERVER_ID, MASTER_SERVER_ID)
+                        .configure(MySqlNode.TEMPLATE_CONFIGURATION_URL, MASTER_CONFIG_URL);
+            } else {
+                return memberSpec;
+            }
+        }
+
+        return EntitySpec.create(MySqlNode.class)
+                .displayName("MySql Master")
+                .configure(MySqlNode.MYSQL_SERVER_ID, MASTER_SERVER_ID)
+                .configure(MySqlNode.TEMPLATE_CONFIGURATION_URL, MASTER_CONFIG_URL);
+    }
+
+    @Override
+    protected EntitySpec<?> getMemberSpec() {
+        Supplier<Integer> serverIdSupplier = getAttribute(SLAVE_NEXT_SERVER_ID);
+
+        EntitySpec<?> spec = super.getMemberSpec();
+        if (spec != null) {
+            return applyDefaults(spec, serverIdSupplier, SLAVE_CONFIG_URL, true);
+        }
+
+        return EntitySpec.create(MySqlNode.class)
+                .displayName("MySql Slave")
+                .configure(MySqlNode.MYSQL_SERVER_ID, serverIdSupplier.get())
+                .configure(MySqlNode.TEMPLATE_CONFIGURATION_URL, SLAVE_CONFIG_URL)
+                // block inheritance, only master should execute the creation script
+                .configure(MySqlNode.CREATION_SCRIPT_URL, (String) null)
+                .configure(MySqlNode.CREATION_SCRIPT_CONTENTS, (String) null);
+    }
+
+    private EntitySpec<?> applyDefaults(EntitySpec<?> spec, Supplier<Integer> serverId, String configUrl, boolean resetCreationScript) {
+        boolean needsServerId = !isKeyConfigured(spec, MySqlNode.MYSQL_SERVER_ID);
+        boolean needsConfigUrl = !isKeyConfigured(spec, MySqlNode.TEMPLATE_CONFIGURATION_URL.getConfigKey());
+        boolean needsCreationScriptUrl = resetCreationScript && !isKeyConfigured(spec, MySqlNode.CREATION_SCRIPT_URL);
+        boolean needsCreationScriptContents = resetCreationScript && !isKeyConfigured(spec, MySqlNode.CREATION_SCRIPT_CONTENTS);
+        if (needsServerId || needsConfigUrl || needsCreationScriptUrl || needsCreationScriptContents) {
+            EntitySpec<?> clonedSpec = EntitySpec.create(spec);
+            if (needsServerId) {
+                clonedSpec.configure(MySqlNode.MYSQL_SERVER_ID, serverId.get());
+            }
+            if (needsConfigUrl) {
+                clonedSpec.configure(MySqlNode.TEMPLATE_CONFIGURATION_URL, configUrl);
+            }
+            if (needsCreationScriptUrl) {
+                clonedSpec.configure(MySqlNode.CREATION_SCRIPT_URL, (String) null);
+            }
+            if (needsCreationScriptContents) {
+                clonedSpec.configure(MySqlNode.CREATION_SCRIPT_URL, (String) null);
+            }
+            return clonedSpec;
+        } else {
+            return spec;
+        }
+    }
+
+    private boolean isKeyConfigured(EntitySpec<?> spec, ConfigKey<?> key) {
+        return spec.getConfig().containsKey(key) || spec.getFlags().containsKey(key.getName());
+    }
+
+    @Override
+    protected Entity createNode(Location loc, Map<?, ?> flags) {
+        Entity node = super.createNode(loc, flags);
+        if (!IS_MASTER.apply(node)) {
+            ServiceNotUpLogic.updateNotUpIndicator((EntityLocal)node, MySqlSlave.SLAVE_HEALTHY, "Replication not started");
+
+            addFeed(FunctionFeed.builder()
+                .entity((EntityLocal)node)
+                .period(Duration.FIVE_SECONDS)
+                .poll(FunctionPollConfig.forSensor(MySqlSlave.SLAVE_HEALTHY)
+                        .callable(new SlaveStateCallable(node))
+                        .checkSuccess(StringPredicates.isNonBlank())
+                        .onSuccess(new SlaveStateParser(node))
+                        .setOnFailure(false)
+                        .description("Polls SHOW SLAVE STATUS"))
+                .build());
+
+            node.addEnricher(Enrichers.builder().updatingMap(Attributes.SERVICE_NOT_UP_INDICATORS)
+                    .from(MySqlSlave.SLAVE_HEALTHY)
+                    .computing(Functionals.ifNotEquals(true).value("Slave replication status is not healthy") )
+                    .build());
+        }
+        return node;
+    }
+
+    public static class SlaveStateCallable implements Callable<String> {
+        private Entity slave;
+        public SlaveStateCallable(Entity slave) {
+            this.slave = slave;
+        }
+
+        @Override
+        public String call() throws Exception {
+            if (Boolean.TRUE.equals(slave.getAttribute(MySqlNode.SERVICE_PROCESS_IS_RUNNING))) {
+                return slave.invoke(MySqlNode.EXECUTE_SCRIPT, ImmutableMap.of("commands", "SHOW SLAVE STATUS \\G")).asTask().getUnchecked();
+            } else {
+                return null;
+            }
+        }
+
+    }
+
+    public static class SlaveStateParser implements Function<String, Boolean> {
+        private Entity slave;
+
+        public SlaveStateParser(Entity slave) {
+            this.slave = slave;
+        }
+
+        @Override
+        public Boolean apply(String result) {
+            Map<String, String> status = MySqlRowParser.parseSingle(result);
+            String secondsBehindMaster = status.get("Seconds_Behind_Master");
+            if (secondsBehindMaster != null && !"NULL".equals(secondsBehindMaster)) {
+                ((EntityLocal)slave).setAttribute(MySqlSlave.SLAVE_SECONDS_BEHIND_MASTER, new Integer(secondsBehindMaster));
+            }
+            return "Yes".equals(status.get("Slave_IO_Running")) && "Yes".equals(status.get("Slave_SQL_Running"));
+        }
+
+    }
+
+    private static class NextServerIdSupplier implements Supplier<Integer> {
+        private AtomicInteger nextId = new AtomicInteger(MASTER_SERVER_ID+1);
+
+        @Override
+        public Integer get() {
+            return nextId.getAndIncrement();
+        }
+    }
+
+    // ============= Member Init =============
+
+    // The task is executed in inessential context (event handler) so
+    // not visible in tasks UI. Better make it visible so the user can
+    // see failures, currently accessible only from logs.
+    private static final class InitReplicationTask implements Runnable {
+        private final MySqlCluster cluster;
+        private final MySqlNode node;
+
+        private InitReplicationTask(MySqlCluster cluster, MySqlNode node) {
+            this.cluster = cluster;
+            this.node = node;
+        }
+
+        @Override
+        public void run() {
+            Integer serverId = node.getConfig(MySqlNode.MYSQL_SERVER_ID);
+            if (serverId == MASTER_SERVER_ID) {
+                initMaster(node);
+            } else if (serverId > MASTER_SERVER_ID) {
+                initSlave(node);
+            }
+        }
+
+        private void initMaster(MySqlNode master) {
+            String binLogInfo = executeScriptOnNode(master, "FLUSH TABLES WITH READ LOCK;SHOW MASTER STATUS \\G UNLOCK TABLES;");
+            Map<String, String> status = MySqlRowParser.parseSingle(binLogInfo);
+            String file = status.get("File");
+            if (file != null) {
+                ((EntityInternal)master).setAttribute(MySqlMaster.MASTER_LOG_FILE, file);
+            }
+            String position = status.get("Position");
+            if (position != null) {
+                ((EntityInternal)master).setAttribute(MySqlMaster.MASTER_LOG_POSITION, new Integer(position));
+            }
+        }
+
+        private void initSlave(MySqlNode slave) {
+            MySqlNode master = (MySqlNode) Iterables.find(cluster.getMembers(), IS_MASTER);
+            String masterLogFile = validateSqlParam(getAttributeBlocking(master, MySqlMaster.MASTER_LOG_FILE));
+            Integer masterLogPos = getAttributeBlocking(master, MySqlMaster.MASTER_LOG_POSITION);
+            String masterAddress = validateSqlParam(master.getAttribute(MySqlNode.SUBNET_ADDRESS));
+            Integer masterPort = master.getAttribute(MySqlNode.MYSQL_PORT);
+            String slaveAddress = validateSqlParam(slave.getAttribute(MySqlNode.SUBNET_ADDRESS));
+            String username = validateSqlParam(cluster.getConfig(SLAVE_USERNAME));
+            String password = validateSqlParam(cluster.getAttribute(SLAVE_PASSWORD));
+
+            executeScriptOnNode(master, String.format(
+                    "CREATE USER '%s'@'%s' IDENTIFIED BY '%s';\n" +
+                    "GRANT REPLICATION SLAVE ON *.* TO '%s'@'%s';\n",
+                    username, slaveAddress, password, username, slaveAddress));
+
+            String slaveCmd = String.format(
+                    "CHANGE MASTER TO " +
+                        "MASTER_HOST='%s', " +
+                        "MASTER_PORT=%d, " +
+                        "MASTER_USER='%s', " +
+                        "MASTER_PASSWORD='%s', " +
+                        "MASTER_LOG_FILE='%s', " +
+                        "MASTER_LOG_POS=%d;\n" +
+                    "START SLAVE;\n",
+                    masterAddress, masterPort, username, password, masterLogFile, masterLogPos);
+            executeScriptOnNode(slave, slaveCmd);
+
+            cluster.getAttribute(SLAVE_ID_ADDRESS_MAPPING).put(slave.getId(), slave.getAttribute(MySqlNode.SUBNET_ADDRESS));
+        }
+
+        private <T> T getAttributeBlocking(Entity masterNode, AttributeSensor<T> att) {
+            return DynamicTasks.queue(DependentConfiguration.attributeWhenReady(masterNode, att)).getUnchecked();
+        }
+
+    }
+
+    private static final class NodeRunningListener implements SensorEventListener<Boolean> {
+        private MySqlCluster cluster;
+
+        public NodeRunningListener(MySqlCluster cluster) {
+            this.cluster = cluster;
+        }
+
+        @Override
+        public void onEvent(SensorEvent<Boolean> event) {
+            final MySqlNode node = (MySqlNode) event.getSource();
+            if (Boolean.TRUE.equals(event.getValue()) &&
+                    // We are interested in SERVICE_PROCESS_IS_RUNNING only while haven't come online yet.
+                    // Probably will get several updates while replication is initialized so an additional
+                    // check is needed whether we have already seen this.
+                    Boolean.FALSE.equals(node.getAttribute(MySqlNode.SERVICE_UP)) &&
+                    !Boolean.TRUE.equals(node.getAttribute(NODE_REPLICATION_INITIALIZED))) {
+
+                // Events executed sequentially so no need to synchronize here.
+                ((EntityLocal)node).setAttribute(NODE_REPLICATION_INITIALIZED, Boolean.TRUE);
+
+                DynamicTasks.queueIfPossible(TaskBuilder.builder()
+                        .name("Configure master-slave replication on node")
+                        .body(new InitReplicationTask(cluster, node))
+                        .build())
+                    .orSubmitAsync(node);
+            }
+        }
+
+    }
+
+    // ============= Member Remove =============
+
+    public class MemberRemovedListener implements SensorEventListener<Entity> {
+        @Override
+        public void onEvent(SensorEvent<Entity> event) {
+            MySqlCluster cluster = (MySqlCluster) event.getSource();
+            Entity node = event.getValue();
+            String slaveAddress = cluster.getAttribute(SLAVE_ID_ADDRESS_MAPPING).remove(node.getId());
+            if (slaveAddress != null) {
+                DynamicTasks.queueIfPossible(TaskBuilder.builder()
+                        .name("Remove slave access")
+                        .body(new RemoveSlaveConfigTask(cluster, slaveAddress))
+                        .build())
+                    .orSubmitAsync(cluster);
+            }
+        }
+    }
+
+    public class RemoveSlaveConfigTask implements Runnable {
+        private MySqlCluster cluster;
+        private String slaveAddress;
+
+        public RemoveSlaveConfigTask(MySqlCluster cluster, String slaveAddress) {
+            this.cluster = cluster;
+            this.slaveAddress = validateSqlParam(slaveAddress);
+        }
+
+        @Override
+        public void run() {
+            // Could already be gone if stopping the entire app - let it throw an exception
+            MySqlNode master = (MySqlNode) Iterables.find(cluster.getMembers(), IS_MASTER);
+            String username = validateSqlParam(cluster.getConfig(SLAVE_USERNAME));
+            executeScriptOnNode(master, String.format("DROP USER '%s'@'%s';", username, slaveAddress));
+        }
+
+    }
+
+    // Can't call node.executeScript directly, need to change execution context, so use an effector task
+    private static String executeScriptOnNode(MySqlNode node, String commands) {
+        return node.invoke(MySqlNode.EXECUTE_SCRIPT, ImmutableMap.of(MySqlNode.EXECUTE_SCRIPT_COMMANDS, commands)).getUnchecked();
+    }
+
+    private static String validateSqlParam(String config) {
+        // Don't go into escape madness, just deny any suspicious strings.
+        // Would be nice to use prepared statements, but not worth pulling in the extra dependencies.
+        if (config.contains("'") && config.contains("\\")) {
+            throw new IllegalStateException("User provided string contains illegal SQL characters: " + config);
+        }
+        return config;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlDriver.java
new file mode 100644
index 0000000..dd63ae1
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlDriver.java
@@ -0,0 +1,31 @@
+/*
+ * 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.entity.database.mysql;
+
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+
+import brooklyn.entity.basic.SoftwareProcessDriver;
+
+/**
+ * The {@link SoftwareProcessDriver} for MySQL.
+ */
+public interface MySqlDriver extends SoftwareProcessDriver {
+    public String getStatusCmd();
+    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..226d8fb
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNode.java
@@ -0,0 +1,97 @@
+/*
+ * 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.entity.database.mysql;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.entity.trait.HasShortName;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.annotation.Effector;
+import brooklyn.entity.annotation.EffectorParam;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.MethodEffector;
+import brooklyn.entity.basic.SoftwareProcess;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
+import brooklyn.event.basic.MapConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+
+import org.apache.brooklyn.location.basic.PortRanges;
+
+@Catalog(name="MySql Node", description="MySql is an open source relational database management system (RDBMS)", iconUrl="classpath:///mysql-logo-110x57.png")
+@ImplementedBy(MySqlNodeImpl.class)
+public interface MySqlNode extends SoftwareProcess, HasShortName, DatastoreCommon {
+
+    // NOTE MySQL changes the minor version number of their GA release frequently, check for latest version if install fails
+    @SetFromFlag("version")
+    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "5.6.26");
+
+    //http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.26-osx10.9-x86_64.tar.gz
+    //http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.26-linux-glibc2.5-x86_64.tar.gz
+    @SetFromFlag("downloadUrl")
+    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new StringAttributeSensorAndConfigKey(
+            Attributes.DOWNLOAD_URL, "http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-${version}-${driver.osTag}.tar.gz");
+
+    @SetFromFlag("port")
+    PortAttributeSensorAndConfigKey MYSQL_PORT = new PortAttributeSensorAndConfigKey("mysql.port", "MySQL port", PortRanges.fromString("3306, 13306+"));
+
+    @SetFromFlag("dataDir")
+    ConfigKey<String> DATA_DIR = ConfigKeys.newStringConfigKey(
+            "mysql.datadir", "Directory for writing data files", null);
+
+    @SetFromFlag("serverConf")
+    MapConfigKey<Object> MYSQL_SERVER_CONF = new MapConfigKey<Object>(
+            Object.class, "mysql.server.conf", "Configuration options for mysqld");
+    
+    ConfigKey<Object> MYSQL_SERVER_CONF_LOWER_CASE_TABLE_NAMES = MYSQL_SERVER_CONF.subKey("lower_case_table_names", "See MySQL guide. Set 1 to ignore case in table names (useful for OS portability)");
+    
+    @SetFromFlag("serverId")
+    ConfigKey<Integer> MYSQL_SERVER_ID = ConfigKeys.newIntegerConfigKey("mysql.server_id", "Corresponds to server_id option", 0);
+    
+    @SetFromFlag("password")
+    StringAttributeSensorAndConfigKey PASSWORD = new StringAttributeSensorAndConfigKey(
+            "mysql.password", "Database admin password (or randomly generated if not set)", null);
+
+    @SetFromFlag("socketUid")
+    StringAttributeSensorAndConfigKey SOCKET_UID = new StringAttributeSensorAndConfigKey(
+            "mysql.socketUid", "Socket uid, for use in file /tmp/mysql.sock.<uid>.3306 (or randomly generated if not set)", null);
+    
+    /** @deprecated since 0.7.0 use DATASTORE_URL */ @Deprecated
+    AttributeSensor<String> MYSQL_URL = DATASTORE_URL;
+
+    @SetFromFlag("configurationTemplateUrl")
+    BasicAttributeSensorAndConfigKey<String> TEMPLATE_CONFIGURATION_URL = new StringAttributeSensorAndConfigKey(
+            "mysql.template.configuration.url", "Template file (in freemarker format) for the mysql.conf file",
+            "classpath://org/apache/brooklyn/entity/database/mysql/mysql.conf");
+
+    AttributeSensor<Double> QUERIES_PER_SECOND_FROM_MYSQL = Sensors.newDoubleSensor("mysql.queries.perSec.fromMysql");
+
+    MethodEffector<String> EXECUTE_SCRIPT = new MethodEffector<String>(MySqlNode.class, "executeScript");
+    String EXECUTE_SCRIPT_COMMANDS = "commands";
+
+    @Effector(description = "Execute SQL script on the node as the root user")
+    String executeScript(@EffectorParam(name=EXECUTE_SCRIPT_COMMANDS) String commands);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..075db69
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java
@@ -0,0 +1,167 @@
+/*
+ * 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.entity.database.mysql;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.entity.effector.EffectorBody;
+import brooklyn.event.feed.ssh.SshFeed;
+import brooklyn.event.feed.ssh.SshPollConfig;
+import brooklyn.event.feed.ssh.SshPollValue;
+
+import org.apache.brooklyn.location.basic.Locations;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Function;
+
+public class MySqlNodeImpl extends SoftwareProcessImpl implements MySqlNode {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MySqlNodeImpl.class);
+
+    private SshFeed feed;
+
+    public MySqlNodeImpl() {
+    }
+
+    public MySqlNodeImpl(Entity parent) {
+        this(MutableMap.of(), parent);
+    }
+
+    public MySqlNodeImpl(Map<?,?> flags) {
+        super(flags, null);
+    }
+
+    public MySqlNodeImpl(Map<?,?> flags, Entity parent) {
+        super(flags, parent);
+    }
+
+    @Override
+    public Class<?> getDriverInterface() {
+        return MySqlDriver.class;
+    }
+
+    @Override
+    public MySqlDriver getDriver() {
+        return (MySqlDriver) super.getDriver();
+    }
+    
+    @Override
+    public void init() {
+        super.init();
+        getMutableEntityType().addEffector(EXECUTE_SCRIPT, new EffectorBody<String>() {
+            @Override
+            public String call(ConfigBag parameters) {
+                return executeScript((String)parameters.getStringKey("commands"));
+            }
+        });
+    }
+
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+        setAttribute(DATASTORE_URL, String.format("mysql://%s:%s/", getAttribute(HOSTNAME), getAttribute(MYSQL_PORT)));
+        
+        /*        
+         * TODO status gives us things like:
+         *   Uptime: 2427  Threads: 1  Questions: 581  Slow queries: 0  Opens: 53  Flush tables: 1  Open tables: 35  Queries per second avg: 0.239
+         * So can extract lots of sensors from that.
+         */
+        Maybe<SshMachineLocation> machine = Locations.findUniqueSshMachineLocation(getLocations());
+        boolean retrieveUsageMetrics = getConfig(RETRIEVE_USAGE_METRICS);
+
+        if (machine.isPresent()) {
+            String cmd = getDriver().getStatusCmd();
+            feed = SshFeed.builder()
+                    .entity(this)
+                    .period(Duration.FIVE_SECONDS)
+                    .machine(machine.get())
+                    .poll(new SshPollConfig<Double>(QUERIES_PER_SECOND_FROM_MYSQL)
+                            .command(cmd)
+                            .onSuccess(new Function<SshPollValue, Double>() {
+                                @Override
+                                public Double apply(SshPollValue input) {
+                                    String q = Strings.getFirstWordAfter(input.getStdout(), "Queries per second avg:");
+                                    if (q==null) return null;
+                                    return Double.parseDouble(q);
+                                }})
+                            .setOnFailureOrException(null)
+                            .enabled(retrieveUsageMetrics))
+                    .poll(new SshPollConfig<Boolean>(SERVICE_PROCESS_IS_RUNNING)
+                            .command(cmd)
+                            .setOnSuccess(true)
+                            .setOnFailureOrException(false)
+                            .suppressDuplicates(true))
+                    .build();
+        } else {
+            LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; setting serviceUp immediately", getLocations());
+            setAttribute(SERVICE_UP, true);
+        }
+    }
+    
+    @Override
+    protected void disconnectSensors() {
+        if (feed != null) feed.stop();
+        super.disconnectSensors();
+    }
+
+    public int getPort() {
+        return getAttribute(MYSQL_PORT);
+    }
+    
+    public String getSocketUid() {
+        String result = getAttribute(MySqlNode.SOCKET_UID);
+        if (Strings.isBlank(result)) {
+            result = Identifiers.makeRandomId(6);
+            setAttribute(MySqlNode.SOCKET_UID, result);
+        }
+        return result;
+    }
+
+    public String getPassword() {
+        String result = getAttribute(MySqlNode.PASSWORD);
+        if (Strings.isBlank(result)) {
+            result = Identifiers.makeRandomId(6);
+            setAttribute(MySqlNode.PASSWORD, result);
+        }
+        return result;
+    }
+    
+    @Override
+    public String getShortName() {
+        return "MySQL";
+    }
+
+    @Override
+    public String executeScript(String commands) {
+        return getDriver().executeScriptAsync(commands).block().getStdout();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlRowParser.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlRowParser.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlRowParser.java
new file mode 100644
index 0000000..2ae12b5
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlRowParser.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.entity.database.mysql;
+
+import java.util.Map;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.text.Strings;
+
+public class MySqlRowParser {
+    public static Map<String, String> parseSingle(String row) {
+        Map<String, String> values = MutableMap.of();
+        String[] lines = row.split("\\n");
+        for (String line : lines) {
+            if (line.startsWith("*")) continue; // row delimiter
+            String[] arr = line.split(":", 2);
+            String key = arr[0].trim();
+            String value = Strings.emptyToNull(arr[1].trim());
+            values.put(key, value);
+        }
+        return values;
+    };
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..eef77cd
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlSshDriver.java
@@ -0,0 +1,279 @@
+/*
+ * 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.entity.database.mysql;
+
+import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
+import static brooklyn.util.ssh.BashCommands.commandsToDownloadUrlsAs;
+import static brooklyn.util.ssh.BashCommands.installPackage;
+import static java.lang.String.format;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.entity.database.DatastoreMixins;
+import brooklyn.entity.software.SshEffectorTasks;
+
+import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.location.basic.BasicOsDetails.OsVersions;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.io.FileUtil;
+import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.ComparableVersion;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.CountdownTimer;
+import brooklyn.util.time.Duration;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * The SSH implementation of the {@link MySqlDriver}.
+ */
+public class MySqlSshDriver extends AbstractSoftwareProcessSshDriver implements MySqlDriver {
+
+    public static final Logger log = LoggerFactory.getLogger(MySqlSshDriver.class);
+
+    public MySqlSshDriver(MySqlNodeImpl entity, SshMachineLocation machine) {
+        super(entity, machine);
+
+        entity.setAttribute(Attributes.LOG_FILE_LOCATION, getLogFile());
+    }
+
+    public String getOsTag() {
+        // e.g. "osx10.6-x86_64"; see http://www.mysql.com/downloads/mysql/#downloads
+        OsDetails os = getLocation().getOsDetails();
+        if (os == null) return "linux-glibc2.5-x86_64";
+        if (os.isMac()) {
+            String osp1 = os.getVersion()==null ? "osx10.8" //lowest common denominator
+                : new ComparableVersion(os.getVersion()).isGreaterThanOrEqualTo(OsVersions.MAC_10_9) ? "osx10.9"
+                : "osx10.8";  //lowest common denominator
+            if (!os.is64bit()) {
+                throw new IllegalStateException("Only 64 bit MySQL build is available for OS X");
+            }
+            return osp1+"-x86_64";
+        }
+        //assume generic linux
+        String osp1 = "linux-glibc2.5";
+        String osp2 = os.is64bit() ? "x86_64" : "i686";
+        return osp1+"-"+osp2;
+    }
+
+    public String getBaseDir() { return getExpandedInstallDir(); }
+
+    public String getDataDir() {
+        String result = entity.getConfig(MySqlNode.DATA_DIR);
+        return (result == null) ? "." : result;
+    }
+
+    public String getLogFile() {
+        return Urls.mergePaths(getRunDir(), "console.log");
+    }
+
+    public String getConfigFile() {
+        return "mymysql.cnf";
+    }
+
+    public String getInstallFilename() {
+        return String.format("mysql-%s-%s.tar.gz", getVersion(), getOsTag());
+    }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this, ImmutableMap.of("filename", getInstallFilename()));
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("mysql-%s-%s", getVersion(), getOsTag()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+
+        List<String> commands = new LinkedList<String>();
+        commands.add(BashCommands.INSTALL_TAR);
+        commands.add(BashCommands.INSTALL_CURL);
+
+        commands.add("echo installing extra packages");
+        commands.add(installPackage(ImmutableMap.of("yum", "libgcc_s.so.1"), null));
+        commands.add(installPackage(ImmutableMap.of("yum", "libaio.so.1 libncurses.so.5", "apt", "libaio1 libaio-dev"), null));
+
+        // these deps are only needed on some OS versions but others don't need them
+        commands.add(installPackage(ImmutableMap.of("yum", "libaio", "apt", "ia32-libs"), null));
+        commands.add("echo finished installing extra packages");
+        commands.addAll(commandsToDownloadUrlsAs(urls, saveAs));
+        commands.add(format("tar xfvz %s", saveAs));
+
+        newScript(INSTALLING).body.append(commands).execute();
+    }
+
+    @Override
+    public MySqlNodeImpl getEntity() { return (MySqlNodeImpl) super.getEntity(); }
+    public int getPort() { return getEntity().getPort(); }
+    public String getSocketUid() { return getEntity().getSocketUid(); }
+    public String getPassword() { return getEntity().getPassword(); }
+
+    @Override
+    public void customize() {
+        copyDatabaseConfigScript();
+
+        newScript(CUSTOMIZING)
+            .updateTaskAndFailOnNonZeroResultCode()
+            .body.append(
+                "chmod 600 "+getConfigFile(),
+                getBaseDir()+"/scripts/mysql_install_db "+
+                    "--basedir="+getBaseDir()+" --datadir="+getDataDir()+" "+
+                    "--defaults-file="+getConfigFile())
+            .execute();
+
+        // launch, then we will configure it
+        launch();
+
+        CountdownTimer timer = Duration.seconds(20).countdownTimer();
+        boolean hasCreationScript = copyDatabaseCreationScript();
+        timer.waitForExpiryUnchecked();
+
+        DynamicTasks.queue(
+            SshEffectorTasks.ssh(
+                "cd "+getRunDir(),
+                getBaseDir()+"/bin/mysqladmin --defaults-file="+getConfigFile()+" --password= password "+getPassword()
+            ).summary("setting password"));
+
+        if (hasCreationScript)
+            executeScriptFromInstalledFileAsync("creation-script.sql").asTask().getUnchecked();
+
+        // not sure necessary to stop then subsequently launch, but seems safest
+        // (if skipping, use a flag in launch to indicate we've just launched it)
+        stop();
+    }
+
+    protected void copyDatabaseConfigScript() {
+        newScript(CUSTOMIZING).execute();  //create the directory
+
+        String configScriptContents = processTemplate(entity.getAttribute(MySqlNode.TEMPLATE_CONFIGURATION_URL));
+        Reader configContents = new StringReader(configScriptContents);
+
+        getMachine().copyTo(configContents, Urls.mergePaths(getRunDir(), getConfigFile()));
+    }
+
+    protected boolean copyDatabaseCreationScript() {
+        String creationScriptContents = DatastoreMixins.getDatabaseCreationScriptAsString(entity);
+        if (creationScriptContents==null) return false;
+
+        File templateFile = null;
+        BufferedWriter writer = null;
+        try {
+            templateFile = File.createTempFile("mysql", null);
+            FileUtil.setFilePermissionsTo600(templateFile);
+            writer = new BufferedWriter(new FileWriter(templateFile));
+            writer.write(creationScriptContents);
+            writer.flush();
+            copyTemplate(templateFile.getAbsoluteFile(), getRunDir() + "/creation-script.sql");
+        } catch (IOException e) {
+            throw Exceptions.propagate(e);
+        } finally {
+            if (writer != null) Streams.closeQuietly(writer);
+            if (templateFile != null) templateFile.delete();
+        }
+        return true;
+    }
+
+    public String getMySqlServerOptionsString() {
+        Map<String, Object> options = entity.getConfig(MySqlNode.MYSQL_SERVER_CONF);
+        StringBuilder result = new StringBuilder();
+        if (groovyTruth(options)) {
+            for (Map.Entry<String, Object> entry : options.entrySet()) {
+                result.append(entry.getKey());
+                String value = entry.getValue().toString();
+                if (!Strings.isEmpty(value)) {
+                    result.append(" = ").append(value);
+                }
+                result.append('\n');
+            }
+        }
+        return result.toString();
+    }
+
+    @Override
+    public void launch() {
+        entity.setAttribute(MySqlNode.PID_FILE, getRunDir() + "/" + AbstractSoftwareProcessSshDriver.PID_FILENAME);
+        newScript(MutableMap.of("usePidFile", true), LAUNCHING)
+            .updateTaskAndFailOnNonZeroResultCode()
+            .body.append(format("nohup %s/bin/mysqld --defaults-file=%s --user=`whoami` > %s 2>&1 < /dev/null &", getBaseDir(), getConfigFile(), getLogFile()))
+            .execute();
+    }
+
+    @Override
+    public boolean isRunning() {
+        return newScript(MutableMap.of("usePidFile", false), CHECK_RUNNING)
+            .body.append(getStatusCmd())
+            .execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(MutableMap.of("usePidFile", true), STOPPING).execute();
+    }
+
+    @Override
+    public void kill() {
+        newScript(MutableMap.of("usePidFile", true), KILLING).execute();
+    }
+
+    @Override
+    public String getStatusCmd() {
+        return format("%s/bin/mysqladmin --defaults-file=%s status", getBaseDir(), Urls.mergePaths(getRunDir(), getConfigFile()));
+    }
+
+    @Override
+    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands) {
+        String filename = "mysql-commands-"+Identifiers.makeRandomId(8);
+        DynamicTasks.queue(SshEffectorTasks.put(Urls.mergePaths(getRunDir(), filename)).contents(commands).summary("copying datastore script to execute "+filename));
+        return executeScriptFromInstalledFileAsync(filename);
+    }
+
+    public ProcessTaskWrapper<Integer> executeScriptFromInstalledFileAsync(String filenameAlreadyInstalledAtServer) {
+        return DynamicTasks.queue(
+                SshEffectorTasks.ssh(
+                                "cd "+getRunDir(),
+                                getBaseDir()+"/bin/mysql --defaults-file="+getConfigFile()+" < "+filenameAlreadyInstalledAtServer)
+                        .requiringExitCodeZero()
+                        .summary("executing datastore script "+filenameAlreadyInstalledAtServer));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
new file mode 100644
index 0000000..c1df992
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
@@ -0,0 +1,33 @@
+/*
+ * 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.entity.database.postgresql;
+
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+
+import brooklyn.entity.basic.SoftwareProcessDriver;
+
+/**
+ * The {@link brooklyn.entity.basic.SoftwareProcessDriver} for PostgreSQL.
+ */
+public interface PostgreSqlDriver extends SoftwareProcessDriver {
+
+    String getStatusCmd();
+
+    ProcessTaskWrapper<Integer> executeScriptAsync(String commands);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..7d195f7
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNode.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.entity.database.postgresql;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.Effector;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.entity.trait.HasShortName;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import org.apache.brooklyn.entity.database.DatabaseNode;
+import org.apache.brooklyn.entity.database.DatastoreMixins;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import brooklyn.entity.effector.Effectors;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+
+import org.apache.brooklyn.location.basic.PortRanges;
+
+/**
+ * PostgreSQL database node entity.
+ * <p>
+ * <ul>
+ * <li>You may need to increase shared memory settings in the kernel depending on the setting of
+ * the {@link #SHARED_MEMORY_BUFFER} key. The minimumm value is <em>128kB</em>. See the PostgreSQL
+ * <a href="http://www.postgresql.org/docs/9.1/static/kernel-resources.html">documentation</a>.
+ * <li>You will also need to enable passwordless sudo.
+ * </ul>
+ */
+@Catalog(name="PostgreSQL Node", description="PostgreSQL is an object-relational database management system (ORDBMS)", iconUrl="classpath:///postgresql-logo-200px.png")
+@ImplementedBy(PostgreSqlNodeImpl.class)
+public interface PostgreSqlNode extends SoftwareProcess, HasShortName, DatastoreCommon, DatabaseNode {
+    
+    @SetFromFlag("version")
+    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "9.3-1");//"9.1-4");
+
+    @SetFromFlag("configFileUrl")
+    ConfigKey<String> CONFIGURATION_FILE_URL = ConfigKeys.newStringConfigKey(
+            "postgresql.config.file.url", "URL where PostgreSQL configuration file can be found; "
+                + "if not supplied the blueprint uses the default and customises it");
+
+    @SetFromFlag("authConfigFileUrl")
+    ConfigKey<String> AUTHENTICATION_CONFIGURATION_FILE_URL = ConfigKeys.newStringConfigKey(
+            "postgresql.authConfig.file.url", "URL where PostgreSQL host-based authentication configuration file can be found; "
+                + "if not supplied the blueprint uses the default and customises it");
+
+    @SetFromFlag("port")
+    PortAttributeSensorAndConfigKey POSTGRESQL_PORT = new PortAttributeSensorAndConfigKey(
+            "postgresql.port", "PostgreSQL port", PortRanges.fromString("5432+"));
+
+    @SetFromFlag("sharedMemory")
+    ConfigKey<String> SHARED_MEMORY = ConfigKeys.newStringConfigKey(
+            "postgresql.sharedMemory", "Size of shared memory buffer (must specify as kB, MB or GB, minimum 128kB)", "4MB");
+
+    @SetFromFlag("maxConnections")
+    ConfigKey<Integer> MAX_CONNECTIONS = ConfigKeys.newIntegerConfigKey(
+            "postgresql.maxConnections", "Maximum number of connections to the database", 100);
+
+    @SetFromFlag("disconnectOnStop")
+    ConfigKey<Boolean> DISCONNECT_ON_STOP = ConfigKeys.newBooleanConfigKey(
+            "postgresql.disconnect.on.stop", "If true, PostgreSQL will immediately disconnet (pg_ctl -m immediate stop) all current connections when the node is stopped", true);
+
+    @SetFromFlag("pollPeriod")
+    ConfigKey<Long> POLL_PERIOD = ConfigKeys.newLongConfigKey(
+            "postgresql.sensorpoll", "Poll period (in milliseconds)", 1000L);
+
+    Effector<String> EXECUTE_SCRIPT = Effectors.effector(DatastoreMixins.EXECUTE_SCRIPT)
+            .description("Executes the given script contents using psql")
+            .buildAbstract();
+
+    Integer getPostgreSqlPort();
+    String getSharedMemory();
+    Integer getMaxConnections();
+
+    String executeScript(String commands);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..e99714a
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
@@ -0,0 +1,171 @@
+/*
+ * 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.entity.database.postgresql;
+
+import org.apache.brooklyn.api.entity.Effector;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.EffectorStartableImpl;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.chef.ChefConfig;
+import brooklyn.entity.chef.ChefLifecycleEffectorTasks;
+import brooklyn.entity.chef.ChefServerTasks;
+import brooklyn.entity.effector.EffectorBody;
+import brooklyn.entity.effector.Effectors;
+import brooklyn.entity.software.SshEffectorTasks;
+import brooklyn.event.feed.ssh.SshFeed;
+import brooklyn.event.feed.ssh.SshPollConfig;
+
+import org.apache.brooklyn.location.basic.Locations;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.collections.Jsonya;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.ssh.BashCommands;
+
+public class PostgreSqlNodeChefImplFromScratch extends EffectorStartableImpl implements PostgreSqlNode {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PostgreSqlNodeChefImplFromScratch.class);
+
+    public static final Effector<String> EXECUTE_SCRIPT = Effectors.effector(String.class, "executeScript")
+            .description("invokes a script")
+            .parameter(ExecuteScriptEffectorBody.SCRIPT)
+            .impl(new ExecuteScriptEffectorBody()).build();
+    
+    private SshFeed feed;
+
+    public void init() {
+        super.init();
+        new ChefPostgreSqlLifecycle().attachLifecycleEffectors(this);
+    }
+
+    @Override
+    public Integer getPostgreSqlPort() { return getAttribute(POSTGRESQL_PORT); }
+
+    @Override
+    public String getSharedMemory() { return getConfig(SHARED_MEMORY); }
+
+    @Override
+    public Integer getMaxConnections() { return getConfig(MAX_CONNECTIONS); }
+
+    @Override
+    public String getShortName() {
+        return "PostgreSQL";
+    }
+
+    public static class ChefPostgreSqlLifecycle extends ChefLifecycleEffectorTasks {
+        {
+            usePidFile("/var/run/postgresql/*.pid");
+            useService("postgresql");
+        }
+        protected void startWithKnifeAsync() {
+            Entities.warnOnIgnoringConfig(entity(), ChefConfig.CHEF_LAUNCH_RUN_LIST);
+            Entities.warnOnIgnoringConfig(entity(), ChefConfig.CHEF_LAUNCH_ATTRIBUTES);
+            
+            DynamicTasks.queue(
+                    ChefServerTasks
+                        .knifeConvergeRunList("postgresql::server")
+                        .knifeAddAttributes(Jsonya
+                            .at("postgresql", "config").add(
+                                "port", entity().getPostgreSqlPort(), 
+                                "listen_addresses", "*").getRootMap())
+                        .knifeAddAttributes(Jsonya
+                            .at("postgresql", "pg_hba").list().map().add(
+                                "type", "host", "db", "all", "user", "all", 
+                                "addr", "0.0.0.0/0", "method", "md5").getRootMap()) 
+                        // no other arguments currenty supported; chef will pick a password for us
+                );
+        }
+        protected void postStartCustom() {
+            super.postStartCustom();
+
+            // now run the creation script
+            String creationScript;
+            String creationScriptUrl = entity().getConfig(PostgreSqlNode.CREATION_SCRIPT_URL);
+            if (creationScriptUrl != null) {
+                creationScript = ResourceUtils.create(entity()).getResourceAsString(creationScriptUrl);
+            } else {
+                creationScript = entity().getConfig(PostgreSqlNode.CREATION_SCRIPT_CONTENTS);
+            }
+            entity().executeScript(creationScript);
+
+            // and finally connect sensors
+            entity().connectSensors();
+        }
+        protected void preStopCustom() {
+            entity().disconnectSensors();
+            super.preStopCustom();
+        }
+        protected PostgreSqlNodeChefImplFromScratch entity() {
+            return (PostgreSqlNodeChefImplFromScratch) super.entity();
+        }
+    }
+    
+    public static class ExecuteScriptEffectorBody extends EffectorBody<String> {
+        public static final ConfigKey<String> SCRIPT = ConfigKeys.newStringConfigKey("script", "contents of script to run");
+        
+        public String call(ConfigBag parameters) {
+            return DynamicTasks.queue(SshEffectorTasks.ssh(
+                    BashCommands.pipeTextTo(
+                        parameters.get(SCRIPT),
+                        BashCommands.sudoAsUser("postgres", "psql --file -")))
+                    .requiringExitCodeZero()).getStdout();
+        }
+    }
+    
+    protected void connectSensors() {
+        setAttribute(DATASTORE_URL, String.format("postgresql://%s:%s/", getAttribute(HOSTNAME), getAttribute(POSTGRESQL_PORT)));
+
+        Maybe<SshMachineLocation> machine = Locations.findUniqueSshMachineLocation(getLocations());
+
+        if (machine.isPresent()) {
+            feed = SshFeed.builder()
+                    .entity(this)
+                    .machine(machine.get())
+                    .poll(new SshPollConfig<Boolean>(SERVICE_UP)
+                            .command("ps -ef | grep [p]ostgres")
+                            .setOnSuccess(true)
+                            .setOnFailureOrException(false))
+                    .build();
+        } else {
+            LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; setting serviceUp immediately", getLocations());
+        }
+    }
+
+    protected void disconnectSensors() {
+        if (feed != null) feed.stop();
+    }
+
+    @Override
+    public String executeScript(String commands) {
+        return Entities.invokeEffector(this, this, EXECUTE_SCRIPT,
+                ConfigBag.newInstance().configure(ExecuteScriptEffectorBody.SCRIPT, commands).getAllConfig()).getUnchecked();
+    }
+
+    @Override
+    public void populateServiceNotUpDiagnostics() {
+        // TODO no-op currently; should check ssh'able etc
+    }    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..5cc9fd8
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.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.entity.database.postgresql;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.entity.effector.EffectorBody;
+
+public class PostgreSqlNodeImpl extends SoftwareProcessImpl implements PostgreSqlNode {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PostgreSqlNodeImpl.class);
+
+    public Class<?> getDriverInterface() {
+        return PostgreSqlDriver.class;
+    }
+    @Override
+    public PostgreSqlDriver getDriver() {
+        return (PostgreSqlDriver) super.getDriver();
+    }
+
+    @Override
+    public Integer getPostgreSqlPort() { return getAttribute(POSTGRESQL_PORT); }
+
+    @Override
+    public String getSharedMemory() { return getConfig(SHARED_MEMORY); }
+
+    @Override
+    public Integer getMaxConnections() { return getConfig(MAX_CONNECTIONS); }
+
+    @Override
+    public void init() {
+        super.init();
+        getMutableEntityType().addEffector(EXECUTE_SCRIPT, new EffectorBody<String>() {
+            @Override
+            public String call(ConfigBag parameters) {
+                return executeScript((String) parameters.getStringKey("commands"));
+            }
+        });
+    }
+
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+        connectServiceUpIsRunning();
+        setAttribute(DATASTORE_URL, String.format("postgresql://%s:%s/", getAttribute(HOSTNAME), getAttribute(POSTGRESQL_PORT)));
+    }
+
+    @Override
+    protected void disconnectSensors() {
+        disconnectServiceUpIsRunning();
+        super.disconnectSensors();
+    }
+    
+    @Override
+    public String getShortName() {
+        return "PostgreSQL";
+    }
+
+    @Override
+    public String executeScript(String commands) {
+        return getDriver()
+                .executeScriptAsync(commands)
+                .block()
+                .getStdout();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSpecs.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSpecs.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSpecs.java
new file mode 100644
index 0000000..5e24275
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSpecs.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.entity.database.postgresql;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+
+import brooklyn.entity.chef.ChefConfig;
+import brooklyn.entity.chef.ChefConfig.ChefModes;
+
+/**
+ * Utiltiy for creating specs for {@link PostgreSqlNode} instances.
+ */
+public class PostgreSqlSpecs {
+
+    private PostgreSqlSpecs() {}
+
+    public static EntitySpec<PostgreSqlNode> spec() {
+        return EntitySpec.create(PostgreSqlNode.class);
+    }
+
+    /** Requires {@code knife}. */
+    public static EntitySpec<PostgreSqlNode> specChef() {
+        EntitySpec<PostgreSqlNode> spec = EntitySpec.create(PostgreSqlNode.class, PostgreSqlNodeChefImplFromScratch.class);
+        spec.configure(ChefConfig.CHEF_MODE, ChefModes.KNIFE);
+        return spec;
+    }
+}


[18/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ValueResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ValueResolver.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ValueResolver.java
new file mode 100644
index 0000000..7fc112b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ValueResolver.java
@@ -0,0 +1,426 @@
+/*
+ * 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.util.task;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.BrooklynTaskTags;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.javalang.JavaClassNames;
+import brooklyn.util.repeat.Repeater;
+import brooklyn.util.time.CountdownTimer;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Durations;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import com.google.common.reflect.TypeToken;
+
+/** 
+ * Resolves a given object, as follows:
+ * <li> If it is a {@link Tasks} or a {@link DeferredSupplier} then get its contents
+ * <li> If it's a map and {@link #deep(boolean)} is requested, it applies resolution to contents
+ * <li> It applies coercion
+ * <p>
+ * Fluent-style API exposes a number of other options.
+ */
+public class ValueResolver<T> implements DeferredSupplier<T> {
+
+    /** 
+     * Period to wait if we're expected to return real quick 
+     * but we want fast things to have time to finish.
+     * <p>
+     * Timings are always somewhat arbitrary but this at least
+     * allows some intention to be captured in code rather than arbitrary values. */
+    public static Duration REAL_QUICK_WAIT = Duration.millis(50);
+    /** 
+     * Period to wait if we're expected to return quickly 
+     * but we want to be a bit more generous for things to finish,
+     * without letting a caller get annoyed. 
+     * <p>
+     * See {@link #REAL_QUICK_WAIT}. */
+    public static Duration PRETTY_QUICK_WAIT = Duration.millis(200);
+    
+    /** Period to wait when we have to poll but want to give the illusion of no wait.
+     * See {@link Repeater#DEFAULT_REAL_QUICK_PERIOD} */ 
+    public static Duration REAL_QUICK_PERIOD = Repeater.DEFAULT_REAL_QUICK_PERIOD;
+    
+    private static final Logger log = LoggerFactory.getLogger(ValueResolver.class);
+    
+    final Object value;
+    final Class<T> type;
+    ExecutionContext exec;
+    String description;
+    boolean forceDeep;
+    /** null means do it if you can; true means always, false means never */
+    Boolean embedResolutionInTask;
+    /** timeout on execution, if possible, or if embedResolutionInTask is true */
+    Duration timeout;
+    boolean isTransientTask = true;
+    
+    T defaultValue = null;
+    boolean returnDefaultOnGet = false;
+    boolean swallowExceptions = false;
+    
+    // internal fields
+    final Object parentOriginalValue;
+    final CountdownTimer parentTimer;
+    AtomicBoolean started = new AtomicBoolean(false);
+    boolean expired;
+    
+    ValueResolver(Object v, Class<T> type) {
+        this.value = v;
+        this.type = type;
+        checkTypeNotNull();
+        parentOriginalValue = null;
+        parentTimer = null;
+    }
+    
+    ValueResolver(Object v, Class<T> type, ValueResolver<?> parent) {
+        this.value = v;
+        this.type = type;
+        checkTypeNotNull();
+        
+        exec = parent.exec;
+        description = parent.description;
+        forceDeep = parent.forceDeep;
+        embedResolutionInTask = parent.embedResolutionInTask;
+
+        parentOriginalValue = parent.getOriginalValue();
+
+        timeout = parent.timeout;
+        parentTimer = parent.parentTimer;
+        if (parentTimer!=null && parentTimer.isExpired())
+            expired = true;
+        
+        // default value and swallow exceptions do not need to be nested
+    }
+
+    public static class ResolverBuilderPretype {
+        final Object v;
+        public ResolverBuilderPretype(Object v) {
+            this.v = v;
+        }
+        public <T> ValueResolver<T> as(Class<T> type) {
+            return new ValueResolver<T>(v, type);
+        }
+    }
+
+    /** returns a copy of this resolver which can be queried, even if the original (single-use instance) has already been copied */
+    public ValueResolver<T> clone() {
+        ValueResolver<T> result = new ValueResolver<T>(value, type)
+            .context(exec).description(description)
+            .embedResolutionInTask(embedResolutionInTask)
+            .deep(forceDeep)
+            .timeout(timeout);
+        if (returnDefaultOnGet) result.defaultValue(defaultValue);
+        if (swallowExceptions) result.swallowExceptions();
+        return result;
+    }
+    
+    /** execution context to use when resolving; required if resolving unsubmitted tasks or running with a time limit */
+    public ValueResolver<T> context(ExecutionContext exec) {
+        this.exec = exec;
+        return this;
+    }
+    /** as {@link #context(ExecutionContext)} for use from an entity */
+    public ValueResolver<T> context(Entity entity) {
+        return context(entity!=null ? ((EntityInternal)entity).getExecutionContext() : null);
+    }
+    
+    /** sets a message which will be displayed in status reports while it waits (e.g. the name of the config key being looked up) */
+    public ValueResolver<T> description(String description) {
+        this.description = description;
+        return this;
+    }
+    
+    /** sets a default value which will be returned on a call to {@link #get()} if the task does not complete
+     * or completes with an error
+     * <p>
+     * note that {@link #getMaybe()} returns an absent object even in the presence of
+     * a default, so that any error can still be accessed */
+    public ValueResolver<T> defaultValue(T defaultValue) {
+        this.defaultValue = defaultValue;
+        this.returnDefaultOnGet = true;
+        return this;
+    }
+
+    /** indicates that no default value should be returned on a call to {@link #get()}, and instead it should throw
+     * (this is the default; this method is provided to undo a call to {@link #defaultValue(Object)}) */
+    public ValueResolver<T> noDefaultValue() {
+        this.returnDefaultOnGet = false;
+        this.defaultValue = null;
+        return this;
+    }
+    
+    /** indicates that exceptions in resolution should not be thrown on a call to {@link #getMaybe()}, 
+     * but rather used as part of the {@link Maybe#get()} if it's absent, 
+     * and swallowed altogether on a call to {@link #get()} in the presence of a {@link #defaultValue(Object)} */
+    public ValueResolver<T> swallowExceptions() {
+        this.swallowExceptions = true;
+        return this;
+    }
+    
+    /** whether the task should be marked as transient; defaults true */
+    public ValueResolver<T> transientTask(boolean isTransientTask) {
+        this.isTransientTask = isTransientTask;
+        return this;
+    }
+    
+    public Maybe<T> getDefault() {
+        if (returnDefaultOnGet) return Maybe.of(defaultValue);
+        else return Maybe.absent("No default value set");
+    }
+    
+    /** causes nested structures (maps, lists) to be descended and nested unresolved values resolved */
+    public ValueResolver<T> deep(boolean forceDeep) {
+        this.forceDeep = forceDeep;
+        return this;
+    }
+
+    /** if true, forces execution of a deferred supplier to be run in a task;
+     * if false, it prevents it (meaning time limits may not be applied);
+     * if null, the default, it runs in a task if a time limit is applied.
+     * <p>
+     * running inside a task is required for some {@link DeferredSupplier}
+     * instances which look up a task {@link ExecutionContext}. */
+    public ValueResolver<T> embedResolutionInTask(Boolean embedResolutionInTask) {
+        this.embedResolutionInTask = embedResolutionInTask;
+        return this;
+    }
+    
+    /** sets a time limit on executions
+     * <p>
+     * used for {@link Task} and {@link DeferredSupplier} instances.
+     * may require an execution context at runtime. */
+    public ValueResolver<T> timeout(Duration timeout) {
+        this.timeout = timeout;
+        return this;
+    }
+    
+    protected void checkTypeNotNull() {
+        if (type==null) 
+            throw new NullPointerException("type must be set to resolve, for '"+value+"'"+(description!=null ? ", "+description : ""));
+    }
+
+    public T get() {
+        Maybe<T> m = getMaybe();
+        if (m.isPresent()) return m.get();
+        if (returnDefaultOnGet) return defaultValue;
+        return m.get();
+    }
+    
+    public Maybe<T> getMaybe() {
+        Maybe<T> result = getMaybeInternal();
+        if (log.isTraceEnabled()) {
+            log.trace(this+" evaluated as "+result);
+        }
+        return result;
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected Maybe<T> getMaybeInternal() {
+        if (started.getAndSet(true))
+            throw new IllegalStateException("ValueResolver can only be used once");
+        
+        if (expired) return Maybe.absent("Nested resolution of "+getOriginalValue()+" did not complete within "+timeout);
+        
+        ExecutionContext exec = this.exec;
+        if (exec==null) {
+            // if execution context not specified, take it from the current task if present
+            exec = BasicExecutionContext.getCurrentExecutionContext();
+        }
+        
+        CountdownTimer timerU = parentTimer;
+        if (timerU==null && timeout!=null)
+            timerU = timeout.countdownTimer();
+        final CountdownTimer timer = timerU;
+        if (timer!=null && !timer.isRunning())
+            timer.start();
+        
+        checkTypeNotNull();
+        Object v = this.value;
+        
+        //if the expected type is a closure or map and that's what we have, we're done (or if it's null);
+        //but not allowed to return a future or DeferredSupplier as the resolved value
+        if (v==null || (!forceDeep && type.isInstance(v) && !Future.class.isInstance(v) && !DeferredSupplier.class.isInstance(v)))
+            return Maybe.of((T) v);
+        
+        try {
+            //if it's a task or a future, we wait for the task to complete
+            if (v instanceof TaskAdaptable<?>) {
+                //if it's a task, we make sure it is submitted
+                if (!((TaskAdaptable<?>) v).asTask().isSubmitted() ) {
+                    if (exec==null)
+                        return Maybe.absent("Value for unsubmitted task '"+getDescription()+"' requested but no execution context available");
+                    exec.submit(((TaskAdaptable<?>) v).asTask());
+                }
+            }
+
+            if (v instanceof Future) {
+                final Future<?> vfuture = (Future<?>) v;
+
+                //including tasks, above
+                if (!vfuture.isDone()) {
+                    Callable<Maybe> callable = new Callable<Maybe>() {
+                        public Maybe call() throws Exception {
+                            return Durations.get(vfuture, timer);
+                        } };
+
+                    String description = getDescription();
+                    Maybe vm = Tasks.withBlockingDetails("Waiting for "+description, callable);
+                    if (vm.isAbsent()) return vm;
+                    v = vm.get();
+
+                } else {
+                    v = vfuture.get();
+                    
+                }
+
+            } else if (v instanceof DeferredSupplier<?>) {
+                final Object vf = v;
+
+                if ((!Boolean.FALSE.equals(embedResolutionInTask) && (exec!=null || timeout!=null)) || Boolean.TRUE.equals(embedResolutionInTask)) {
+                    if (exec==null)
+                        return Maybe.absent("Embedding in task needed for '"+getDescription()+"' but no execution context available");
+                        
+                    Callable<Object> callable = new Callable<Object>() {
+                        public Object call() throws Exception {
+                            try {
+                                Tasks.setBlockingDetails("Retrieving "+vf);
+                                return ((DeferredSupplier<?>) vf).get();
+                            } finally {
+                                Tasks.resetBlockingDetails();
+                            }
+                        } };
+                    String description = getDescription();
+                    TaskBuilder<Object> vb = Tasks.<Object>builder().body(callable).name("Resolving dependent value").description(description);
+                    if (isTransientTask) vb.tag(BrooklynTaskTags.TRANSIENT_TASK_TAG);
+                    Task<Object> vt = exec.submit(vb.build());
+                    // TODO to handle immediate resolution, it would be nice to be able to submit 
+                    // so it executes in the current thread,
+                    // or put a marker in the target thread or task while it is running that the task 
+                    // should never wait on anything other than another value being resolved 
+                    // (though either could recurse infinitely) 
+                    Maybe<Object> vm = Durations.get(vt, timer);
+                    vt.cancel(true);
+                    if (vm.isAbsent()) return (Maybe<T>)vm;
+                    v = vm.get();
+                    
+                } else {
+                    try {
+                        Tasks.setBlockingDetails("Retrieving (non-task) "+vf);
+                        v = ((DeferredSupplier<?>) vf).get();
+                    } finally {
+                        Tasks.resetBlockingDetails();
+                    }
+                }
+
+            } else if (v instanceof Map) {
+                //and if a map or list we look inside
+                Map result = Maps.newLinkedHashMap();
+                for (Map.Entry<?,?> entry : ((Map<?,?>)v).entrySet()) {
+                    Maybe<?> kk = new ValueResolver(entry.getKey(), type, this)
+                        .description( (description!=null ? description+", " : "") + "map key "+entry.getKey() )
+                        .getMaybe();
+                    if (kk.isAbsent()) return (Maybe<T>)kk;
+                    Maybe<?> vv = new ValueResolver(entry.getValue(), type, this)
+                        .description( (description!=null ? description+", " : "") + "map value for key "+kk.get() )
+                        .getMaybe();
+                    if (vv.isAbsent()) return (Maybe<T>)vv;
+                    result.put(kk.get(), vv.get());
+                }
+                return Maybe.of((T) result);
+
+            } else if (v instanceof Set) {
+                Set result = Sets.newLinkedHashSet();
+                int count = 0;
+                for (Object it : (Set)v) {
+                    Maybe<?> vv = new ValueResolver(it, type, this)
+                        .description( (description!=null ? description+", " : "") + "entry "+count )
+                        .getMaybe();
+                    if (vv.isAbsent()) return (Maybe<T>)vv;
+                    result.add(vv.get());
+                    count++;
+                }
+                return Maybe.of((T) result);
+
+            } else if (v instanceof Iterable) {
+                List result = Lists.newArrayList();
+                int count = 0;
+                for (Object it : (Iterable)v) {
+                    Maybe<?> vv = new ValueResolver(it, type, this)
+                        .description( (description!=null ? description+", " : "") + "entry "+count )
+                        .getMaybe();
+                    if (vv.isAbsent()) return (Maybe<T>)vv;
+                    result.add(vv.get());
+                    count++;
+                }
+                return Maybe.of((T) result);
+
+            } else {
+                return TypeCoercions.tryCoerce(v, TypeToken.of(type));
+            }
+
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            
+            IllegalArgumentException problem = new IllegalArgumentException("Error resolving "+(description!=null ? description+", " : "")+v+", in "+exec+": "+e, e);
+            if (swallowExceptions) {
+                if (log.isDebugEnabled())
+                    log.debug("Resolution of "+this+" failed, swallowing and returning: "+e);
+                return Maybe.absent(problem);
+            }
+            if (log.isDebugEnabled())
+                log.debug("Resolution of "+this+" failed, throwing: "+e);
+            throw problem;
+        }
+        
+        return new ValueResolver(v, type, this).getMaybe();
+    }
+
+    protected String getDescription() {
+        return description!=null ? description : ""+value;
+    }
+    protected Object getOriginalValue() {
+        if (parentOriginalValue!=null) return parentOriginalValue;
+        return value;
+    }
+    
+    @Override
+    public String toString() {
+        return JavaClassNames.cleanSimpleClassName(this)+"["+JavaClassNames.cleanSimpleClassName(type)+" "+value+"]";
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshFetchTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshFetchTaskFactory.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshFetchTaskFactory.java
new file mode 100644
index 0000000..a38e305
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshFetchTaskFactory.java
@@ -0,0 +1,88 @@
+/*
+ * 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.util.task.ssh;
+
+import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+// cannot be (cleanly) instantiated due to nested generic self-referential type; however trivial subclasses do allow it 
+public class SshFetchTaskFactory implements TaskFactory<SshFetchTaskWrapper> {
+    
+    private static final Logger log = LoggerFactory.getLogger(SshFetchTaskFactory.class);
+    
+    private boolean dirty = false;
+    
+    protected SshMachineLocation machine;
+    protected String remoteFile;
+    protected final ConfigBag config = ConfigBag.newInstance();
+
+    /** constructor where machine will be added later */
+    public SshFetchTaskFactory(String remoteFile) {
+        remoteFile(remoteFile);
+    }
+
+    /** convenience constructor to supply machine immediately */
+    public SshFetchTaskFactory(SshMachineLocation machine, String remoteFile) {
+        machine(machine);
+        remoteFile(remoteFile);
+    }
+
+    protected SshFetchTaskFactory self() { return this; }
+
+    protected void markDirty() {
+        dirty = true;
+    }
+    
+    public SshFetchTaskFactory machine(SshMachineLocation machine) {
+        markDirty();
+        this.machine = machine;
+        return self();
+    }
+        
+    public SshMachineLocation getMachine() {
+        return machine;
+    }
+    
+    public SshFetchTaskFactory remoteFile(String remoteFile) {
+        this.remoteFile = remoteFile;
+        return self();
+    }
+
+    public ConfigBag getConfig() {
+        return config;
+    }
+    
+    @Override
+    public SshFetchTaskWrapper newTask() {
+        dirty = false;
+        return new SshFetchTaskWrapper(this);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        // help let people know of API usage error
+        if (dirty)
+            log.warn("Task "+this+" was modified but modification was never used");
+        super.finalize();
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshFetchTaskWrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshFetchTaskWrapper.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshFetchTaskWrapper.java
new file mode 100644
index 0000000..b6c2931
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshFetchTaskWrapper.java
@@ -0,0 +1,135 @@
+/*
+ * 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.util.task.ssh;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskWrapper;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.os.Os;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+/**
+ * As {@link ProcessTaskWrapper}, but putting a file on the remote machine
+ * 
+ * @since 0.6.0
+ */
+@Beta
+public class SshFetchTaskWrapper implements TaskWrapper<String> {
+
+    private final Task<String> task;
+
+    private final String remoteFile;
+    private final SshMachineLocation machine;
+    private File backingFile;
+    private final ConfigBag config;
+    
+    
+    // package private as only AbstractSshTaskFactory should invoke
+    SshFetchTaskWrapper(SshFetchTaskFactory factory) {
+        this.remoteFile = Preconditions.checkNotNull(factory.remoteFile, "remoteFile");
+        this.machine = Preconditions.checkNotNull(factory.machine, "machine");
+        TaskBuilder<String> tb = TaskBuilder.<String>builder().dynamic(false).name("ssh fetch "+factory.remoteFile);
+        task = tb.body(new SshFetchJob()).build();
+        config = factory.getConfig();
+    }
+    
+    @Override
+    public Task<String> asTask() {
+        return getTask();
+    }
+    
+    @Override
+    public Task<String> getTask() {
+        return task;
+    }
+    
+    public String getRemoteFile() {
+        return remoteFile;
+    }
+    
+    public SshMachineLocation getMachine() {
+        return machine;
+    }
+        
+    private class SshFetchJob implements Callable<String> {
+        @Override
+        public String call() throws Exception {
+            int result = -1;
+            try {
+                Preconditions.checkNotNull(getMachine(), "machine");
+                backingFile = Os.newTempFile("brooklyn-ssh-fetch-", FilenameUtils.getName(remoteFile));
+                backingFile.deleteOnExit();
+                
+                result = getMachine().copyFrom(config.getAllConfig(), remoteFile, backingFile.getPath());
+            } catch (Exception e) {
+                throw new IllegalStateException("SSH fetch "+getRemoteFile()+" from "+getMachine()+" returned threw exception, in "+Tasks.current()+": "+e, e);
+            }
+            if (result!=0) {
+                throw new IllegalStateException("SSH fetch "+getRemoteFile()+" from "+getMachine()+" returned non-zero exit code  "+result+", in "+Tasks.current());
+            }
+            return FileUtils.readFileToString(backingFile);
+        }
+    }
+    
+    @Override
+    public String toString() {
+        return super.toString()+"["+task+"]";
+    }
+
+    /** blocks, returns the fetched file as a string, throwing if there was an exception */
+    public String get() {
+        return getTask().getUnchecked();
+    }
+    
+    /** blocks, returns the fetched file as bytes, throwing if there was an exception */
+    public byte[] getBytes() {
+        block();
+        try {
+            return FileUtils.readFileToByteArray(backingFile);
+        } catch (IOException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    /** blocks until the task completes; does not throw */
+    public SshFetchTaskWrapper block() {
+        getTask().blockUntilEnded();
+        return this;
+    }
+ 
+    /** true iff the ssh job has completed (with or without failure) */
+    public boolean isDone() {
+        return getTask().isDone();
+    }   
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskFactory.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskFactory.java
new file mode 100644
index 0000000..05cc42e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskFactory.java
@@ -0,0 +1,123 @@
+/*
+ * 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.util.task.ssh;
+
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.apache.brooklyn.api.management.TaskFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.stream.KnownSizeInputStream;
+import brooklyn.util.stream.ReaderInputStream;
+
+import com.google.common.base.Suppliers;
+
+// cannot be (cleanly) instantiated due to nested generic self-referential type; however trivial subclasses do allow it 
+public class SshPutTaskFactory extends SshPutTaskStub implements TaskFactory<SshPutTaskWrapper> {
+    
+    private static final Logger log = LoggerFactory.getLogger(SshPutTaskFactory.class);
+    
+    private boolean dirty = false;
+
+    /** constructor where machine will be added later */
+    public SshPutTaskFactory(String remoteFile) {
+        remoteFile(remoteFile);
+    }
+
+    /** convenience constructor to supply machine immediately */
+    public SshPutTaskFactory(SshMachineLocation machine, String remoteFile) {
+        machine(machine);
+        remoteFile(remoteFile);
+    }
+
+    protected SshPutTaskFactory self() { return this; }
+
+    protected void markDirty() {
+        dirty = true;
+    }
+    
+    public SshPutTaskFactory machine(SshMachineLocation machine) {
+        markDirty();
+        this.machine = machine;
+        return self();
+    }
+        
+    public SshPutTaskFactory remoteFile(String remoteFile) {
+        this.remoteFile = remoteFile;
+        return self();
+    }
+
+    public SshPutTaskFactory summary(String summary) {
+        markDirty();
+        this.summary = summary;
+        return self();
+    }
+
+    public SshPutTaskFactory contents(String contents) {
+        markDirty();
+        this.contents = Suppliers.ofInstance(KnownSizeInputStream.of(contents));  
+        return self();
+    }
+
+    public SshPutTaskFactory contents(byte[] contents) {
+        markDirty();
+        this.contents = Suppliers.ofInstance(KnownSizeInputStream.of(contents));  
+        return self();
+    }
+
+    public SshPutTaskFactory contents(InputStream stream) {
+        markDirty();
+        this.contents = Suppliers.ofInstance(stream);  
+        return self();
+    }
+
+    public SshPutTaskFactory contents(Reader reader) {
+        markDirty();
+        this.contents = Suppliers.ofInstance(new ReaderInputStream(reader));  
+        return self();
+    }
+
+    public SshPutTaskFactory allowFailure() {
+        markDirty();
+        allowFailure = true;
+        return self();
+    }
+    
+    public SshPutTaskFactory createDirectory() {
+        markDirty();
+        createDirectory = true;
+        return self();
+    }
+    
+    public SshPutTaskWrapper newTask() {
+        dirty = false;
+        return new SshPutTaskWrapper(this);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        // help let people know of API usage error
+        if (dirty)
+            log.warn("Task "+this+" was modified but modification was never used");
+        super.finalize();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskStub.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskStub.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskStub.java
new file mode 100644
index 0000000..4e3a024
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskStub.java
@@ -0,0 +1,69 @@
+/*
+ * 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.util.task.ssh;
+
+import java.io.InputStream;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import com.google.common.base.Supplier;
+
+public class SshPutTaskStub {
+
+    protected String remoteFile;
+    protected SshMachineLocation machine;
+    protected Supplier<? extends InputStream> contents;
+    protected String summary;
+    protected String permissions;
+    protected boolean allowFailure = false;
+    protected boolean createDirectory = false;
+    protected final ConfigBag config = ConfigBag.newInstance();
+
+    protected SshPutTaskStub() {
+    }
+    
+    protected SshPutTaskStub(SshPutTaskStub constructor) {
+        this.remoteFile = constructor.remoteFile;
+        this.machine = constructor.machine;
+        this.contents = constructor.contents;
+        this.summary = constructor.summary;
+        this.allowFailure = constructor.allowFailure;
+        this.createDirectory = constructor.createDirectory;
+        this.permissions = constructor.permissions;
+        this.config.copy(constructor.config);
+    }
+
+    public String getRemoteFile() {
+        return remoteFile;
+    }
+    
+    public String getSummary() {
+        if (summary!=null) return summary;
+        return "scp put: "+remoteFile;
+    }
+
+    public SshMachineLocation getMachine() {
+        return machine;
+    }
+    
+    protected ConfigBag getConfig() {
+        return config;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskWrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskWrapper.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskWrapper.java
new file mode 100644
index 0000000..13449d0
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshPutTaskWrapper.java
@@ -0,0 +1,189 @@
+/*
+ * 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.util.task.ssh;
+
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskWrapper;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+/** As {@link ProcessTaskWrapper}, but putting a file on the remote machine */
+@Beta
+public class SshPutTaskWrapper extends SshPutTaskStub implements TaskWrapper<Void> {
+
+    private static final Logger log = LoggerFactory.getLogger(SshPutTaskWrapper.class);
+    
+    private final Task<Void> task;
+
+    protected Integer exitCodeOfCopy = null;
+    protected Exception exception = null;
+    protected boolean successful = false;
+    
+    // package private as only AbstractSshTaskFactory should invoke
+    SshPutTaskWrapper(SshPutTaskFactory constructor) {
+        super(constructor);
+        TaskBuilder<Void> tb = TaskBuilder.<Void>builder().dynamic(false).name(getSummary());
+        task = tb.body(new SshPutJob()).build();
+    }
+    
+    @Override
+    public Task<Void> asTask() {
+        return getTask();
+    }
+    
+    @Override
+    public Task<Void> getTask() {
+        return task;
+    }
+        
+    // TODO:
+    //   verify
+    //   copyAsRoot
+    //   owner
+    //   lastModificationDate - see {@link #PROP_LAST_MODIFICATION_DATE}; not supported by all SshTool implementations
+    //   lastAccessDate - see {@link #PROP_LAST_ACCESS_DATE}; not supported by all SshTool implementations
+
+    private class SshPutJob implements Callable<Void> {
+        @Override
+        public Void call() throws Exception {
+            try {
+                Preconditions.checkNotNull(getMachine(), "machine");
+                
+                String remoteFile = getRemoteFile();
+
+                if (createDirectory) {
+                    String remoteDir = remoteFile;
+                    int exitCodeOfCreate = -1;
+                    try {
+                        int li = remoteDir.lastIndexOf("/");
+                        if (li>=0) {
+                            remoteDir = remoteDir.substring(0, li+1);
+                            exitCodeOfCreate = getMachine().execCommands("creating directory for "+getSummary(), 
+                                    Arrays.asList("mkdir -p "+remoteDir));
+                        } else {
+                            // nothing to create
+                            exitCodeOfCreate = 0;
+                        }
+                    } catch (Exception e) {
+                        if (log.isDebugEnabled())
+                            log.debug("SSH put "+getRemoteFile()+" (create dir, in task "+getSummary()+") to "+getMachine()+" threw exception: "+e);
+                        exception = e;
+                    }
+                    if (exception!=null || !((Integer)0).equals(exitCodeOfCreate)) {
+                        if (!allowFailure) {
+                            if (exception != null) {
+                                throw new IllegalStateException(getSummary()+" (creating dir "+remoteDir+" for SSH put task) ended with exception, in "+Tasks.current()+": "+exception, exception);
+                            }
+                            if (exitCodeOfCreate!=0) {
+                                exception = new IllegalStateException(getSummary()+" (creating dir "+remoteDir+" SSH put task) ended with exit code "+exitCodeOfCreate+", in "+Tasks.current());
+                                throw exception;
+                            }
+                        }
+                        // not successful, but allowed
+                        return null;
+                    }
+                }
+                
+                ConfigBag config = ConfigBag.newInstanceCopying(getConfig());
+                if (permissions!=null) config.put(SshTool.PROP_PERMISSIONS, permissions);
+                
+                exitCodeOfCopy = getMachine().copyTo(config.getAllConfig(), contents.get(), remoteFile);
+
+                if (log.isDebugEnabled())
+                    log.debug("SSH put "+getRemoteFile()+" (task "+getSummary()+") to "+getMachine()+" completed with exit code "+exitCodeOfCopy);
+            } catch (Exception e) {
+                if (log.isDebugEnabled())
+                    log.debug("SSH put "+getRemoteFile()+" (task "+getSummary()+") to "+getMachine()+" threw exception: "+e);
+                exception = e;
+            }
+            
+            if (exception!=null || !((Integer)0).equals(exitCodeOfCopy)) {
+                if (!allowFailure) {
+                    if (exception != null) {
+                        throw new IllegalStateException(getSummary()+" (SSH put task) ended with exception, in "+Tasks.current()+": "+exception, exception);
+                    }
+                    if (exitCodeOfCopy!=0) {
+                        exception = new IllegalStateException(getSummary()+" (SSH put task) ended with exit code "+exitCodeOfCopy+", in "+Tasks.current());
+                        throw exception;
+                    }
+                }
+                // not successful, but allowed
+                return null;
+            }
+            
+            // TODO verify
+
+            successful = (exception==null && ((Integer)0).equals(exitCodeOfCopy));
+            return null;
+        }
+    }
+    
+    @Override
+    public String toString() {
+        return super.toString()+"["+task+"]";
+    }
+
+    /** blocks, throwing if there was an exception */
+    public Void get() {
+        return getTask().getUnchecked();
+    }
+    
+    /** returns the exit code from the copy, 0 on success; 
+     * null if it has not completed or threw exception
+     * (not sure if this is ever a non-zero integer or if it is meaningful)
+     * <p>
+     * most callers will want the simpler {@link #isSuccessful()} */
+    public Integer getExitCode() {
+        return exitCodeOfCopy;
+    }
+    
+    /** returns any exception encountered in the operation */
+    public Exception getException() {
+        return exception;
+    }
+    
+    /** blocks until the task completes; does not throw */
+    public SshPutTaskWrapper block() {
+        getTask().blockUntilEnded();
+        return this;
+    }
+ 
+    /** true iff the ssh job has completed (with or without failure) */
+    public boolean isDone() {
+        return getTask().isDone();
+    }
+
+    /** true iff the scp has completed successfully; guaranteed to be set before {@link #isDone()} or {@link #block()} are satisfied */
+    public boolean isSuccessful() {
+        return successful;
+    }
+    
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshTasks.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshTasks.java
new file mode 100644
index 0000000..5f8d735
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/SshTasks.java
@@ -0,0 +1,236 @@
+/*
+ * 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.util.task.ssh;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.api.management.TaskQueueingContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ssh.internal.PlainSshExecTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.config.ConfigUtils;
+import brooklyn.entity.basic.BrooklynTaskTags;
+import brooklyn.entity.basic.ConfigKeys;
+
+import org.apache.brooklyn.location.basic.AbstractLocation;
+import org.apache.brooklyn.location.basic.LocationInternal;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.net.Urls;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.Strings;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+
+/**
+ * Conveniences for generating {@link Task} instances to perform SSH activities on an {@link SshMachineLocation}.
+ * <p>
+ * To infer the {@link SshMachineLocation} and take properties from entities and global management context the
+ * {@link SshEffectorTasks} should be preferred over this class.
+ *  
+ * @see SshEffectorTasks
+ * @since 0.6.0
+ */
+@Beta
+public class SshTasks {
+
+    private static final Logger log = LoggerFactory.getLogger(SshTasks.class);
+        
+    public static ProcessTaskFactory<Integer> newSshExecTaskFactory(SshMachineLocation machine, String ...commands) {
+        return newSshExecTaskFactory(machine, true, commands);
+    }
+    
+    public static ProcessTaskFactory<Integer> newSshExecTaskFactory(SshMachineLocation machine, final boolean useMachineConfig, String ...commands) {
+        return new PlainSshExecTaskFactory<Integer>(machine, commands) {
+            {
+                if (useMachineConfig)
+                    config.putIfAbsent(getSshFlags(machine));
+            }
+        };
+    }
+
+    public static SshPutTaskFactory newSshPutTaskFactory(SshMachineLocation machine, String remoteFile) {
+        return newSshPutTaskFactory(machine, true, remoteFile);
+    }
+    
+    public static SshPutTaskFactory newSshPutTaskFactory(SshMachineLocation machine, final boolean useMachineConfig, String remoteFile) {
+        return new SshPutTaskFactory(machine, remoteFile) {
+            {
+                if (useMachineConfig)
+                    config.putIfAbsent(getSshFlags(machine));
+            }
+        };
+    }
+
+    public static SshFetchTaskFactory newSshFetchTaskFactory(SshMachineLocation machine, String remoteFile) {
+        return newSshFetchTaskFactory(machine, true, remoteFile);
+    }
+    
+    public static SshFetchTaskFactory newSshFetchTaskFactory(SshMachineLocation machine, final boolean useMachineConfig, String remoteFile) {
+        return new SshFetchTaskFactory(machine, remoteFile) {
+            {
+                if (useMachineConfig)
+                    config.putIfAbsent(getSshFlags(machine));
+            }
+        };
+    }
+
+    private static Map<String, Object> getSshFlags(Location location) {
+        ConfigBag allConfig = ConfigBag.newInstance();
+        
+        if (location instanceof AbstractLocation) {
+            ManagementContext mgmt = ((AbstractLocation)location).getManagementContext();
+            if (mgmt!=null)
+                allConfig.putAll(mgmt.getConfig().getAllConfig());
+        }
+        
+        allConfig.putAll(((LocationInternal)location).config().getBag());
+        
+        Map<String, Object> result = Maps.newLinkedHashMap();
+        for (String keyS : allConfig.getAllConfig().keySet()) {
+            ConfigKey<?> key = ConfigKeys.newConfigKey(Object.class, keyS);
+            if (key.getName().startsWith(SshTool.BROOKLYN_CONFIG_KEY_PREFIX)) {
+                result.put(ConfigUtils.unprefixedKey(SshTool.BROOKLYN_CONFIG_KEY_PREFIX, key).getName(), allConfig.get(key));
+            }
+        }
+        return result;
+    }
+
+    @Beta
+    public static enum OnFailingTask { 
+        FAIL,
+        /** issues a warning, sometimes implemented as marking the task inessential and failing it if it appears
+         * we are in a dynamic {@link TaskQueueingContext};
+         * useful because this way the warning appears to the user;
+         * but note that the check is done against the calling thread so use with some care
+         * (and thus this enum is currently here rather then elsewhere) */
+        WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL,
+        /** issues a warning in the log if the task fails, otherwise swallows it */
+        WARN_IN_LOG_ONLY, 
+        /** not even a warning if the task fails (the caller is expected to handle it as appropriate) */
+        IGNORE }
+    
+    public static ProcessTaskFactory<Boolean> dontRequireTtyForSudo(SshMachineLocation machine, final boolean failIfCantSudo) {
+        return dontRequireTtyForSudo(machine, failIfCantSudo ? OnFailingTask.FAIL : OnFailingTask.WARN_IN_LOG_ONLY);
+    }
+    /** creates a task which returns modifies sudoers to ensure non-tty access is permitted;
+     * also gives nice warnings if sudo is not permitted */
+    public static ProcessTaskFactory<Boolean> dontRequireTtyForSudo(SshMachineLocation machine, OnFailingTask onFailingTaskRequested) {
+        final OnFailingTask onFailingTask;
+        if (onFailingTaskRequested==OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL) {
+            if (DynamicTasks.getTaskQueuingContext()!=null)
+                onFailingTask = onFailingTaskRequested;
+            else
+                onFailingTask = OnFailingTask.WARN_IN_LOG_ONLY;
+        } else {
+            onFailingTask = onFailingTaskRequested;
+        }
+        
+        final String id = Identifiers.makeRandomId(6);
+        return newSshExecTaskFactory(machine, 
+                BashCommands.dontRequireTtyForSudo(),
+                // strange quotes are to ensure we don't match against echoed stdin
+                BashCommands.sudo("echo \"sudo\"-is-working-"+id))
+            .summary("setting up sudo")
+            .configure(SshTool.PROP_ALLOCATE_PTY, true)
+            .allowingNonZeroExitCode()
+            .returning(new Function<ProcessTaskWrapper<?>,Boolean>() { public Boolean apply(ProcessTaskWrapper<?> task) {
+                if (task.getExitCode()==0 && task.getStdout().contains("sudo-is-working-"+id)) return true;
+                Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
+                
+                
+                if (onFailingTask!=OnFailingTask.IGNORE) {
+                    // TODO if in a queueing context can we mark this task inessential and throw?
+                    // that way user sees the message...
+                    String message = "Error setting up sudo for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+" "+
+                        " (exit code "+task.getExitCode()+(entity!=null ? ", entity "+entity : "")+")";
+                    DynamicTasks.queueIfPossible(Tasks.warning(message, null));
+                }
+                Streams.logStreamTail(log, "STDERR of sudo setup problem", Streams.byteArrayOfString(task.getStderr()), 1024);
+                
+                if (onFailingTask==OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL) {
+                    Tasks.markInessential();
+                }
+                if (onFailingTask==OnFailingTask.FAIL || onFailingTask==OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL) {
+                    throw new IllegalStateException("Passwordless sudo is required for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+
+                            (entity!=null ? " ("+entity+")" : ""));
+                }
+                return false; 
+            } });
+    }
+
+    /** Function for use in {@link ProcessTaskFactory#returning(Function)} which logs all information, optionally requires zero exit code, 
+     * and then returns stdout */
+    public static Function<ProcessTaskWrapper<?>, String> returningStdoutLoggingInfo(final Logger logger, final boolean requireZero) {
+        return new Function<ProcessTaskWrapper<?>, String>() {
+          public String apply(@Nullable ProcessTaskWrapper<?> input) {
+            if (logger!=null) logger.info(input+" COMMANDS:\n"+Strings.join(input.getCommands(),"\n"));
+            if (logger!=null) logger.info(input+" STDOUT:\n"+input.getStdout());
+            if (logger!=null) logger.info(input+" STDERR:\n"+input.getStderr());
+            if (requireZero && input.getExitCode()!=0) 
+                throw new IllegalStateException("non-zero exit code in "+input.getSummary()+": see log for more details!");
+            return input.getStdout();
+          }
+        };
+    }
+
+    /** task to install a file given a url, where the url is resolved remotely first then locally */
+    public static TaskFactory<?> installFromUrl(final SshMachineLocation location, final String url, final String destPath) {
+        return installFromUrl(ResourceUtils.create(SshTasks.class), ImmutableMap.<String,Object>of(), location, url, destPath);
+    }
+    /** task to install a file given a url, where the url is resolved remotely first then locally */
+    public static TaskFactory<?> installFromUrl(final ResourceUtils utils, final Map<String, ?> props, final SshMachineLocation location, final String url, final String destPath) {
+        return new TaskFactory<TaskAdaptable<?>>() {
+            @Override
+            public TaskAdaptable<?> newTask() {
+                return Tasks.<Void>builder().name("installing "+Urls.getBasename(url)).description("installing "+url+" to "+destPath).body(new Runnable() {
+                    @Override
+                    public void run() {
+                        int result = location.installTo(utils, props, url, destPath);
+                        if (result!=0) 
+                            throw new IllegalStateException("Failed to install '"+url+"' to '"+destPath+"' at "+location+": exit code "+result);
+                    }
+                }).build();
+            }
+        };
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/internal/AbstractSshExecTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/internal/AbstractSshExecTaskFactory.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/internal/AbstractSshExecTaskFactory.java
new file mode 100644
index 0000000..45600d5
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/internal/AbstractSshExecTaskFactory.java
@@ -0,0 +1,58 @@
+/*
+ * 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.util.task.ssh.internal;
+
+import com.google.common.base.Preconditions;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.core.util.task.system.internal.AbstractProcessTaskFactory;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+// cannot be (cleanly) instantiated due to nested generic self-referential type; however trivial subclasses do allow it 
+public abstract class AbstractSshExecTaskFactory<T extends AbstractProcessTaskFactory<T,RET>,RET> extends AbstractProcessTaskFactory<T,RET> implements ProcessTaskFactory<RET> {
+    
+    /** constructor where machine will be added later */
+    public AbstractSshExecTaskFactory(String ...commands) {
+        super(commands);
+    }
+
+    /** convenience constructor to supply machine immediately */
+    public AbstractSshExecTaskFactory(SshMachineLocation machine, String ...commands) {
+        this(commands);
+        machine(machine);
+    }
+    
+    @Override
+    public ProcessTaskWrapper<RET> newTask() {
+        dirty = false;
+        return new ProcessTaskWrapper<RET>(this) {
+            protected void run(ConfigBag config) {
+                Preconditions.checkNotNull(getMachine(), "machine");
+                if (Boolean.FALSE.equals(this.runAsScript)) {
+                    this.exitCode = getMachine().execCommands(config.getAllConfig(), getSummary(), commands, shellEnvironment);
+                } else { // runScript = null or TRUE
+                    this.exitCode = getMachine().execScript(config.getAllConfig(), getSummary(), commands, shellEnvironment);
+                }
+            }
+            protected String taskTypeShortName() { return "SSH"; }
+        };
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/internal/PlainSshExecTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/internal/PlainSshExecTaskFactory.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/internal/PlainSshExecTaskFactory.java
new file mode 100644
index 0000000..4d5dfce
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ssh/internal/PlainSshExecTaskFactory.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.core.util.task.ssh.internal;
+
+import java.util.List;
+
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import com.google.common.base.Function;
+
+/** the "Plain" class exists purely so we can massage return types for callers' convenience */
+public class PlainSshExecTaskFactory<RET> extends AbstractSshExecTaskFactory<PlainSshExecTaskFactory<RET>,RET> {
+    /** constructor where machine will be added later */
+    public PlainSshExecTaskFactory(String ...commands) {
+        super(commands);
+    }
+
+    /** convenience constructor to supply machine immediately */
+    public PlainSshExecTaskFactory(SshMachineLocation machine, String ...commands) {
+        this(commands);
+        machine(machine);
+    }
+
+    /** Constructor where machine will be added later */
+    public PlainSshExecTaskFactory(List<String> commands) {
+        this(commands.toArray(new String[commands.size()]));
+    }
+
+    /** Convenience constructor to supply machine immediately */
+    public PlainSshExecTaskFactory(SshMachineLocation machine, List<String> commands) {
+        this(machine, commands.toArray(new String[commands.size()]));
+    }
+
+    @Override
+    public <T2> PlainSshExecTaskFactory<T2> returning(ScriptReturnType type) {
+        return (PlainSshExecTaskFactory<T2>) super.<T2>returning(type);
+    }
+
+    @Override
+    public <RET2> PlainSshExecTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation) {
+        return (PlainSshExecTaskFactory<RET2>) super.returning(resultTransformation);
+    }
+    
+    @Override
+    public PlainSshExecTaskFactory<Boolean> returningIsExitCodeZero() {
+        return (PlainSshExecTaskFactory<Boolean>) super.returningIsExitCodeZero();
+    }
+    
+    @Override
+    public PlainSshExecTaskFactory<String> requiringZeroAndReturningStdout() {
+        return (PlainSshExecTaskFactory<String>) super.requiringZeroAndReturningStdout();
+    }
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskFactory.java b/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskFactory.java
new file mode 100644
index 0000000..f66e1ea
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskFactory.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.util.task.system;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskStub.ScriptReturnType;
+
+import brooklyn.config.ConfigKey;
+
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+
+public interface ProcessTaskFactory<T> extends TaskFactory<ProcessTaskWrapper<T>> {
+    public ProcessTaskFactory<T> machine(SshMachineLocation machine);
+    public ProcessTaskFactory<T> add(String ...commandsToAdd);
+    public ProcessTaskFactory<T> add(Iterable<String> commandsToAdd);
+    public ProcessTaskFactory<T> requiringExitCodeZero();
+    public ProcessTaskFactory<T> requiringExitCodeZero(String extraErrorMessage);
+    public ProcessTaskFactory<T> allowingNonZeroExitCode();
+    public ProcessTaskFactory<String> requiringZeroAndReturningStdout();
+    public ProcessTaskFactory<Boolean> returningIsExitCodeZero();
+    public <RET2> ProcessTaskFactory<RET2> returning(ScriptReturnType type);
+    public <RET2> ProcessTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation);
+    public ProcessTaskFactory<T> runAsCommand();
+    public ProcessTaskFactory<T> runAsScript();
+    public ProcessTaskFactory<T> runAsRoot();
+    public ProcessTaskFactory<T> environmentVariable(String key, String val);
+    public ProcessTaskFactory<T> environmentVariables(Map<String,String> vars);
+    public ProcessTaskFactory<T> summary(String summary);
+    
+    /** allows setting config-key based properties for specific underlying tools */
+    @Beta
+    public <V> ProcessTaskFactory<T> configure(ConfigKey<V> key, V value);
+
+    /** allows setting config-key/flag based properties for specific underlying tools;
+     * but note that if any are prefixed with {@link SshTool#BROOKLYN_CONFIG_KEY_PREFIX}
+     * these should normally be filtered out */
+    @Beta
+    public ProcessTaskFactory<T> configure(Map<?,?> flags);
+
+    /** adds a listener which will be notified of (otherwise) successful completion,
+     * typically used to invalidate the result (ie throw exception, to promote a string in the output to an exception);
+     * invoked even if return code is zero, so a better error can be thrown */
+    public ProcessTaskFactory<T> addCompletionListener(Function<ProcessTaskWrapper<?>, Void> function);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskStub.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskStub.java b/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskStub.java
new file mode 100644
index 0000000..1937d15
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskStub.java
@@ -0,0 +1,102 @@
+/*
+ * 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.util.task.system;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class ProcessTaskStub {
+    
+    protected final List<String> commands = new ArrayList<String>();
+    /** null for localhost */
+    protected SshMachineLocation machine;
+    
+    // config data
+    protected String summary;
+    protected final ConfigBag config = ConfigBag.newInstance();
+    
+    public static enum ScriptReturnType { CUSTOM, EXIT_CODE, STDOUT_STRING, STDOUT_BYTES, STDERR_STRING, STDERR_BYTES }
+    protected Function<ProcessTaskWrapper<?>, ?> returnResultTransformation = null;
+    protected ScriptReturnType returnType = ScriptReturnType.EXIT_CODE;
+    
+    protected Boolean runAsScript = null;
+    protected boolean runAsRoot = false;
+    protected Boolean requireExitCodeZero = null;
+    protected String extraErrorMessage = null;
+    protected Map<String,String> shellEnvironment = new MutableMap<String, String>();
+    protected final List<Function<ProcessTaskWrapper<?>, Void>> completionListeners = new ArrayList<Function<ProcessTaskWrapper<?>,Void>>();
+
+    public ProcessTaskStub() {}
+    
+    protected ProcessTaskStub(ProcessTaskStub source) {
+        commands.addAll(source.getCommands());
+        machine = source.getMachine();
+        summary = source.getSummary();
+        config.copy(source.getConfig());
+        returnResultTransformation = source.returnResultTransformation;
+        returnType = source.returnType;
+        runAsScript = source.runAsScript;
+        runAsRoot = source.runAsRoot;
+        requireExitCodeZero = source.requireExitCodeZero;
+        extraErrorMessage = source.extraErrorMessage;
+        shellEnvironment.putAll(source.getShellEnvironment());
+        completionListeners.addAll(source.getCompletionListeners());
+    }
+
+    public String getSummary() {
+        if (summary!=null) return summary;
+        return Strings.maxlen(Strings.join(commands, " ; "), 160);
+    }
+    
+    /** null for localhost */
+    public SshMachineLocation getMachine() {
+        return machine;
+    }
+    
+    public Map<String, String> getShellEnvironment() {
+        return ImmutableMap.copyOf(shellEnvironment);
+    }
+ 
+    @Override
+    public String toString() {
+        return super.toString()+"["+getSummary()+"]";
+    }
+
+    public List<String> getCommands() {
+        return ImmutableList.copyOf(commands);
+    }
+ 
+    public List<Function<ProcessTaskWrapper<?>, Void>> getCompletionListeners() {
+        return completionListeners;
+    }
+
+    protected ConfigBag getConfig() { return config; }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskWrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskWrapper.java b/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskWrapper.java
new file mode 100644
index 0000000..045b3c9
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/system/ProcessTaskWrapper.java
@@ -0,0 +1,187 @@
+/*
+ * 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.util.task.system;
+
+import java.io.ByteArrayOutputStream;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskWrapper;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.system.internal.AbstractProcessTaskFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.BrooklynTaskTags;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Function;
+
+/** Wraps a fully constructed process task, and allows callers to inspect status. 
+ * Note that methods in here such as {@link #getStdout()} will return partially completed streams while the task is ongoing
+ * (and exit code will be null). You can {@link #block()} or {@link #get()} as conveniences on the underlying {@link #getTask()}. */ 
+public abstract class ProcessTaskWrapper<RET> extends ProcessTaskStub implements TaskWrapper<RET> {
+
+    private static final Logger log = LoggerFactory.getLogger(ProcessTaskWrapper.class);
+    
+    private final Task<RET> task;
+
+    // execution details
+    protected ByteArrayOutputStream stdout = new ByteArrayOutputStream();
+    protected ByteArrayOutputStream stderr = new ByteArrayOutputStream();
+    protected Integer exitCode = null;
+    
+    @SuppressWarnings("unchecked")
+    protected ProcessTaskWrapper(AbstractProcessTaskFactory<?,RET> constructor) {
+        super(constructor);
+        TaskBuilder<Object> tb = constructor.constructCustomizedTaskBuilder();
+        if (stdout!=null) tb.tag(BrooklynTaskTags.tagForStreamSoft(BrooklynTaskTags.STREAM_STDOUT, stdout));
+        if (stderr!=null) tb.tag(BrooklynTaskTags.tagForStreamSoft(BrooklynTaskTags.STREAM_STDERR, stderr));
+        task = (Task<RET>) tb.body(new ProcessTaskInternalJob()).build();
+    }
+    
+    @Override
+    public Task<RET> asTask() {
+        return getTask();
+    }
+    
+    @Override
+    public Task<RET> getTask() {
+        return task;
+    }
+    
+    public Integer getExitCode() {
+        return exitCode;
+    }
+    
+    public byte[] getStdoutBytes() {
+        if (stdout==null) return null;
+        return stdout.toByteArray();
+    }
+    
+    public byte[] getStderrBytes() {
+        if (stderr==null) return null;
+        return stderr.toByteArray();
+    }
+    
+    public String getStdout() {
+        if (stdout==null) return null;
+        return stdout.toString();
+    }
+    
+    public String getStderr() {
+        if (stderr==null) return null;
+        return stderr.toString();
+    }
+
+    protected class ProcessTaskInternalJob implements Callable<Object> {
+        @Override
+        public Object call() throws Exception {
+            run( getConfigForRunning() );
+            
+            for (Function<ProcessTaskWrapper<?>, Void> listener: completionListeners) {
+                try {
+                    listener.apply(ProcessTaskWrapper.this);
+                } catch (Exception e) {
+                    logWithDetailsAndThrow("Error in "+taskTypeShortName()+" task "+getSummary()+": "+e, e);                    
+                }
+            }
+            
+            if (exitCode!=0 && !Boolean.FALSE.equals(requireExitCodeZero)) {
+                if (Boolean.TRUE.equals(requireExitCodeZero)) {
+                    logWithDetailsAndThrow(taskTypeShortName()+" task ended with exit code "+exitCode+" when 0 was required, in "+Tasks.current()+": "+getSummary(), null);
+                } else {
+                    // warn, but allow, on non-zero not explicitly allowed
+                    log.warn(taskTypeShortName()+" task ended with exit code "+exitCode+" when non-zero was not explicitly allowed (error may be thrown in future), in "
+                            +Tasks.current()+": "+getSummary());
+                }
+            }
+            switch (returnType) {
+            case CUSTOM: return returnResultTransformation.apply(ProcessTaskWrapper.this);
+            case STDOUT_STRING: return stdout.toString();
+            case STDOUT_BYTES: return stdout.toByteArray();
+            case STDERR_STRING: return stderr.toString();
+            case STDERR_BYTES: return stderr.toByteArray();
+            case EXIT_CODE: return exitCode;
+            }
+
+            throw new IllegalStateException("Unknown return type for "+taskTypeShortName()+" job "+getSummary()+": "+returnType);
+        }
+
+        protected void logWithDetailsAndThrow(String message, Throwable optionalCause) {
+            message = (extraErrorMessage!=null ? extraErrorMessage+": " : "") + message;
+            log.warn(message+" (throwing)");
+            logProblemDetails("STDERR", stderr, 1024);
+            logProblemDetails("STDOUT", stdout, 1024);
+            logProblemDetails("STDIN", Streams.byteArrayOfString(Strings.join(commands,"\n")), 4096);
+            if (optionalCause!=null) throw new IllegalStateException(message, optionalCause);
+            throw new IllegalStateException(message);
+        }
+        
+        protected void logProblemDetails(String streamName, ByteArrayOutputStream stream, int max) {
+            Streams.logStreamTail(log, streamName+" for problem in "+Tasks.current(), stream, max);
+        }
+
+    }
+    
+    @Override
+    public String toString() {
+        return super.toString()+"["+task+"]";
+    }
+
+    /** blocks and gets the result, throwing if there was an exception */
+    public RET get() {
+        return getTask().getUnchecked();
+    }
+    
+    /** blocks until the task completes; does not throw */
+    public ProcessTaskWrapper<RET> block() {
+        getTask().blockUntilEnded();
+        return this;
+    }
+ 
+    /** true iff the process has completed (with or without failure) */
+    public boolean isDone() {
+        return getTask().isDone();
+    }
+
+    /** for overriding */
+    protected ConfigBag getConfigForRunning() {
+        ConfigBag config = ConfigBag.newInstanceCopying(ProcessTaskWrapper.this.config);
+        if (stdout!=null) config.put(ShellTool.PROP_OUT_STREAM, stdout);
+        if (stderr!=null) config.put(ShellTool.PROP_ERR_STREAM, stderr);
+        
+        if (!config.containsKey(ShellTool.PROP_NO_EXTRA_OUTPUT))
+            // by default no extra output (so things like cat, etc work as expected)
+            config.put(ShellTool.PROP_NO_EXTRA_OUTPUT, true);
+
+        if (runAsRoot)
+            config.put(ShellTool.PROP_RUN_AS_ROOT, true);
+        return config;
+    }
+
+    protected abstract void run(ConfigBag config);
+    
+    protected abstract String taskTypeShortName();
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/system/SystemTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/system/SystemTasks.java b/core/src/main/java/org/apache/brooklyn/core/util/task/system/SystemTasks.java
new file mode 100644
index 0000000..d05b09c
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/system/SystemTasks.java
@@ -0,0 +1,29 @@
+/*
+ * 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.util.task.system;
+
+import org.apache.brooklyn.core.util.task.system.internal.SystemProcessTaskFactory.ConcreteSystemProcessTaskFactory;
+
+public class SystemTasks {
+
+    public static ProcessTaskFactory<Integer> exec(String ...commands) {
+        return new ConcreteSystemProcessTaskFactory<Integer>(commands);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/AbstractProcessTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/AbstractProcessTaskFactory.java b/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/AbstractProcessTaskFactory.java
new file mode 100644
index 0000000..8b90263
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/AbstractProcessTaskFactory.java
@@ -0,0 +1,216 @@
+/*
+ * 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.util.task.system.internal;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.BrooklynTaskTags;
+
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskStub;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+public abstract class AbstractProcessTaskFactory<T extends AbstractProcessTaskFactory<T,RET>,RET> extends ProcessTaskStub implements ProcessTaskFactory<RET> {
+    
+    private static final Logger log = LoggerFactory.getLogger(AbstractProcessTaskFactory.class);
+    
+    protected boolean dirty = false;
+    
+    public AbstractProcessTaskFactory(String ...commands) {
+        this.commands.addAll(Arrays.asList(commands));
+    }
+
+    @SuppressWarnings("unchecked")
+    protected T self() { return (T)this; }
+    
+    protected void markDirty() {
+        dirty = true;
+    }
+    
+    @Override
+    public T add(String ...commandsToAdd) {
+        markDirty();
+        for (String commandToAdd: commandsToAdd) this.commands.add(commandToAdd);
+        return self();
+    }
+
+    @Override
+    public T add(Iterable<String> commandsToAdd) {
+        Iterables.addAll(this.commands, commandsToAdd);
+        return self();
+    }
+    
+    @Override
+    public T machine(SshMachineLocation machine) {
+        markDirty();
+        this.machine = machine;
+        return self();
+    }
+
+    @Override
+    public T requiringExitCodeZero() {
+        markDirty();
+        requireExitCodeZero = true;
+        return self();
+    }
+    
+    @Override
+    public T requiringExitCodeZero(String extraErrorMessage) {
+        markDirty();
+        requireExitCodeZero = true;
+        this.extraErrorMessage = extraErrorMessage;
+        return self();
+    }
+    
+    @Override
+    public T allowingNonZeroExitCode() {
+        markDirty();
+        requireExitCodeZero = false;
+        return self();
+    }
+
+    @Override
+    public ProcessTaskFactory<Boolean> returningIsExitCodeZero() {
+        if (requireExitCodeZero==null) allowingNonZeroExitCode();
+        return returning(new Function<ProcessTaskWrapper<?>,Boolean>() {
+            public Boolean apply(ProcessTaskWrapper<?> input) {
+                return input.getExitCode()==0;
+            }
+        });
+    }
+
+    @Override
+    public ProcessTaskFactory<String> requiringZeroAndReturningStdout() {
+        requiringExitCodeZero();
+        return this.<String>returning(ScriptReturnType.STDOUT_STRING);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <RET2> ProcessTaskFactory<RET2> returning(ScriptReturnType type) {
+        markDirty();
+        returnType = Preconditions.checkNotNull(type);
+        return (ProcessTaskFactory<RET2>) self();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <RET2> ProcessTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation) {
+        markDirty();
+        returnType = ScriptReturnType.CUSTOM;
+        this.returnResultTransformation = resultTransformation;
+        return (ProcessTaskFactory<RET2>) self();
+    }
+    
+    @Override
+    public T runAsCommand() {
+        markDirty();
+        runAsScript = false;
+        return self();
+    }
+
+    @Override
+    public T runAsScript() {
+        markDirty();
+        runAsScript = true;
+        return self();
+    }
+
+    @Override
+    public T runAsRoot() {
+        markDirty();
+        runAsRoot = true;
+        return self();
+    }
+    
+    @Override
+    public T environmentVariable(String key, String val) {
+        markDirty();
+        shellEnvironment.put(key, val);
+        return self();
+    }
+
+    @Override
+    public T environmentVariables(Map<String,String> vars) {
+        if (vars!=null) {
+            markDirty();
+            shellEnvironment.putAll(vars);
+        }
+        return self();
+    }
+
+    /** creates the TaskBuilder which can be further customized; typically invoked by the initial {@link #newTask()} */
+    public TaskBuilder<Object> constructCustomizedTaskBuilder() {
+        TaskBuilder<Object> tb = TaskBuilder.builder().dynamic(false).name("ssh: "+getSummary());
+        
+        tb.tag(BrooklynTaskTags.tagForStream(BrooklynTaskTags.STREAM_STDIN, 
+                Streams.byteArrayOfString(Strings.join(commands, "\n"))));
+        tb.tag(BrooklynTaskTags.tagForEnvStream(BrooklynTaskTags.STREAM_ENV, shellEnvironment));
+        
+        return tb;
+    }
+    
+    @Override
+    public T summary(String summary) {
+        markDirty();
+        this.summary = summary;
+        return self();
+    }
+
+    @Override
+    public <V> T configure(ConfigKey<V> key, V value) {
+        config.configure(key, value);
+        return self();
+    }
+    
+    @Override
+    public T configure(Map<?, ?> flags) {
+        if (flags!=null)
+            config.putAll(flags);
+        return self();
+    }
+ 
+    @Override
+    public T addCompletionListener(Function<ProcessTaskWrapper<?>, Void> listener) {
+        completionListeners.add(listener);
+        return self();
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        // help let people know of API usage error
+        if (dirty)
+            log.warn("Task "+this+" was modified but modification was never used");
+        super.finalize();
+    }
+}



[40/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/policy

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java b/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
index 9da5e12..18480bd 100644
--- a/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/autoscaling/AutoScalerPolicy.java
@@ -40,6 +40,7 @@ import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.core.util.task.Tasks;
@@ -52,7 +53,6 @@ import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.BasicNotificationSensor;
 import brooklyn.policy.autoscaling.SizeHistory.WindowSummary;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.loadbalancing.LoadBalancingPolicy;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java b/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
index dde1609..b76682c 100644
--- a/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/followthesun/FollowTheSunPolicy.java
@@ -38,12 +38,12 @@ import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.basic.Attributes;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.followthesun.FollowTheSunPool.ContainerItemPair;
 import brooklyn.policy.loadbalancing.Movable;
 import brooklyn.util.collections.MutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java b/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
index 0c2f4d2..9d8c58f 100644
--- a/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
+++ b/policy/src/main/java/brooklyn/policy/ha/AbstractFailureDetector.java
@@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.core.util.task.BasicTask;
 import org.apache.brooklyn.core.util.task.ScheduledTask;
@@ -38,7 +39,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityInternal;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/policy/src/main/java/brooklyn/policy/ha/ConditionalSuspendPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/ConditionalSuspendPolicy.java b/policy/src/main/java/brooklyn/policy/ha/ConditionalSuspendPolicy.java
index 9a869ae..b347949 100644
--- a/policy/src/main/java/brooklyn/policy/ha/ConditionalSuspendPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/ha/ConditionalSuspendPolicy.java
@@ -23,13 +23,13 @@ import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.javalang.JavaClassNames;
 
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/policy/src/main/java/brooklyn/policy/ha/ServiceReplacer.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/ServiceReplacer.java b/policy/src/main/java/brooklyn/policy/ha/ServiceReplacer.java
index 884f2df..6bea1d4 100644
--- a/policy/src/main/java/brooklyn/policy/ha/ServiceReplacer.java
+++ b/policy/src/main/java/brooklyn/policy/ha/ServiceReplacer.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
@@ -47,7 +48,6 @@ import brooklyn.entity.group.StopFailedRuntimeException;
 import brooklyn.entity.trait.MemberReplaceable;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.BasicNotificationSensor;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java b/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
index d53434e..ab1359d 100644
--- a/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
+++ b/policy/src/main/java/brooklyn/policy/ha/ServiceRestarter.java
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
@@ -39,7 +40,6 @@ import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.basic.ServiceStateLogic;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.BasicNotificationSensor;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.ha.HASensors.FailureDescriptor;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.javalang.JavaClassNames;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java b/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
index 2c50883..57b736b 100644
--- a/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
+++ b/policy/src/main/java/brooklyn/policy/loadbalancing/LoadBalancingPolicy.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,7 +43,6 @@ import org.slf4j.LoggerFactory;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.policy.autoscaling.AutoScalerPolicy;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.policy.loadbalancing.BalanceableWorkerPool.ContainerItemPair;
 import brooklyn.util.collections.MutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestReferencingPolicy.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestReferencingPolicy.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestReferencingPolicy.java
index f175e0d..d3f550b 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestReferencingPolicy.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/TestReferencingPolicy.java
@@ -19,10 +19,10 @@
 package org.apache.brooklyn.camp.brooklyn;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.policy.basic.AbstractPolicy;
 
 public class TestReferencingPolicy extends AbstractPolicy {
     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/54f5c363/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 4d22b3f..e25b47a 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,6 +31,7 @@ import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.core.util.javalang.UrlClassLoader;
 import org.reflections.Reflections;
@@ -45,7 +46,6 @@ import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
index 31a3b99..c5ea74a 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyResource.java
@@ -25,13 +25,11 @@ import javax.ws.rs.core.Response;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
-import brooklyn.policy.basic.Policies;
-
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.policy.basic.Policies;
 import org.apache.brooklyn.rest.api.PolicyApi;
 import org.apache.brooklyn.rest.domain.PolicySummary;
 import org.apache.brooklyn.rest.domain.Status;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
index a43127c..35e62d6 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/transform/PolicyTransformer.java
@@ -22,11 +22,11 @@ import java.net.URI;
 import java.util.Map;
 
 import brooklyn.config.ConfigKey;
-import brooklyn.policy.basic.Policies;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.core.policy.basic.Policies;
 import org.apache.brooklyn.rest.domain.ApplicationSummary;
 import org.apache.brooklyn.rest.domain.PolicyConfigSummary;
 import org.apache.brooklyn.rest.domain.PolicySummary;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/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 d29b6e8..751eb22 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
@@ -53,6 +53,7 @@ import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
 import org.apache.brooklyn.core.management.entitlement.Entitlements.StringAndArgument;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import brooklyn.config.ConfigKey;
@@ -64,7 +65,6 @@ import brooklyn.entity.basic.BasicApplication;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.trait.Startable;
-import brooklyn.policy.basic.AbstractPolicy;
 
 import org.apache.brooklyn.rest.domain.ApplicationSpec;
 import org.apache.brooklyn.rest.domain.EntitySpec;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/CapitalizePolicy.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/CapitalizePolicy.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/CapitalizePolicy.java
index d324507..5881990 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/CapitalizePolicy.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/CapitalizePolicy.java
@@ -19,8 +19,7 @@
 package org.apache.brooklyn.rest.testing.mocks;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
-
-import brooklyn.policy.basic.AbstractPolicy;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 
 public class CapitalizePolicy extends AbstractPolicy {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimplePolicy.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimplePolicy.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimplePolicy.java
index d6e2b77..f1546ff 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimplePolicy.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/testing/mocks/RestMockSimplePolicy.java
@@ -20,13 +20,13 @@ package org.apache.brooklyn.rest.testing.mocks;
 
 import java.util.Map;
 
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.policy.basic.AbstractPolicy;
 
 public class RestMockSimplePolicy extends AbstractPolicy {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/usage/rest-server/src/test/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtilsTest.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtilsTest.java b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtilsTest.java
index 484f6ab..2c5c1d6 100644
--- a/usage/rest-server/src/test/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtilsTest.java
+++ b/usage/rest-server/src/test/java/org/apache/brooklyn/rest/util/BrooklynRestResourceUtilsTest.java
@@ -36,12 +36,12 @@ import org.apache.brooklyn.core.catalog.internal.CatalogItemBuilder;
 import org.apache.brooklyn.core.catalog.internal.CatalogTemplateItemDto;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 
 import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.basic.BasicEntity;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.proxying.EntityProxy;
-import brooklyn.policy.basic.AbstractPolicy;
 
 import org.apache.brooklyn.rest.domain.ApplicationSpec;
 import org.apache.brooklyn.rest.domain.EntitySpec;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimplePolicy.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimplePolicy.java b/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimplePolicy.java
index f70b60b..a034886 100644
--- a/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimplePolicy.java
+++ b/utils/test-bundles/entities/src/main/java/brooklyn/osgi/tests/SimplePolicy.java
@@ -19,11 +19,11 @@
 package brooklyn.osgi.tests;
 
 
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.config.ConfigKey;
-import brooklyn.policy.basic.AbstractPolicy;
 
 public class SimplePolicy extends AbstractPolicy {
     @SetFromFlag("config1")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/utils/test-bundles/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MorePolicy.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MorePolicy.java b/utils/test-bundles/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MorePolicy.java
index 50b5945..466d8e2 100644
--- a/utils/test-bundles/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MorePolicy.java
+++ b/utils/test-bundles/more-entities-v1/src/main/java/brooklyn/osgi/tests/more/MorePolicy.java
@@ -20,8 +20,7 @@ package brooklyn.osgi.tests.more;
 
 
 import org.apache.brooklyn.api.catalog.Catalog;
-
-import brooklyn.policy.basic.AbstractPolicy;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 
 public class MorePolicy extends AbstractPolicy {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/utils/test-bundles/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MorePolicy.java
----------------------------------------------------------------------
diff --git a/utils/test-bundles/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MorePolicy.java b/utils/test-bundles/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MorePolicy.java
index 4bfa366..43c53b5 100644
--- a/utils/test-bundles/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MorePolicy.java
+++ b/utils/test-bundles/more-entities-v2/src/main/java/brooklyn/osgi/tests/more/MorePolicy.java
@@ -20,7 +20,7 @@ package brooklyn.osgi.tests.more;
 
 
 import org.apache.brooklyn.api.catalog.Catalog;
-import brooklyn.policy.basic.AbstractPolicy;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 
 @Catalog(name="More Policy", description="Cataliog item OSGi test policy")
 public class MorePolicy extends AbstractPolicy {


[22/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjTool.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjTool.java
new file mode 100644
index 0000000..8262729
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjTool.java
@@ -0,0 +1,1091 @@
+/*
+ * 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.util.internal.ssh.sshj;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Throwables.getCausalChain;
+import static com.google.common.collect.Iterables.any;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import net.schmizz.sshj.connection.ConnectionException;
+import net.schmizz.sshj.connection.channel.direct.PTYMode;
+import net.schmizz.sshj.connection.channel.direct.Session;
+import net.schmizz.sshj.connection.channel.direct.Session.Command;
+import net.schmizz.sshj.connection.channel.direct.Session.Shell;
+import net.schmizz.sshj.connection.channel.direct.SessionChannel;
+import net.schmizz.sshj.sftp.FileAttributes;
+import net.schmizz.sshj.sftp.SFTPClient;
+import net.schmizz.sshj.transport.TransportException;
+import net.schmizz.sshj.xfer.InMemorySourceFile;
+
+import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
+import org.apache.brooklyn.core.util.internal.ssh.BackoffLimitedRetryHandler;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshAbstractTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.commons.io.input.ProxyInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.RuntimeTimeoutException;
+import brooklyn.util.io.FileUtil;
+import brooklyn.util.repeat.Repeater;
+import brooklyn.util.stream.KnownSizeInputStream;
+import brooklyn.util.stream.StreamGobbler;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.base.Predicate;
+import com.google.common.base.Stopwatch;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.CountingOutputStream;
+import com.google.common.net.HostAndPort;
+import com.google.common.primitives.Ints;
+
+/**
+ * For ssh and scp-style commands, using the sshj library.
+ */
+public class SshjTool extends SshAbstractTool implements SshTool {
+
+    /*
+     * TODO synchronization of connect/disconnect needs revisited!
+     * Saw SshjToolIntegrationTest.testExecBigConcurrentCommand fail with:
+     *     Caused by: java.lang.AssertionError
+     *         at net.schmizz.sshj.SSHClient.auth(SSHClient.java:204)
+     * i.e. another thread had called disconnect just before the failing thread
+     * did SSHClient.auth.
+     * Having multiple threads call connect/disconnect is going to be brittle. With
+     * our retries we can get away with it usually, but it's not good!
+     *
+     * TODO need to upgrade sshj version from 0.8.1 to 0.9, but jclouds 1.7.2 still 
+     * relies on 0.8.1. In 0.9, it fixes the https://github.com/shikhar/sshj/issues/89
+     * so does not throw AssertionError.
+     */
+
+    private static final Logger LOG = LoggerFactory.getLogger(SshjTool.class);
+
+    protected final int sshTries;
+    protected final long sshTriesTimeout;
+    protected final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
+
+    /** Terminal type name for {@code allocatePTY} option. */
+    final static String TERM = "vt100"; // "dumb"
+    
+    private class CloseFtpChannelOnCloseInputStream extends ProxyInputStream {
+        private final SFTPClient sftp;
+
+        private CloseFtpChannelOnCloseInputStream(InputStream proxy, SFTPClient sftp) {
+            super(proxy);
+            this.sftp = sftp;
+        }
+
+        @Override
+        public void close() throws IOException {
+            super.close();
+            closeWhispering(sftp, this);
+        }
+    }
+
+    private final SshjClientConnection sshClientConnection;
+
+    public static SshjToolBuilder builder() {
+        return new SshjToolBuilder();
+    }
+    
+    public static class SshjToolBuilder extends Builder<SshjTool, SshjToolBuilder> {
+    }
+    
+    public static class Builder<T extends SshjTool, B extends Builder<T,B>> extends AbstractSshToolBuilder<T,B> {
+        protected long connectTimeout;
+        protected long sessionTimeout;
+        protected int sshTries = 4;  //allow 4 tries by default, much safer
+        protected long sshTriesTimeout = 2*60*1000;  //allow 2 minutes by default (so if too slow trying sshTries times, abort anyway)
+        protected long sshRetryDelay = 50L;
+        
+        @Override
+        public B from(Map<String,?> props) {
+            super.from(props);
+            sshTries = getOptionalVal(props, PROP_SSH_TRIES);
+            sshTriesTimeout = getOptionalVal(props, PROP_SSH_TRIES_TIMEOUT);
+            sshRetryDelay = getOptionalVal(props, PROP_SSH_RETRY_DELAY);
+            connectTimeout = getOptionalVal(props, PROP_CONNECT_TIMEOUT);
+            sessionTimeout = getOptionalVal(props, PROP_SESSION_TIMEOUT);
+            return self();
+        }
+        public B connectTimeout(int val) {
+            this.connectTimeout = val; return self();
+        }
+        public B sessionTimeout(int val) {
+            this.sessionTimeout = val; return self();
+        }
+        public B sshRetries(int val) {
+            this.sshTries = val; return self();
+        }
+        public B sshRetriesTimeout(int val) {
+            this.sshTriesTimeout = val; return self();
+        }
+        public B sshRetryDelay(long val) {
+            this.sshRetryDelay = val; return self();
+        }
+        @Override
+        @SuppressWarnings("unchecked")
+        public T build() {
+            return (T) new SshjTool(this);
+        }
+    }
+
+    public SshjTool(Map<String,?> map) {
+        this(builder().from(map));
+    }
+    
+    protected SshjTool(Builder<?,?> builder) {
+        super(builder);
+        
+        sshTries = builder.sshTries;
+        sshTriesTimeout = builder.sshTriesTimeout;
+        backoffLimitedRetryHandler = new BackoffLimitedRetryHandler(sshTries, builder.sshRetryDelay);
+
+        sshClientConnection = SshjClientConnection.builder()
+                .hostAndPort(HostAndPort.fromParts(host, port))
+                .username(user)
+                .password(password)
+                .privateKeyPassphrase(privateKeyPassphrase)
+                .privateKeyData(privateKeyData)
+                .privateKeyFile(privateKeyFile)
+                .strictHostKeyChecking(strictHostKeyChecking)
+                .connectTimeout(builder.connectTimeout)
+                .sessionTimeout(builder.sessionTimeout)
+                .build();
+        
+        if (LOG.isTraceEnabled()) LOG.trace("Created SshTool {} ({})", this, System.identityHashCode(this));
+    }
+    
+    @Override
+    public void connect() {
+        try {
+            if (LOG.isTraceEnabled()) LOG.trace("Connecting SshjTool {} ({})", this, System.identityHashCode(this));
+            acquire(sshClientConnection);
+        } catch (Exception e) {
+            if (LOG.isDebugEnabled()) LOG.debug(toString()+" failed to connect (rethrowing)", e);
+            throw propagate(e, "failed to connect");
+        }
+    }
+
+    @Override
+    @Deprecated // see super
+    public void connect(int maxAttempts) {
+        connect(); // FIXME Should callers instead configure sshTries? But that would apply to all ssh attempts
+    }
+
+    @Override
+    public void disconnect() {
+        if (LOG.isTraceEnabled()) LOG.trace("Disconnecting SshjTool {} ({})", this, System.identityHashCode(this));
+        try {
+            Stopwatch perfStopwatch = Stopwatch.createStarted();
+            sshClientConnection.clear();
+            if (LOG.isTraceEnabled()) LOG.trace("SSH Performance: {} disconnect took {}", sshClientConnection.getHostAndPort(), Time.makeTimeStringRounded(perfStopwatch));
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    @Override
+    public boolean isConnected() {
+        return sshClientConnection.isConnected() && sshClientConnection.isAuthenticated();
+    }
+    
+    @Override
+    public int copyToServer(java.util.Map<String,?> props, byte[] contents, String pathAndFileOnRemoteServer) {
+        return copyToServer(props, newInputStreamSupplier(contents), contents.length, pathAndFileOnRemoteServer);
+    }
+    
+    @Override
+    public int copyToServer(Map<String,?> props, InputStream contents, String pathAndFileOnRemoteServer) {
+        /* sshj needs to:
+         *   1) to know the length of the InputStream to copy the file to perform copy; and
+         *   2) re-read the input stream on retry if the first attempt fails.
+         * For now, write it to a file, unless caller supplies a KnownSizeInputStream
+         * 
+         * (We could have a switch where we hold it in memory if less than some max size,
+         * but most the routines should supply a string or byte array or similar,
+         * so we probably don't come here too often.)
+         */
+        if (contents instanceof KnownSizeInputStream) {
+            return copyToServer(props, Suppliers.ofInstance(contents), ((KnownSizeInputStream)contents).length(), pathAndFileOnRemoteServer);
+        } else {
+            File tempFile = writeTempFile(contents);
+            try {
+                return copyToServer(props, tempFile, pathAndFileOnRemoteServer);
+            } finally {
+                tempFile.delete();
+            }
+        }
+    }
+    
+    @Override
+    public int copyToServer(Map<String,?> props, File localFile, String pathAndFileOnRemoteServer) {
+        return copyToServer(props, newInputStreamSupplier(localFile), (int)localFile.length(), pathAndFileOnRemoteServer);
+    }
+    
+    private int copyToServer(Map<String,?> props, Supplier<InputStream> contentsSupplier, long length, String pathAndFileOnRemoteServer) {
+        acquire(new PutFileAction(props, pathAndFileOnRemoteServer, contentsSupplier, length));
+        return 0; // TODO Can we assume put will have thrown exception if failed? Rather than exit code != 0?
+    }
+
+
+    @Override
+    public int copyFromServer(Map<String,?> props, String pathAndFileOnRemoteServer, File localFile) {
+        InputStream contents = acquire(new GetFileAction(pathAndFileOnRemoteServer));
+        try {
+            FileUtil.copyTo(contents, localFile);
+            return 0; // TODO Can we assume put will have thrown exception if failed? Rather than exit code != 0?
+        } finally {
+            Streams.closeQuietly(contents);
+        }
+    }
+
+    /**
+     * This creates a script containing the user's commands, copies it to the remote server, and
+     * executes the script. The script is then deleted.
+     * <p>
+     * Executing commands directly is fraught with dangers! Here are other options, and their problems:
+     * <ul>
+     *   <li>Use execCommands, rather than shell.
+     *       The user's environment will not be setup normally (e.g. ~/.bash_profile will not have been sourced)
+     *       so things like wget may not be on the PATH.
+     *   <li>Send the stream of commands to the shell.
+     *       But characters being sent can be lost.
+     *       Try the following (e.g. in an OS X terminal):
+     *        - sleep 5
+     *        - <paste a command that is 1000s of characters long>
+     *       Only the first 1024 characters appear. The rest are lost.
+     *       If sending a stream of commands, you need to be careful not send the next (big) command while the
+     *       previous one is still executing.
+     *   <li>Send a stream to the shell, but spot when the previous command has completed.
+     *       e.g. by looking for the prompt (but what if the commands being executed change the prompt?)
+     *       e.g. by putting every second command as "echo <uid>", and waiting for the stdout.
+     *       This gets fiddly...
+     * </ul>
+     * 
+     * So on balance, the script-based approach seems most reliable, even if there is an overhead
+     * of separate message(s) for copying the file!
+     * 
+     * Another consideration is long-running scripts. On some clouds when executing a script that takes 
+     * several minutes, we have seen it fail with -1 (e.g. 1 in 20 times). This suggests the ssh connection
+     * is being dropped. To avoid this problem, we can execute the script asynchronously, writing to files
+     * the stdout/stderr/pid/exitStatus. We then periodically poll to retrieve the contents of these files.
+     * Use {@link #PROP_EXEC_ASYNC} to force this mode of execution.
+     */
+    @Override
+    public int execScript(final Map<String,?> props, final List<String> commands, final Map<String,?> env) {
+        Boolean execAsync = getOptionalVal(props, PROP_EXEC_ASYNC);
+        if (Boolean.TRUE.equals(execAsync) && BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC)) {
+            return execScriptAsyncAndPoll(props, commands, env);
+        } else {
+            if (Boolean.TRUE.equals(execAsync)) {
+                if (LOG.isDebugEnabled()) LOG.debug("Ignoring ssh exec-async configuration, because feature is disabled");
+            }
+            return new ToolAbstractExecScript(props) {
+                public int run() {
+                    String scriptContents = toScript(props, commands, env);
+                    if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} as script: {}", host, scriptContents);
+                    copyToServer(ImmutableMap.of("permissions", "0700"), scriptContents.getBytes(), scriptPath);
+                    return asInt(acquire(new ShellAction(buildRunScriptCommand(), out, err, execTimeout)), -1);
+                }
+            }.run();
+        }
+    }
+
+    /**
+     * Executes the script in the background (`nohup ... &`), and then executes other ssh commands to poll for the
+     * stdout, stderr and exit code of that original process (which will each have been written to separate files).
+     * 
+     * The polling is a "long poll". That is, it executes a long-running ssh command to retrieve the stdout, etc.
+     * If that long-poll command fails, then we just execute another one to pick up from where it left off.
+     * This means we do not need to execute many ssh commands (which are expensive), but can still return promptly
+     * when the command completes.
+     * 
+     * Much of this was motivated by https://issues.apache.org/jira/browse/BROOKLYN-106, which is no longer
+     * an issue. The retries (e.g. in the upload-script) are arguably overkill given that {@link #acquire(SshAction)}
+     * will already retry. However, leaving this in place as it could prove useful when working with flakey
+     * networks in the future.
+     * 
+     * TODO There are (probably) issues with this method when using {@link ShellTool#PROP_RUN_AS_ROOT}.
+     * I (Aled) saw the .pid file having an owner of root:root, and a failure message in stderr of:
+     *   -bash: line 3: /tmp/brooklyn-20150113-161203056-XMEo-move_install_dir_from_user_to_.pid: Permission denied
+     */
+    protected int execScriptAsyncAndPoll(final Map<String,?> props, final List<String> commands, final Map<String,?> env) {
+        return new ToolAbstractAsyncExecScript(props) {
+            private int maxConsecutiveSshFailures = 3;
+            private Duration maxDelayBetweenPolls = Duration.seconds(20);
+            private Duration pollTimeout = getOptionalVal(props, PROP_EXEC_ASYNC_POLLING_TIMEOUT, Duration.FIVE_MINUTES);
+            private int iteration = 0;
+            private int consecutiveSshFailures = 0;
+            private int stdoutCount = 0;
+            private int stderrCount = 0;
+            private Stopwatch timer;
+            
+            public int run() {
+                timer = Stopwatch.createStarted();
+                final String scriptContents = toScript(props, commands, env);
+                if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} as async script: {}", host, scriptContents);
+                
+                // Upload script; try repeatedly because have seen timeout intermittently on vcloud-director (BROOKLYN-106 related).
+                boolean uploadSuccess = Repeater.create("async script upload on "+SshjTool.this.toString()+" (for "+getSummary()+")")
+                        .backoffTo(maxDelayBetweenPolls)
+                        .limitIterationsTo(3)
+                        .rethrowException()
+                        .until(new Callable<Boolean>() {
+                            @Override
+                            public Boolean call() throws Exception {
+                                iteration++;
+                                if (LOG.isDebugEnabled()) {
+                                    String msg = "Uploading (iteration="+iteration+") for async script on "+SshjTool.this.toString()+" (for "+getSummary()+")";
+                                    if (iteration == 1) {
+                                        LOG.trace(msg);
+                                    } else {
+                                        LOG.debug(msg);
+                                    }
+                                }
+                                copyToServer(ImmutableMap.of("permissions", "0700"), scriptContents.getBytes(), scriptPath);
+                                return true;
+                            }})
+                        .run();
+                
+                if (!uploadSuccess) {
+                    // Unexpected! Should have either returned true or have rethrown the exception; should never get false.
+                    String msg = "Unexpected state: repeated failure for async script upload on "+SshjTool.this.toString()+" ("+getSummary()+")";
+                    LOG.warn(msg+"; rethrowing");
+                    throw new IllegalStateException(msg);
+                }
+                
+                // Execute script asynchronously
+                int execResult = asInt(acquire(new ShellAction(buildRunScriptCommand(), out, err, execTimeout)), -1);
+                if (execResult != 0) return execResult;
+
+                // Long polling to get the status
+                try {
+                    final AtomicReference<Integer> result = new AtomicReference<Integer>();
+                    boolean success = Repeater.create("async script long-poll on "+SshjTool.this.toString()+" (for "+getSummary()+")")
+                            .backoffTo(maxDelayBetweenPolls)
+                            .limitTimeTo(execTimeout)
+                            .until(new Callable<Boolean>() {
+                                @Override
+                                public Boolean call() throws Exception {
+                                    iteration++;
+                                    if (LOG.isDebugEnabled()) LOG.debug("Doing long-poll (iteration="+iteration+") for async script to complete on "+SshjTool.this.toString()+" (for "+getSummary()+")");
+                                    Integer exitstatus = longPoll();
+                                    result.set(exitstatus);
+                                    return exitstatus != null;
+                                }})
+                            .run();
+                    
+                    if (!success) {
+                        // Timed out
+                        String msg = "Timeout for async script to complete on "+SshjTool.this.toString()+" ("+getSummary()+")";
+                        LOG.warn(msg+"; rethrowing");
+                        throw new TimeoutException(msg);
+                    }
+                    
+                    return result.get();
+                    
+                } catch (Exception e) {
+                    LOG.debug("Problem polling for async script on "+SshjTool.this.toString()+" (for "+getSummary()+"); rethrowing after deleting temporary files", e);
+                    throw Exceptions.propagate(e);
+                } finally {
+                    // Delete the temporary files created (and the `tail -c` commands that might have been left behind by long-polls).
+                    // Using pollTimeout so doesn't wait forever, but waits for a reasonable (configurable) length of time.
+                    // TODO also execute this if the `buildRunScriptCommand` fails, as that might have left files behind?
+                    try {
+                        int execDeleteResult = asInt(acquire(new ShellAction(deleteTemporaryFilesCommand(), out, err, pollTimeout)), -1);
+                        if (execDeleteResult != 0) {
+                            LOG.debug("Problem deleting temporary files of async script on "+SshjTool.this.toString()+" (for "+getSummary()+"): exit status "+execDeleteResult);
+                        }
+                    } catch (Exception e) {
+                        Exceptions.propagateIfFatal(e);
+                        LOG.debug("Problem deleting temporary files of async script on "+SshjTool.this.toString()+" (for "+getSummary()+"); continuing", e);
+                    }
+                }
+            }
+            
+            Integer longPoll() throws IOException {
+                // Long-polling to get stdout, stderr + exit status of async task.
+                // If our long-poll disconnects, we will just re-execute.
+                // We wrap the stdout/stderr so that we can get the size count. 
+                // If we disconnect, we will pick up from that char of the stream.
+                // TODO Additional stdout/stderr written by buildLongPollCommand() could interfere, 
+                //      causing us to miss some characters.
+                Duration nextPollTimeout = Duration.min(pollTimeout, Duration.millis(execTimeout.toMilliseconds()-timer.elapsed(TimeUnit.MILLISECONDS)));
+                CountingOutputStream countingOut = (out == null) ? null : new CountingOutputStream(out);
+                CountingOutputStream countingErr = (err == null) ? null : new CountingOutputStream(err);
+                List<String> pollCommand = buildLongPollCommand(stdoutCount, stderrCount, nextPollTimeout);
+                Duration sshJoinTimeout = nextPollTimeout.add(Duration.TEN_SECONDS);
+                ShellAction action = new ShellAction(pollCommand, countingOut, countingErr, sshJoinTimeout);
+                
+                int longPollResult;
+                try {
+                    longPollResult = asInt(acquire(action, 3, nextPollTimeout), -1);
+                } catch (RuntimeTimeoutException e) {
+                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll timed out on "+SshjTool.this.toString()+" (for "+getSummary()+"): "+e);
+                    return null;
+                }
+                stdoutCount += (countingOut == null) ? 0 : countingOut.getCount();
+                stderrCount += (countingErr == null) ? 0 : countingErr.getCount();
+                
+                if (longPollResult == 0) {
+                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll succeeded (exit status 0) on "+SshjTool.this.toString()+" (for "+getSummary()+")");
+                    return longPollResult; // success
+                    
+                } else if (longPollResult == -1) {
+                    // probably a connection failure; try again
+                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll received exit status -1; will retry on "+SshjTool.this.toString()+" (for "+getSummary()+")");
+                    return null;
+
+                } else if (longPollResult == 125) {
+                    // 125 is the special code for timeout in long-poll (see buildLongPollCommand).
+                    // However, there is a tiny chance that the underlying command might have returned that exact exit code!
+                    // Don't treat a timeout as a "consecutiveSshFailure".
+                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll received exit status "+longPollResult+"; most likely timeout; retrieving actual status on "+SshjTool.this.toString()+" (for "+getSummary()+")");
+                    return retrieveStatusCommand();
+
+                } else {
+                    // want to double-check whether this is the exit-code from the async process, or
+                    // some unexpected failure in our long-poll command.
+                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll received exit status "+longPollResult+"; retrieving actual status on "+SshjTool.this.toString()+" (for "+getSummary()+")");
+                    Integer result = retrieveStatusCommand();
+                    if (result != null) {
+                        return result;
+                    }
+                }
+                    
+                consecutiveSshFailures++;
+                if (consecutiveSshFailures > maxConsecutiveSshFailures) {
+                    LOG.warn("Aborting on "+consecutiveSshFailures+" consecutive ssh connection errors (return -1) when polling for async script to complete on "+SshjTool.this.toString()+" ("+getSummary()+")");
+                    return -1;
+                } else {
+                    LOG.info("Retrying after ssh connection error when polling for async script to complete on "+SshjTool.this.toString()+" ("+getSummary()+")");
+                    return null;
+                }
+            }
+            
+            Integer retrieveStatusCommand() throws IOException {
+                // want to double-check whether this is the exit-code from the async process, or
+                // some unexpected failure in our long-poll command.
+                ByteArrayOutputStream statusOut = new ByteArrayOutputStream();
+                ByteArrayOutputStream statusErr = new ByteArrayOutputStream();
+                int statusResult = asInt(acquire(new ShellAction(buildRetrieveStatusCommand(), statusOut, statusErr, execTimeout)), -1);
+                
+                if (statusResult == 0) {
+                    // The status we retrieved really is valid; return it.
+                    // TODO How to ensure no additional output in stdout/stderr when parsing below?
+                    String statusOutStr = new String(statusOut.toByteArray()).trim();
+                    if (Strings.isEmpty(statusOutStr)) {
+                        // suggests not yet completed; will retry with long-poll
+                        if (LOG.isDebugEnabled()) LOG.debug("Long-poll retrieved status directly; command successful but no result available on "+SshjTool.this.toString()+" (for "+getSummary()+")");
+                        return null;
+                    } else {
+                        if (LOG.isDebugEnabled()) LOG.debug("Long-poll retrieved status directly; returning '"+statusOutStr+"' on "+SshjTool.this.toString()+" (for "+getSummary()+")");
+                        int result = Integer.parseInt(statusOutStr);
+                        return result;
+                    }
+
+                } else if (statusResult == -1) {
+                    // probably a connection failure; try again with long-poll
+                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll retrieving status directly received exit status -1; will retry on "+SshjTool.this.toString()+" (for "+getSummary()+")");
+                    return null;
+                    
+                } else {
+                    if (out != null) {
+                        out.write(toUTF8ByteArray("retrieving status failed with exit code "+statusResult+" (stdout follow)"));
+                        out.write(statusOut.toByteArray());
+                    }
+                    if (err != null) {
+                        err.write(toUTF8ByteArray("retrieving status failed with exit code "+statusResult+" (stderr follow)"));
+                        err.write(statusErr.toByteArray());
+                    }
+                    
+                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll retrieving status failed; returning "+statusResult+" on "+SshjTool.this.toString()+" (for "+getSummary()+")");
+                    return statusResult;
+                }
+            }
+        }.run();
+    }
+    
+    public int execShellDirect(Map<String,?> props, List<String> commands, Map<String,?> env) {
+        OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
+        OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
+        Duration execTimeout = getOptionalVal(props, PROP_EXEC_TIMEOUT);
+        
+        List<String> cmdSequence = toCommandSequence(commands, env);
+        List<String> allcmds = ImmutableList.<String>builder()
+                .add(getOptionalVal(props, PROP_DIRECT_HEADER))
+                .addAll(cmdSequence)
+                .add("exit $?")
+                .build();
+        
+        if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {}: {}", host, allcmds);
+        
+        Integer result = acquire(new ShellAction(allcmds, out, err, execTimeout));
+        if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} completed: return status {}", host, result);
+        return asInt(result, -1);
+    }
+
+    @Override
+    public int execCommands(Map<String,?> props, List<String> commands, Map<String,?> env) {
+        if (Boolean.FALSE.equals(props.get("blocks"))) {
+            throw new IllegalArgumentException("Cannot exec non-blocking: command="+commands);
+        }
+        
+        // If async is set, then do it as execScript
+        Boolean execAsync = getOptionalVal(props, PROP_EXEC_ASYNC);
+        if (Boolean.TRUE.equals(execAsync) && BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC)) {
+            return execScriptAsyncAndPoll(props, commands, env);
+        }
+
+        OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
+        OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
+        String separator = getOptionalVal(props, PROP_SEPARATOR);
+        Duration execTimeout = getOptionalVal(props, PROP_EXEC_TIMEOUT);
+
+        List<String> allcmds = toCommandSequence(commands, env);
+        String singlecmd = Joiner.on(separator).join(allcmds);
+
+        if (Boolean.TRUE.equals(getOptionalVal(props, PROP_RUN_AS_ROOT))) {
+            LOG.warn("Cannot run as root when executing as command; run as a script instead (will run as normal user): "+singlecmd);
+        }
+        
+        if (LOG.isTraceEnabled()) LOG.trace("Running command at {}: {}", host, singlecmd);
+        
+        Command result = acquire(new ExecAction(singlecmd, out, err, execTimeout));
+        if (LOG.isTraceEnabled()) LOG.trace("Running command at {} completed: exit code {}", host, result.getExitStatus());
+        // can be null if no exit status is received (observed on kill `ps aux | grep thing-to-grep-for | awk {print $2}`
+        if (result.getExitStatus()==null) LOG.warn("Null exit status running at {}: {}", host, singlecmd);
+        
+        return asInt(result.getExitStatus(), -1);
+    }
+
+    protected void checkConnected() {
+        if (!isConnected()) {
+            throw new IllegalStateException(String.format("(%s) ssh not connected!", toString()));
+        }
+    }
+
+    protected void backoffForAttempt(int retryAttempt, String message) {
+        backoffLimitedRetryHandler.imposeBackoffExponentialDelay(retryAttempt, message);
+    }
+
+    protected <T, C extends SshAction<T>> T acquire(C action) {
+        return acquire(action, sshTries, sshTriesTimeout == 0 ? Duration.PRACTICALLY_FOREVER : Duration.millis(sshTriesTimeout));
+    }
+    
+    protected <T, C extends SshAction<T>> T acquire(C action, int sshTries, Duration sshTriesTimeout) {
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        
+        for (int i = 0; i < sshTries; i++) {
+            try {
+                action.clear();
+                if (LOG.isTraceEnabled()) LOG.trace(">> ({}) acquiring {}", toString(), action);
+                Stopwatch perfStopwatch = Stopwatch.createStarted();
+                
+                T returnVal;
+                try {
+                    returnVal = action.create();
+                } catch (AssertionError e) {
+                    /*
+                     * TODO In net.schmizz.sshj.SSHClient.auth(SSHClient.java:204) throws AssertionError
+                     * if not connected. This can happen if another thread has called disconnect
+                     * concurrently. This is changed in sshj v0.9.0 to instead throw an IllegalStateException.
+                     * 
+                     * For now, we'll retry. See "TODO" at top of class about synchronization.
+                     */
+                    throw new IllegalStateException("Problem in "+toString()+" for "+action, e);
+                }
+                
+                if (LOG.isTraceEnabled()) LOG.trace("<< ({}) acquired {}", toString(), returnVal);
+                if (LOG.isTraceEnabled()) LOG.trace("SSH Performance: {} {} took {}", new Object[] {
+                        sshClientConnection.getHostAndPort(), 
+                        action.getClass().getSimpleName() != null ? action.getClass().getSimpleName() : action, 
+                        Time.makeTimeStringRounded(perfStopwatch)});
+                return returnVal;
+            } catch (Exception e) {
+                // uninformative net.schmizz.sshj.connection.ConnectionException: 
+                //    Request failed (reason=UNKNOWN) may mean remote Subsytem is disabled (e.g. for FTP)
+                // if key is missing, get a UserAuth error
+                String errorMessage = String.format("(%s) error acquiring %s", toString(), action);
+                String fullMessage = String.format("%s (attempt %s/%s, in time %s/%s)", 
+                        errorMessage, (i+1), sshTries, Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS)), 
+                        (sshTriesTimeout.equals(Duration.PRACTICALLY_FOREVER) ? "unlimited" : Time.makeTimeStringRounded(sshTriesTimeout)));
+                try {
+                    disconnect();
+                } catch (Exception e2) {
+                    LOG.debug("<< ("+toString()+") error closing connection: "+e+" / "+e2, e);
+                }
+                if (i + 1 == sshTries) {
+                    LOG.debug("<< {} (rethrowing, out of retries): {}", fullMessage, e.getMessage());
+                    throw propagate(e, fullMessage + "; out of retries");
+                } else if (sshTriesTimeout.isShorterThan(stopwatch)) {
+                    LOG.debug("<< {} (rethrowing, out of time - max {}): {}", new Object[] { fullMessage, Time.makeTimeStringRounded(sshTriesTimeout), e.getMessage() });
+                    throw new RuntimeTimeoutException(fullMessage + "; out of time", e);
+                } else {
+                    if (LOG.isDebugEnabled()) LOG.debug("<< {}: {}", fullMessage, e.getMessage());
+                    backoffForAttempt(i + 1, errorMessage + ": " + e.getMessage());
+                    if (action != sshClientConnection)
+                        connect();
+                    continue;
+                }
+            }
+        }
+        assert false : "should not reach here";
+        return null;
+    }
+
+    private final SshAction<SFTPClient> sftpConnection = new SshAction<SFTPClient>() {
+
+        private SFTPClient sftp;
+
+        @Override
+        public void clear() {
+            closeWhispering(sftp, this);
+            sftp = null;
+        }
+
+        @Override
+        public SFTPClient create() throws IOException {
+            checkConnected();
+            sftp = sshClientConnection.ssh.newSFTPClient();
+            return sftp;
+        }
+
+        @Override
+        public String toString() {
+            return "SFTPClient()";
+        }
+    };
+
+    private class GetFileAction implements SshAction<InputStream> {
+        private final String path;
+        private SFTPClient sftp;
+
+        GetFileAction(String path) {
+            this.path = checkNotNull(path, "path");
+        }
+
+        @Override
+        public void clear() throws IOException {
+            closeWhispering(sftp, this);
+            sftp = null;
+        }
+
+        @Override
+        public InputStream create() throws Exception {
+            sftp = acquire(sftpConnection);
+            return new CloseFtpChannelOnCloseInputStream(
+                    sftp.getSFTPEngine().open(path).getInputStream(), sftp);
+        }
+
+        @Override
+        public String toString() {
+            return "Payload(path=[" + path + "])";
+        }
+    }
+
+    private class PutFileAction implements SshAction<Void> {
+        // TODO support backup as a property?
+        
+        private SFTPClient sftp;
+        private final String path;
+        private final int permissionsMask;
+        private final long lastModificationDate;
+        private final long lastAccessDate;
+        private final int uid;
+        private final Supplier<InputStream> contentsSupplier;
+        private final Integer length;
+        
+        PutFileAction(Map<String,?> props, String path, Supplier<InputStream> contentsSupplier, long length) {
+            String permissions = getOptionalVal(props, PROP_PERMISSIONS);
+            long lastModificationDateVal = getOptionalVal(props, PROP_LAST_MODIFICATION_DATE);
+            long lastAccessDateVal = getOptionalVal(props, PROP_LAST_ACCESS_DATE);
+            if (lastAccessDateVal <= 0 ^ lastModificationDateVal <= 0) {
+                lastAccessDateVal = Math.max(lastAccessDateVal, lastModificationDateVal);
+                lastModificationDateVal = Math.max(lastAccessDateVal, lastModificationDateVal);
+            }
+            this.permissionsMask = Integer.parseInt(permissions, 8);
+            this.lastAccessDate = lastAccessDateVal;
+            this.lastModificationDate = lastModificationDateVal;
+            this.uid = getOptionalVal(props, PROP_OWNER_UID);
+            this.path = checkNotNull(path, "path");
+            this.contentsSupplier = checkNotNull(contentsSupplier, "contents");
+            this.length = Ints.checkedCast(checkNotNull((long)length, "size"));
+        }
+
+        @Override
+        public void clear() {
+            closeWhispering(sftp, this);
+            sftp = null;
+        }
+
+        @Override
+        public Void create() throws Exception {
+            final AtomicReference<InputStream> inputStreamRef = new AtomicReference<InputStream>();
+            sftp = acquire(sftpConnection);
+            try {
+                sftp.put(new InMemorySourceFile() {
+                    @Override public String getName() {
+                        return path;
+                    }
+                    @Override public long getLength() {
+                        return length;
+                    }
+                    @Override public InputStream getInputStream() throws IOException {
+                        InputStream contents = contentsSupplier.get();
+                        inputStreamRef.set(contents);
+                        return contents;
+                    }
+                }, path);
+                sftp.chmod(path, permissionsMask);
+                if (uid != -1) {
+                    sftp.chown(path, uid);
+                }
+                if (lastAccessDate > 0) {
+                    sftp.setattr(path, new FileAttributes.Builder()
+                            .withAtimeMtime(lastAccessDate, lastModificationDate)
+                            .build());
+                }
+            } finally {
+                closeWhispering(inputStreamRef.get(), this);
+            }
+            return null;
+        }
+
+        @Override
+        public String toString() {
+            return "Put(path=[" + path + " "+length+"])";
+        }
+    }
+
+    // TODO simpler not to use predicates
+    @VisibleForTesting
+    Predicate<String> causalChainHasMessageContaining(final Exception from) {
+        return new Predicate<String>() {
+            @Override
+            public boolean apply(final String input) {
+                return any(getCausalChain(from), new Predicate<Throwable>() {
+                    @Override
+                    public boolean apply(Throwable throwable) {
+                        return (throwable.toString().contains(input))
+                                || (throwable.getMessage() != null && throwable.getMessage().contains(input));
+                    }
+                });
+            }
+        };
+    }
+    
+    protected SshAction<Session> newSessionAction() {
+
+        return new SshAction<Session>() {
+
+            private Session session = null;
+
+            @Override
+            public void clear() throws TransportException, ConnectionException {
+                closeWhispering(session, this);
+                session = null;
+            }
+
+            @Override
+            public Session create() throws Exception {
+                checkConnected();
+                session = sshClientConnection.ssh.startSession();
+                if (allocatePTY) {
+                    session.allocatePTY(TERM, 80, 24, 0, 0, Collections.<PTYMode, Integer> emptyMap());
+                }
+                return session;
+            }
+
+            @Override
+            public String toString() {
+                return "Session()";
+            }
+        };
+
+    }
+
+    class ExecAction implements SshAction<Command> {
+        private final String command;
+        private final OutputStream out;
+        private final OutputStream err;
+        private final Duration timeout;
+        
+        private Session session;
+        private Shell shell;
+        private StreamGobbler outgobbler;
+        private StreamGobbler errgobbler;
+        
+        ExecAction(String command, OutputStream out, OutputStream err, Duration timeout) {
+            this.command = checkNotNull(command, "command");
+            this.out = out;
+            this.err = err;
+            Duration sessionTimeout = (sshClientConnection.getSessionTimeout() == 0) 
+                    ? Duration.PRACTICALLY_FOREVER 
+                    : Duration.millis(sshClientConnection.getSessionTimeout());
+            this.timeout = (timeout == null) ? sessionTimeout : Duration.min(timeout, sessionTimeout);
+        }
+
+        @Override
+        public void clear() throws TransportException, ConnectionException {
+            closeWhispering(session, this);
+            closeWhispering(shell, this);
+            closeWhispering(outgobbler, this);
+            closeWhispering(errgobbler, this);
+            session = null;
+            shell = null;
+        }
+
+        @Override
+        public Command create() throws Exception {
+            try {
+                session = acquire(newSessionAction());
+                
+                Command output = session.exec(checkNotNull(command, "command"));
+                
+                if (out != null) {
+                    outgobbler = new StreamGobbler(output.getInputStream(), out, (Logger)null);
+                    outgobbler.start();
+                }
+                if (err != null) {
+                    errgobbler = new StreamGobbler(output.getErrorStream(), err, (Logger)null);
+                    errgobbler.start();
+                }
+                try {
+                    output.join((int)Math.min(timeout.toMilliseconds(), Integer.MAX_VALUE), TimeUnit.MILLISECONDS);
+                    return output;
+                    
+                } finally {
+                    // wait for all stdout/stderr to have been re-directed
+                    try {
+                        // Don't use forever (i.e. 0) because BROOKLYN-106: ssh hangs
+                        long joinTimeout = 10*1000;
+                        if (outgobbler != null) outgobbler.join(joinTimeout);
+                        if (errgobbler != null) errgobbler.join(joinTimeout);
+                    } catch (InterruptedException e) {
+                        LOG.warn("Interrupted gobbling streams from ssh: "+command, e);
+                        Thread.currentThread().interrupt();
+                    }
+                }
+                
+            } finally {
+                clear();
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "Exec(command=[" + command + "])";
+        }
+    }
+
+    class ShellAction implements SshAction<Integer> {
+        @VisibleForTesting
+        final List<String> commands;
+        @VisibleForTesting
+        final OutputStream out;
+        @VisibleForTesting
+        final OutputStream err;
+        
+        private Session session;
+        private Shell shell;
+        private StreamGobbler outgobbler;
+        private StreamGobbler errgobbler;
+        private Duration timeout;
+
+        ShellAction(List<String> commands, OutputStream out, OutputStream err, Duration timeout) {
+            this.commands = checkNotNull(commands, "commands");
+            this.out = out;
+            this.err = err;
+            Duration sessionTimeout = (sshClientConnection.getSessionTimeout() == 0) 
+                    ? Duration.PRACTICALLY_FOREVER 
+                    : Duration.millis(sshClientConnection.getSessionTimeout());
+            this.timeout = (timeout == null) ? sessionTimeout : Duration.min(timeout, sessionTimeout);
+        }
+
+        @Override
+        public void clear() throws TransportException, ConnectionException {
+            closeWhispering(session, this);
+            closeWhispering(shell, this);
+            closeWhispering(outgobbler, this);
+            closeWhispering(errgobbler, this);
+            session = null;
+            shell = null;
+        }
+
+        @Override
+        public Integer create() throws Exception {
+            try {
+                session = acquire(newSessionAction());
+                
+                shell = session.startShell();
+                
+                if (out != null) {
+                    InputStream outstream = shell.getInputStream();
+                    outgobbler = new StreamGobbler(outstream, out, (Logger)null);
+                    outgobbler.start();
+                }
+                if (err != null) {
+                    InputStream errstream = shell.getErrorStream();
+                    errgobbler = new StreamGobbler(errstream, err, (Logger)null);
+                    errgobbler.start();
+                }
+                
+                OutputStream output = shell.getOutputStream();
+
+                for (CharSequence cmd : commands) {
+                    try {
+                        output.write(toUTF8ByteArray(cmd+"\n"));
+                        output.flush();
+                    } catch (ConnectionException e) {
+                        if (!shell.isOpen()) {
+                            // shell is closed; presumably the user command did `exit`
+                            if (LOG.isDebugEnabled()) LOG.debug("Shell closed to {} when executing {}", SshjTool.this.toString(), commands);
+                            break;
+                        } else {
+                            throw e;
+                        }
+                    }
+                }
+                // workaround attempt for SSHJ deadlock - https://github.com/shikhar/sshj/issues/105
+                synchronized (shell.getOutputStream()) {
+                    shell.sendEOF();
+                }
+                closeWhispering(output, this);
+                
+                boolean timedOut = false;
+                try {
+                    long timeoutMillis = Math.min(timeout.toMilliseconds(), Integer.MAX_VALUE);
+                    long timeoutEnd = System.currentTimeMillis() + timeoutMillis;
+                    Exception last = null;
+                    do {
+                        if (!shell.isOpen() && ((SessionChannel)session).getExitStatus()!=null)
+                            // shell closed, and exit status returned
+                            break;
+                        boolean endBecauseReturned =
+                            // if either condition is satisfied, then wait 1s in hopes the other does, then return
+                            (!shell.isOpen() || ((SessionChannel)session).getExitStatus()!=null);
+                        try {
+                            shell.join(1000, TimeUnit.MILLISECONDS);
+                        } catch (ConnectionException e) {
+                            last = e;
+                        }
+                        if (endBecauseReturned) {
+                            // shell is still open, ie some process is running
+                            // but we have a result code, so main shell is finished
+                            // we waited one second extra to allow any background process 
+                            // which is nohupped to really be in the background (#162)
+                            // now let's bail out
+                            break;
+                        }
+                    } while (System.currentTimeMillis() < timeoutEnd);
+                    if (shell.isOpen() && ((SessionChannel)session).getExitStatus()==null) {
+                        LOG.debug("Timeout ({}) in SSH shell to {}", timeout, this);
+                        // we timed out, or other problem -- reproduce the error.
+                        // The shell.join should always have thrown ConnectionExceptoin (looking at code of
+                        // AbstractChannel), but javadoc of Channel doesn't explicity say that so play it safe.
+                        timedOut = true;
+                        throw (last != null) ? last : new TimeoutException("Timeout after "+timeout+" executing "+this);
+                    }
+                    return ((SessionChannel)session).getExitStatus();
+                } finally {
+                    // wait for all stdout/stderr to have been re-directed
+                    closeWhispering(shell, this);
+                    shell = null;
+                    try {
+                        // Don't use forever (i.e. 0) because BROOKLYN-106: ssh hangs
+                        long joinTimeout = (timedOut) ? 1000 : 10*1000;
+                        if (outgobbler != null) {
+                            outgobbler.join(joinTimeout);
+                            outgobbler.close();
+                        }
+                        if (errgobbler != null) {
+                            errgobbler.join(joinTimeout);
+                            errgobbler.close();
+                        }
+                    } catch (InterruptedException e) {
+                        LOG.warn("Interrupted gobbling streams from ssh: "+commands, e);
+                        Thread.currentThread().interrupt();
+                    }
+                }
+                
+            } finally {
+                clear();
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "Shell(command=[" + commands + "])";
+        }
+    }
+
+    private byte[] toUTF8ByteArray(String string) {
+        return org.bouncycastle.util.Strings.toUTF8ByteArray(string);
+    }
+    
+    private Supplier<InputStream> newInputStreamSupplier(final byte[] contents) {
+        return new Supplier<InputStream>() {
+            @Override public InputStream get() {
+                return new ByteArrayInputStream(contents);
+            }
+        };
+    }
+
+    private Supplier<InputStream> newInputStreamSupplier(final File file) {
+        return new Supplier<InputStream>() {
+            @Override public InputStream get() {
+                try {
+                    return new FileInputStream(file);
+                } catch (FileNotFoundException e) {
+                    throw Exceptions.propagate(e);
+                }
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/javalang/ReflectionScanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/javalang/ReflectionScanner.java b/core/src/main/java/org/apache/brooklyn/core/util/javalang/ReflectionScanner.java
new file mode 100644
index 0000000..e0b824a
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/javalang/ReflectionScanner.java
@@ -0,0 +1,135 @@
+/*
+ * 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.util.javalang;
+
+import java.lang.annotation.Annotation;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.reflections.ReflectionUtils;
+import org.reflections.Reflections;
+import org.reflections.Store;
+import org.reflections.scanners.Scanner;
+import org.reflections.scanners.SubTypesScanner;
+import org.reflections.scanners.TypeAnnotationsScanner;
+import org.reflections.util.ClasspathHelper;
+import org.reflections.util.ConfigurationBuilder;
+import org.reflections.util.FilterBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+/** Facade on {@link Reflections} which logs warnings for unloadable classes but does not fail */
+public class ReflectionScanner {
+
+    private static final Logger log = LoggerFactory.getLogger(ReflectionScanner.class);
+    
+    protected final ClassLoader[] classLoaders;
+    protected final Reflections reflections;
+
+    /** scanner which will look in the given urls 
+     * (or if those are null attempt to infer from the first entry in the classloaders,
+     * although currently that seems to only pick up directories, not JAR's),
+     * optionally filtering for the given prefix;
+     * any or all arguments can be null to accept all (and use default classpath for classloading).
+     **/
+    public ReflectionScanner(
+            final Iterable<URL> urlsToScan, 
+            final String optionalPrefix,
+            final ClassLoader ...classLoaders) {
+        reflections = new Reflections(new ConfigurationBuilder() {
+            {
+                final Predicate<String> filter = 
+                        Strings.isNonEmpty(optionalPrefix) ? new FilterBuilder.Include(FilterBuilder.prefix(optionalPrefix)) : null;
+
+                if (urlsToScan!=null)
+                    setUrls(ImmutableSet.copyOf(urlsToScan));
+                else if (classLoaders.length>0 && classLoaders[0]!=null)
+                    setUrls(
+                            ClasspathHelper.forPackage(Strings.isNonEmpty(optionalPrefix) ? optionalPrefix : "",
+                                    asClassLoaderVarArgs(classLoaders[0])));
+                
+                if (filter!=null) filterInputsBy(filter);
+
+                Scanner typeScanner = new TypeAnnotationsScanner();
+                if (filter!=null) typeScanner = typeScanner.filterResultsBy(filter);
+                Scanner subTypeScanner = new SubTypesScanner();
+                if (filter!=null) subTypeScanner = subTypeScanner.filterResultsBy(filter);
+                setScanners(typeScanner, subTypeScanner);
+                
+                for (ClassLoader cl: classLoaders)
+                    if (cl!=null) addClassLoader(cl);
+            }
+        });
+        this.classLoaders = Iterables.toArray(Iterables.filter(Arrays.asList(classLoaders), Predicates.notNull()), ClassLoader.class);
+    }
+
+    private static ClassLoader[] asClassLoaderVarArgs(final ClassLoader classLoaderToSearch) {
+        return classLoaderToSearch==null ? new ClassLoader[0] : new ClassLoader[] { classLoaderToSearch };
+    }
+
+    public Store getStore() {
+        return reflections.getStore();
+    }
+    
+    /** overrides delegate so as to log rather than throw exception if a class cannot be loaded */
+    public <T> Set<Class<? extends T>> getSubTypesOf(final Class<T> type) {
+        Set<String> subTypes = getStore().getSubTypesOf(type.getName());
+        return ImmutableSet.copyOf(this.<T>forNames(subTypes, "sub-type of "+type));
+    }
+    
+    /** overrides delegate so as to log rather than throw exception if a class cannot be loaded */
+    public Set<Class<?>> getTypesAnnotatedWith(Class<? extends Annotation> annotation) {
+        Set<String> annotatedWith = getStore().getTypesAnnotatedWith(annotation.getName());
+        return ImmutableSet.copyOf(this.forNames(annotatedWith, "annotated "+annotation.getName()));
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> List<Class<? extends T>> forNames(Set<String> classNames, final String context) {
+        List<Class<? extends T>> result = new ArrayList<Class<? extends T>>();
+        for (String className : classNames) {
+            //noinspection unchecked
+            try {
+                Class<? extends T> clazz = (Class<? extends T>) loadClass(className);
+                if (clazz != null) {
+                    result.add(clazz);
+                } else {
+                    log.warn("Unable to instantiate '"+className+"' ("+context+")");
+                }
+            } catch (Throwable e) {
+                log.warn("Unable to instantiate '"+className+"' ("+context+"): "+e);
+            }
+        }
+        return result;
+    }
+    
+    protected Class<?> loadClass(String className) {
+        return ReflectionUtils.forName(className, classLoaders);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/javalang/UrlClassLoader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/javalang/UrlClassLoader.java b/core/src/main/java/org/apache/brooklyn/core/util/javalang/UrlClassLoader.java
new file mode 100644
index 0000000..afd0c8e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/javalang/UrlClassLoader.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.util.javalang;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+
+import org.apache.brooklyn.core.util.ResourceUtils;
+
+import brooklyn.util.exceptions.Exceptions;
+
+/** like URLClassLoader (and delegates to it) but:
+ * * has a nice toString
+ * * supports var args constructor
+ * * supports file://~/xxx semantics (remaps it to user.home); 
+ *      ideally we'd also support mvn, classpath, osgi, etc
+ */
+public class UrlClassLoader extends URLClassLoader {
+
+    private URL[] urls;
+
+    public UrlClassLoader(URL ...urls) {
+        super(tidy(urls));
+        this.urls = urls;
+    }
+
+    public UrlClassLoader(String ...urls) {
+        this(asUrls(urls));
+    }
+    
+    private static URL[] asUrls(String[] urls) {
+        URL[] urlo = new URL[urls.length];
+        try {
+        for (int i=0; i<urls.length; i++)
+            urlo[i] = new URL(urls[i]);
+        } catch (MalformedURLException e) {
+            throw Exceptions.propagate(e);
+        }
+        return urlo;
+    }
+
+    private static URL[] tidy(URL[] urls) {
+        for (int i=0; i<urls.length; i++)
+            urls[i] = ResourceUtils.tidy(urls[i]);
+        return urls;
+    }
+
+    @Override
+    public String toString() {
+        return "UrlClassLoader"+Arrays.asList(urls);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/mutex/MutexSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/mutex/MutexSupport.java b/core/src/main/java/org/apache/brooklyn/core/util/mutex/MutexSupport.java
new file mode 100644
index 0000000..2a90f95
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/mutex/MutexSupport.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.util.mutex;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+public class MutexSupport implements WithMutexes {
+
+    private static final Logger log = LoggerFactory.getLogger(MutexSupport.class);
+    private final Map<String,SemaphoreWithOwners> semaphores = new LinkedHashMap<String,SemaphoreWithOwners>();
+
+    protected synchronized SemaphoreWithOwners getSemaphore(String mutexId) {
+        return getSemaphore(mutexId, false);
+    }
+    // NB: the map could be "lock-striped" (hashed on mutexId) to avoid the central lock 
+    protected synchronized SemaphoreWithOwners getSemaphore(String mutexId, boolean requestBeforeReturning) {
+        SemaphoreWithOwners s = semaphores.get(mutexId);
+        if (s==null) {
+            s = new SemaphoreWithOwners(mutexId);
+            semaphores.put(mutexId, s);
+        }
+        if (requestBeforeReturning) s.indicateCallingThreadWillRequest();
+        return s;
+    }
+    /** forces deletion of the given mutex if it is unused; 
+     * normally not required as is done automatically on close
+     * (but possibly needed where there are cancelations and risk of memory leaks) */
+    public synchronized void cleanupMutex(String mutexId) {
+        SemaphoreWithOwners s = semaphores.get(mutexId);
+        if (!s.isInUse()) semaphores.remove(mutexId);
+    }
+    public synchronized void cleanup() {
+        Iterator<SemaphoreWithOwners> si = semaphores.values().iterator();
+        while (si.hasNext()) {
+            SemaphoreWithOwners s = si.next();
+            if (!s.isInUse()) si.remove();
+        }
+    }
+
+    @Override
+    public synchronized boolean hasMutex(String mutexId) {
+        SemaphoreWithOwners s = semaphores.get(mutexId);
+        if (s!=null) return s.isCallingThreadAnOwner();
+        return false;
+    }
+    
+    @Override
+    public void acquireMutex(String mutexId, String description) throws InterruptedException {
+        SemaphoreWithOwners s = getSemaphore(mutexId, true);
+        if (description!=null) Tasks.setBlockingDetails(description+" - waiting for "+mutexId);
+        if (log.isDebugEnabled())
+            log.debug("Acquiring mutex: "+mutexId+"@"+this+" - "+description);
+        s.acquire(); 
+        if (description!=null) Tasks.setBlockingDetails(null);
+        s.setDescription(description);
+        if (log.isDebugEnabled())
+            log.debug("Acquired mutex: "+mutexId+"@"+this+" - "+description);
+    }
+
+    @Override
+    public boolean tryAcquireMutex(String mutexId, String description) {
+        SemaphoreWithOwners s = getSemaphore(mutexId, true);
+        if (s.tryAcquire()) {
+            if (log.isDebugEnabled())
+                log.debug("Acquired mutex (opportunistic): "+mutexId+"@"+this+" - "+description);
+            s.setDescription(description);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized void releaseMutex(String mutexId) {
+        SemaphoreWithOwners s;
+        if (log.isDebugEnabled())
+            log.debug("Releasing mutex: "+mutexId+"@"+this);
+        synchronized (this) { s = semaphores.get(mutexId); }
+        if (s==null) throw new IllegalStateException("No mutex known for '"+mutexId+"'");
+        s.release();
+        cleanupMutex(mutexId);
+    }
+    
+    @Override
+    public synchronized String toString() {
+        return super.toString()+"["+semaphores.size()+" semaphores: "+semaphores.values()+"]";
+    }
+    
+    /** Returns the semaphores in use at the time the method is called, for inspection purposes (and testing).
+     * The semaphores used by this class may change over time so callers are strongly discouraged
+     * from manipulating the semaphore objects themselves. 
+     */
+    public synchronized Map<String,SemaphoreWithOwners> getAllSemaphores() {
+        return ImmutableMap.<String,SemaphoreWithOwners>copyOf(semaphores);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/mutex/SemaphoreForTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/mutex/SemaphoreForTasks.java b/core/src/main/java/org/apache/brooklyn/core/util/mutex/SemaphoreForTasks.java
new file mode 100644
index 0000000..7e805b0
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/mutex/SemaphoreForTasks.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.util.mutex;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.Tasks;
+
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+
+/** A subclass of {@link SemaphoreWithOwners} 
+ * which additionally sets Task blocking information. 
+ * <p>
+ * TODO As tasks are distributed this should support distribution across the management context. */
+public class SemaphoreForTasks extends SemaphoreWithOwners {
+    
+    private static final long serialVersionUID = 7898283056223005952L;
+    
+    /** unused at present, but wanted on the API for when this may be federated */
+    @SuppressWarnings("unused")
+    private final ManagementContext mgmt;
+    
+    final private MutableList<Task<?>> owningTasks = new MutableList<Task<?>>();
+    final private MutableSet<Task<?>> requestingTasks = new MutableSet<Task<?>>();
+
+    public SemaphoreForTasks(String name, ManagementContext mgmt) {
+        super(name);
+        this.mgmt = Preconditions.checkNotNull(mgmt);
+    }
+    
+    public SemaphoreForTasks(String name, int permits, boolean fair, ManagementContext mgmt) {
+        super(name, permits, fair);
+        this.mgmt = Preconditions.checkNotNull(mgmt);
+    }
+    
+    public synchronized Set<Task<?>> getRequestingTasks() {
+        return ImmutableSet.copyOf(requestingTasks);
+    }
+    
+    public synchronized List<Task<?>> getOwningTasks() {
+        return ImmutableList.copyOf(owningTasks);
+    }
+
+    @Override
+    protected synchronized void onRequesting() {
+        if (!owningTasks.isEmpty() || !requestingTasks.isEmpty()) {
+            Tasks.setBlockingTask( !requestingTasks.isEmpty() ? Iterables.getLast(requestingTasks) : Iterables.getFirst(owningTasks, null) );
+            Tasks.setBlockingDetails("Waiting on semaphore "+getName()+" ("+getDescription()+"); "
+                + "queued at "+Time.makeDateString()+" when "+getRequestingThreads().size()+" ahead in queue");
+        }
+        requestingTasks.addIfNotNull(Tasks.current());
+        super.onRequesting();
+    }
+    
+    @Override
+    protected synchronized void onRequestFinished() {
+        super.onRequestFinished();
+        requestingTasks.removeIfNotNull(Tasks.current());
+        
+        Tasks.resetBlockingDetails();
+        Tasks.resetBlockingTask();
+    }
+    
+    @Override
+    protected synchronized void onAcquired(int permits) {
+        super.onAcquired(permits);
+        for (int i=0; i<permits; i++)
+            owningTasks.appendIfNotNull(Tasks.current());
+    }
+    
+    @Override
+    protected synchronized void onReleased(int permits) {
+        super.onReleased(permits);
+        for (int i=0; i<permits; i++)
+            owningTasks.removeIfNotNull(Tasks.current());
+    }
+    
+    @Override
+    public synchronized String toString() {
+        return super.toString()+"["
+            + "owningTasks="+owningTasks
+            + "; requestingTasks="+requestingTasks+"]";
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/mutex/SemaphoreWithOwners.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/mutex/SemaphoreWithOwners.java b/core/src/main/java/org/apache/brooklyn/core/util/mutex/SemaphoreWithOwners.java
new file mode 100644
index 0000000..0144d4d
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/mutex/SemaphoreWithOwners.java
@@ -0,0 +1,231 @@
+/*
+ * 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.util.mutex;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.collect.ImmutableList;
+
+/** a subclass of {@link Semaphore} 
+ * which tracks who created and released the semaphores,
+ * and which requires the same thread to release as created it. */
+public class SemaphoreWithOwners extends Semaphore {
+    public SemaphoreWithOwners(String name) {
+        this(name, 1, true);
+    }
+    public SemaphoreWithOwners(String name, int permits, boolean fair) {
+        super(permits, fair);
+        this.name = name;
+    }
+    private static final long serialVersionUID = -5303474637353009454L;
+    final private List<Thread> owningThreads = new ArrayList<Thread>();
+    final private Set<Thread> requestingThreads = new LinkedHashSet<Thread>();
+    
+    @Override
+    public void acquire() throws InterruptedException {
+        try {
+            onRequesting();
+            super.acquire();
+            onAcquired(1);
+        } finally {
+            onRequestFinished();
+        }
+    }
+    @Override
+    public void acquire(int permits) throws InterruptedException {
+        try {
+            onRequesting();
+            super.acquire(permits);
+            onAcquired(permits);
+        } finally {
+            onRequestFinished();
+        }
+    }
+    @Override
+    public void acquireUninterruptibly() {
+        try {
+            onRequesting();
+            super.acquireUninterruptibly();
+            onAcquired(1);
+        } finally {
+            onRequestFinished();
+        }
+    }
+    @Override
+    public void acquireUninterruptibly(int permits) {
+        try {
+            onRequesting();
+            super.acquireUninterruptibly(permits);
+            onAcquired(permits);
+        } finally {
+            onRequestFinished();
+        }
+    }
+
+    public void acquireUnchecked() {
+        try {
+            acquire();
+        } catch (InterruptedException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    public void acquireUnchecked(int numPermits) {
+        try {
+            acquire(numPermits);
+        } catch (InterruptedException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    @Override
+    public boolean tryAcquire() {
+        try {
+            onRequesting();
+            if (super.tryAcquire()) {
+                onAcquired(1);
+                return true;
+            }
+            return false;
+        } finally {
+            onRequestFinished();
+        }
+    }
+    @Override
+    public boolean tryAcquire(int permits) {
+        try {
+            onRequesting();
+            if (super.tryAcquire(permits)) {
+                onAcquired(permits);
+                return true;
+            }
+            return false;
+        } finally {
+            onRequestFinished();
+        }
+    }
+    @Override
+    public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException {
+        try {
+            onRequesting();
+            if (super.tryAcquire(permits, timeout, unit)) {
+                onAcquired(permits);
+                return true;
+            }
+            return false;
+        } finally {
+            onRequestFinished();
+        }
+    }
+    @Override
+    public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException {
+        try {
+            onRequesting();
+            if (super.tryAcquire(timeout, unit)) {
+                onAcquired(1);
+                return true;
+            }
+            return false;
+        } finally {
+            onRequestFinished();
+        }
+    }
+
+    /** invoked when a caller successfully acquires a mutex, before {@link #onRequestFinished()} */
+    protected synchronized void onAcquired(int permits) {
+        for (int i=0; i<permits; i++) owningThreads.add(Thread.currentThread());
+    }
+    /** invoked when a caller is about to request a semaphore (before it might block);
+     * guaranteed to call {@link #onRequestFinished()} after the blocking,
+     * with a call to {@link #onAcquired(int)} beforehand if the acquisition was successful */
+    protected synchronized void onRequesting() {
+        requestingThreads.add(Thread.currentThread());
+    }
+    /** invoked when a caller has completed requesting a mutex, whether successful, aborted, or interrupted */
+    protected synchronized void onRequestFinished() {
+        requestingThreads.remove(Thread.currentThread());
+    }
+
+    @Override
+    public void release() {
+        super.release();
+        onReleased(1);
+    }
+    @Override
+    public void release(int permits) {
+        super.release(permits);
+        onReleased(permits);
+    }
+
+    /** invoked when a caller has released permits */
+    protected synchronized void onReleased(int permits) {
+        boolean result = true;
+        for (int i=0; i<permits; i++) result = owningThreads.remove(Thread.currentThread()) & result;
+        if (!result) throw new IllegalStateException("Thread "+Thread.currentThread()+" which released "+this+" did not own it.");  
+    }
+
+    /** true iff there are any owners or any requesters (callers blocked trying to acquire) */
+    public synchronized boolean isInUse() {
+        return !owningThreads.isEmpty() || !requestingThreads.isEmpty();
+    }
+
+    /** true iff the calling thread is one of the owners */ 
+    public synchronized boolean isCallingThreadAnOwner() {
+        return owningThreads.contains(Thread.currentThread());
+    }
+
+    private final String name;
+    /** constructor-time supplied name */
+    public String getName() { return name; }
+
+    private String description;
+    public void setDescription(String description) { this.description = description; }
+    /** caller supplied description */
+    public String getDescription() { return description; }
+
+    /** unmodifiable view of threads owning the permits; threads with multiple permits listed multiply */
+    public synchronized List<Thread> getOwningThreads() {
+        return ImmutableList.<Thread>copyOf(owningThreads);
+    }
+    /** unmodifiable view of threads requesting access (blocked or briefly trying to acquire);
+     * this is guaranteed to be cleared _after_ getOwners 
+     * (synchronizing on this class while reading both fields will give canonical access) */
+    public synchronized List<Thread> getRequestingThreads() {
+        return ImmutableList.<Thread>copyOf(requestingThreads);
+    }
+    
+    @Override
+    public synchronized String toString() {
+        return super.toString()+"["+name+"; description="+description+"; owning="+owningThreads+"; requesting="+requestingThreads+"]";
+    }
+    
+    /** Indicate that the calling thread is going to acquire or tryAcquire, 
+     * in order to set up the semaphore's isInUse() value appropriately for certain checks.
+     * It *must* do so after invoking this method. */ 
+    public void indicateCallingThreadWillRequest() {
+        requestingThreads.add(Thread.currentThread());
+    }
+    
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/mutex/WithMutexes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/mutex/WithMutexes.java b/core/src/main/java/org/apache/brooklyn/core/util/mutex/WithMutexes.java
new file mode 100644
index 0000000..82eab02
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/mutex/WithMutexes.java
@@ -0,0 +1,45 @@
+/*
+ * 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.util.mutex;
+
+/** interface which allows multiple callers to co-operate using named mutexes, inspectably,
+ * and containing implementation as inner class
+ * <p>
+ * MutexSupport is a common implementation of this.
+ * mixin code frequently delegates to this, 
+ * as shown in the test case's WithMutexesTest.SampleWithMutexesDelegatingMixin class 
+ **/
+public interface WithMutexes {
+
+    /** returns true if the calling thread has the mutex with the given ID */
+    public boolean hasMutex(String mutexId);
+    
+    /** acquires a mutex, if available, otherwise blocks on its becoming available;
+     * caller must release after use */
+    public void acquireMutex(String mutexId, String description) throws InterruptedException;
+
+    /** acquires a mutex and returns true, if available; otherwise immediately returns false;
+     * caller must release after use if this returns true */
+    public boolean tryAcquireMutex(String mutexId, String description);
+
+    /** releases a mutex, triggering another thread to use it or cleaning it up if no one else is waiting;
+     * this should only be called by the mutex owner (thread) */
+    public void releaseMutex(String mutexId);
+    
+}


[56/64] incubator-brooklyn git commit: brooklyn-software-database: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..d66ed76
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
@@ -0,0 +1,425 @@
+/*
+ * 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.entity.database.postgresql;
+
+import static brooklyn.util.ssh.BashCommands.INSTALL_WGET;
+import static brooklyn.util.ssh.BashCommands.alternativesGroup;
+import static brooklyn.util.ssh.BashCommands.chainGroup;
+import static brooklyn.util.ssh.BashCommands.dontRequireTtyForSudo;
+import static brooklyn.util.ssh.BashCommands.executeCommandThenAsUserTeeOutputToFile;
+import static brooklyn.util.ssh.BashCommands.fail;
+import static brooklyn.util.ssh.BashCommands.ifExecutableElse0;
+import static brooklyn.util.ssh.BashCommands.ifExecutableElse1;
+import static brooklyn.util.ssh.BashCommands.installPackage;
+import static brooklyn.util.ssh.BashCommands.sudo;
+import static brooklyn.util.ssh.BashCommands.sudoAsUser;
+import static brooklyn.util.ssh.BashCommands.warn;
+import static java.lang.String.format;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.SoftwareProcess;
+import org.apache.brooklyn.entity.database.DatastoreMixins;
+import brooklyn.entity.software.SshEffectorTasks;
+
+import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks.OnFailingTask;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.StringFunctions;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Charsets;
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+
+/**
+ * The SSH implementation of the {@link PostgreSqlDriver}.
+ */
+public class PostgreSqlSshDriver extends AbstractSoftwareProcessSshDriver implements PostgreSqlDriver {
+
+    public static final Logger log = LoggerFactory.getLogger(PostgreSqlSshDriver.class);
+
+    public PostgreSqlSshDriver(PostgreSqlNodeImpl entity, SshMachineLocation machine) {
+        super(entity, machine);
+
+        entity.setAttribute(Attributes.LOG_FILE_LOCATION, getLogFile());
+    }
+
+    /*
+     * TODO this is much messier than we would like because postgres runs as user postgres,
+     * meaning the dirs must be RW by that user, and accessible (thus all parent paths),
+     * which may rule out putting it in a location used by the default user.
+     * Two irritating things:
+     * * currently we sometimes make up a different onbox base dir;
+     * * currently we put files to /tmp for staging
+     * Could investigate if it really needs to run as user postgres;
+     * could also see whether default user can be added to group postgres,
+     * and the run dir (and all parents) made accessible to group postgres.
+     */
+    @Override
+    public void install() {
+        String version = getEntity().getConfig(SoftwareProcess.SUGGESTED_VERSION);
+        String majorMinorVersion = version.substring(0, version.lastIndexOf("-"));
+        String shortVersion = majorMinorVersion.replace(".", "");
+
+        String altTarget = "/opt/brooklyn/postgres/";
+        String altInstallDir = Urls.mergePaths(altTarget, "install/"+majorMinorVersion);
+        
+        Iterable<String> pgctlLocations = ImmutableList.of(
+            altInstallDir+"/bin",
+            "/usr/lib/postgresql/"+majorMinorVersion+"/bin/",
+            "/opt/local/lib/postgresql"+shortVersion+"/bin/",
+            "/usr/pgsql-"+majorMinorVersion+"/bin",
+            "/usr/local/bin/",
+            "/usr/bin/",
+            "/bin/");
+
+        DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(getMachine(),
+            // sudo is absolutely required here, in customize we set user to postgres
+            OnFailingTask.FAIL)).orSubmitAndBlock();
+        DynamicTasks.waitForLast();
+
+        // Check whether we can find a usable pg_ctl, and if not install one
+        MutableList<String> findOrInstall = MutableList.<String>of()
+            .append("which pg_ctl")
+            .appendAll(Iterables.transform(pgctlLocations, StringFunctions.formatter("test -x %s/pg_ctl")))
+            .append(installPackage(ImmutableMap.of(
+                "yum", "postgresql"+shortVersion+" postgresql"+shortVersion+"-server",
+                "apt", "postgresql-"+majorMinorVersion,
+                "port", "postgresql"+shortVersion+" postgresql"+shortVersion+"-server"
+                ), null))
+                // due to impl of installPackage, it will not come to the line below I don't think
+                .append(warn(format("WARNING: failed to find or install postgresql %s binaries", majorMinorVersion)));
+
+        // Link to correct binaries folder (different versions of pg_ctl and psql don't always play well together)
+        MutableList<String> linkFromHere = MutableList.<String>of()
+            .append(ifExecutableElse1("pg_ctl", chainGroup(
+                "PG_EXECUTABLE=`which pg_ctl`",
+                "PG_DIR=`dirname $PG_EXECUTABLE`",
+                "echo 'found pg_ctl in '$PG_DIR' on path so linking PG bin/ to that dir'",
+                "ln -s $PG_DIR bin")))
+                .appendAll(Iterables.transform(pgctlLocations, givenDirIfFileExistsInItLinkToDir("pg_ctl", "bin")))
+                .append(fail(format("WARNING: failed to find postgresql %s binaries for pg_ctl, may already have another version installed; aborting", majorMinorVersion), 9));
+
+        newScript(INSTALLING)
+        .body.append(
+            dontRequireTtyForSudo(),
+            ifExecutableElse0("yum", getYumRepository(version, majorMinorVersion, shortVersion)),
+            ifExecutableElse0("apt-get", getAptRepository()),
+            "rm -f bin", // if left over from previous incomplete/failed install (not sure why that keeps happening!)
+            alternativesGroup(findOrInstall),
+            alternativesGroup(linkFromHere))
+            .failOnNonZeroResultCode()
+            .queue();
+        
+        // check that the proposed install dir is one that user postgres can access
+        if (DynamicTasks.queue(SshEffectorTasks.ssh(sudoAsUser("postgres", "ls "+getInstallDir())).allowingNonZeroExitCode()
+                .summary("check postgres user can access install dir")).asTask().getUnchecked()!=0) {
+            log.info("Postgres install dir "+getInstallDir()+" for "+getEntity()+" is not accessible to user 'postgres'; " + "using "+altInstallDir+" instead");
+            String newRunDir = Urls.mergePaths(altTarget, "apps", getEntity().getApplication().getId(), getEntity().getId());
+            if (DynamicTasks.queue(SshEffectorTasks.ssh("ls "+altInstallDir+"/pg_ctl").allowingNonZeroExitCode()
+                    .summary("check whether "+altInstallDir+" is set up")).asTask().getUnchecked()==0) {
+                // alt target already exists with binary; nothing to do for install
+            } else {
+                DynamicTasks.queue(SshEffectorTasks.ssh(
+                    "mkdir -p "+altInstallDir,
+                    "rm -rf '"+altInstallDir+"'",
+                    "mv "+getInstallDir()+" "+altInstallDir,
+                    "rm -rf '"+getInstallDir()+"'",
+                    "ln -s "+altInstallDir+" "+getInstallDir(),
+                    "mkdir -p " + newRunDir,
+                    "chown -R postgres:postgres "+altTarget).runAsRoot().requiringExitCodeZero()
+                    .summary("move install dir from user to postgres owned space"));
+            }
+            DynamicTasks.waitForLast();
+            setInstallDir(altInstallDir);
+            setRunDir(newRunDir);
+        }
+    }
+
+    private String getYumRepository(String version, String majorMinorVersion, String shortVersion) {
+        // postgres becomes available if you add the repos using an RPM such as
+        // http://yum.postgresql.org/9.3/redhat/rhel-6-i386/pgdg-centos93-9.3-1.noarch.rpm
+        // fedora, rhel, sl, and centos supported for RPM's
+
+        OsDetails osDetails = getMachine().getMachineDetails().getOsDetails();
+        String arch = osDetails.getArch();
+        String osMajorVersion = osDetails.getVersion();
+        String osName = osDetails.getName();
+
+        log.debug("postgres detecting yum information for "+getEntity()+" at "+getMachine()+": "+osName+", "+osMajorVersion+", "+arch);
+
+        if (osName==null) osName = ""; else osName = osName.toLowerCase();
+
+        if (osName.equals("ubuntu")) return "echo skipping yum repo setup as this is not an rpm environment";
+
+        if (osName.equals("rhel")) osName = "redhat";
+        else if (osName.equals("centos")) osName = "centos";
+        else if (osName.equals("sl") || osName.startsWith("scientific")) osName = "sl";
+        else if (osName.equals("fedora")) osName = "fedora";
+        else {
+            log.debug("insufficient OS family information '"+osName+"' for "+getMachine()+" when installing "+getEntity()+" (yum repos); treating as centos");
+            osName = "centos";
+        }
+
+        if (Strings.isBlank(arch)) {
+            log.warn("Insuffient architecture information '"+arch+"' for "+getMachine()+"when installing "+getEntity()+"; treating as x86_64");
+            arch = "x86_64";
+        }
+
+        if (Strings.isBlank(osMajorVersion)) {
+            if (osName.equals("fedora")) osMajorVersion = "20";
+            else osMajorVersion = "6";
+            log.warn("Insuffient OS version information '"+getMachine().getOsDetails().getVersion()+"' for "+getMachine()+"when installing "+getEntity()+" (yum repos); treating as "+osMajorVersion);
+        } else {
+            if (osMajorVersion.indexOf(".")>0) 
+                osMajorVersion = osMajorVersion.substring(0, osMajorVersion.indexOf('.'));
+        }
+
+        return chainGroup(
+                INSTALL_WGET,
+                sudo(format("wget http://yum.postgresql.org/%s/redhat/rhel-%s-%s/pgdg-%s%s-%s.noarch.rpm", majorMinorVersion, osMajorVersion, arch, osName, shortVersion, version)),
+                sudo(format("rpm -Uvh pgdg-%s%s-%s.noarch.rpm", osName, shortVersion, version))
+            );
+    }
+
+    private String getAptRepository() {
+        return chainGroup(
+                INSTALL_WGET,
+                "wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo tee -a apt-key add -",
+                "echo \"deb http://apt.postgresql.org/pub/repos/apt/   $(sudo lsb_release --codename --short)-pgdg main\" | sudo tee -a /etc/apt/sources.list.d/postgresql.list"
+            );
+    }
+
+    private static Function<String, String> givenDirIfFileExistsInItLinkToDir(final String filename, final String linkToMake) {
+        return new Function<String, String>() {
+            public String apply(@Nullable String dir) {
+                return ifExecutableElse1(Urls.mergePaths(dir, filename),
+                    chainGroup("echo 'found "+filename+" in "+dir+" so linking to it in "+linkToMake+"'", "ln -s "+dir+" "+linkToMake));
+            }
+        };
+    }
+
+    @Override
+    public void customize() {
+        // Some OSes start postgres during package installation
+        DynamicTasks.queue(SshEffectorTasks.ssh(sudoAsUser("postgres", "/etc/init.d/postgresql stop")).allowingNonZeroExitCode()).get();
+
+        newScript(CUSTOMIZING)
+        .body.append(
+            sudo("mkdir -p " + getDataDir()),
+            sudo("chown postgres:postgres " + getDataDir()),
+            sudo("chmod 700 " + getDataDir()),
+            sudo("touch " + getLogFile()),
+            sudo("chown postgres:postgres " + getLogFile()),
+            sudo("touch " + getPidFile()),
+            sudo("chown postgres:postgres " + getPidFile()),
+            alternativesGroup(
+                chainGroup(format("test -e %s", getInstallDir() + "/bin/initdb"),
+                    sudoAsUser("postgres", getInstallDir() + "/bin/initdb -D " + getDataDir())),
+                    callPgctl("initdb", true)))
+                    .failOnNonZeroResultCode()
+                    .execute();
+
+        String configUrl = getEntity().getConfig(PostgreSqlNode.CONFIGURATION_FILE_URL);
+        if (Strings.isBlank(configUrl)) {
+            // http://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server
+            // If the same setting is listed multiple times, the last one wins.
+            DynamicTasks.queue(SshEffectorTasks.ssh(
+                executeCommandThenAsUserTeeOutputToFile(
+                    chainGroup(
+                        "echo \"listen_addresses = '*'\"",
+                        "echo \"port = " + getEntity().getPostgreSqlPort() +  "\"",
+                        "echo \"max_connections = " + getEntity().getMaxConnections() +  "\"",
+                        "echo \"shared_buffers = " + getEntity().getSharedMemory() +  "\"",
+                        "echo \"external_pid_file = '" + getPidFile() +  "'\""),
+                        "postgres", getDataDir() + "/postgresql.conf")));
+        } else {
+            String contents = processTemplate(configUrl);
+            DynamicTasks.queue(
+                SshEffectorTasks.put("/tmp/postgresql.conf").contents(contents),
+                SshEffectorTasks.ssh(sudoAsUser("postgres", "cp /tmp/postgresql.conf " + getDataDir() + "/postgresql.conf")));
+        }
+
+        String authConfigUrl = getEntity().getConfig(PostgreSqlNode.AUTHENTICATION_CONFIGURATION_FILE_URL);
+        if (Strings.isBlank(authConfigUrl)) {
+            DynamicTasks.queue(SshEffectorTasks.ssh(
+                // TODO give users control which hosts can connect and the authentication mechanism
+                executeCommandThenAsUserTeeOutputToFile("echo \"host all all 0.0.0.0/0 md5\"", "postgres", getDataDir() + "/pg_hba.conf")));
+        } else {
+            String contents = processTemplate(authConfigUrl);
+            DynamicTasks.queue(
+                SshEffectorTasks.put("/tmp/pg_hba.conf").contents(contents),
+                SshEffectorTasks.ssh(sudoAsUser("postgres", "cp /tmp/pg_hba.conf " + getDataDir() + "/pg_hba.conf")));
+        }
+
+        // Wait for commands to complete before running the creation script
+        DynamicTasks.waitForLast();
+
+        // Capture log file contents if there is an error configuring the database
+        try {
+            executeDatabaseCreationScript();
+        } catch (RuntimeException r) {
+            logTailOfPostgresLog();
+            throw Exceptions.propagate(r);
+        }
+
+        // Try establishing an external connection. If you get a "Connection refused...accepting TCP/IP connections
+        // on port 5432?" error then the port is probably closed. Check that the firewall allows external TCP/IP
+        // connections (netstat -nap). You can open a port with lokkit or by configuring the iptables.
+    }
+
+    protected void executeDatabaseCreationScript() {
+        if (copyDatabaseCreationScript()) {
+            newScript("running postgres creation script")
+            .body.append(
+                "cd " + getInstallDir(),
+                callPgctl("start", true),
+                sudoAsUser("postgres", getInstallDir() + "/bin/psql -p " + entity.getAttribute(PostgreSqlNode.POSTGRESQL_PORT) + " --file " + getRunDir() + "/creation-script.sql"),
+                callPgctl("stop", true))
+                .failOnNonZeroResultCode()
+                .execute();
+        }
+    }
+
+    private boolean installFile(InputStream contents, String destName) {
+        String uid = Identifiers.makeRandomId(8);
+        // TODO currently put in /tmp for staging, since run dir may not be accessible to ssh user
+        getMachine().copyTo(contents, "/tmp/"+destName+"_"+uid);
+        DynamicTasks.queueIfPossible(SshEffectorTasks.ssh(
+            "cd "+getRunDir(), 
+            "mv /tmp/"+destName+"_"+uid+" "+destName,
+            "chown postgres:postgres "+destName,
+            "chmod 644 "+destName)
+            .runAsRoot().requiringExitCodeZero())
+            .orSubmitAndBlock(getEntity()).andWaitForSuccess();
+        return true;
+    }
+    private boolean copyDatabaseCreationScript() {
+        InputStream creationScript = DatastoreMixins.getDatabaseCreationScript(entity);
+        if (creationScript==null)
+            return false;
+        return installFile(creationScript, "creation-script.sql");
+    }
+
+    public String getDataDir() {
+        return getRunDir() + "/data";
+    }
+
+    public String getLogFile() {
+        return getRunDir() + "/postgresql.log";
+    }
+
+    public String getPidFile() {
+        return getRunDir() + "/postgresql.pid";
+    }
+
+    /** @deprecated since 0.7.0 renamed {@link #logTailOfPostgresLog()} */
+    @Deprecated
+    public void copyLogFileContents() { logTailOfPostgresLog(); }
+    public void logTailOfPostgresLog() {
+        try {
+            File file = Os.newTempFile("postgresql-"+getEntity().getId(), "log");
+            int result = getMachine().copyFrom(getLogFile(), file.getAbsolutePath());
+            if (result != 0) throw new IllegalStateException("Could not access log file " + getLogFile());
+            log.info("Saving {} contents as {}", getLogFile(), file);
+            Streams.logStreamTail(log, "postgresql.log", Streams.byteArrayOfString(Files.toString(file, Charsets.UTF_8)), 1024);
+            file.delete();
+        } catch (IOException ioe) {
+            log.debug("Error reading copied log file: {}", ioe);
+        }
+    }
+
+    protected String callPgctl(String command, boolean waitForIt) {
+        return sudoAsUser("postgres", getInstallDir() + "/bin/pg_ctl -D " + getDataDir() +
+            " -l " + getLogFile() + (waitForIt ? " -w " : " ") + command);
+    }
+
+    @Override
+    public void launch() {
+        log.info(String.format("Starting entity %s at %s", this, getLocation()));
+        newScript(MutableMap.of("usePidFile", false), LAUNCHING)
+        .body.append(callPgctl("start", false))
+        .execute();
+    }
+
+    @Override
+    public boolean isRunning() {
+        return newScript(MutableMap.of("usePidFile", getPidFile()), CHECK_RUNNING)
+            .body.append(getStatusCmd())
+            .execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(MutableMap.of("usePidFile", false), STOPPING)
+        .body.append(callPgctl((entity.getConfig(PostgreSqlNode.DISCONNECT_ON_STOP) ? "-m immediate " : "") + "stop", false))
+        .failOnNonZeroResultCode()
+        .execute();
+        newScript(MutableMap.of("usePidFile", getPidFile(), "processOwner", "postgres"), STOPPING).execute();
+    }
+
+    @Override
+    public PostgreSqlNodeImpl getEntity() {
+        return (PostgreSqlNodeImpl) super.getEntity();
+    }
+
+    @Override
+    public String getStatusCmd() {
+        return callPgctl("status", false);
+    }
+
+    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands) {
+        String filename = "postgresql-commands-"+Identifiers.makeRandomId(8);
+        installFile(Streams.newInputStreamWithContents(commands), filename);
+        return executeScriptFromInstalledFileAsync(filename);
+    }
+
+    public ProcessTaskWrapper<Integer> executeScriptFromInstalledFileAsync(String filenameAlreadyInstalledAtServer) {
+        return DynamicTasks.queue(
+            SshEffectorTasks.ssh(
+                "cd "+getRunDir(),
+                sudoAsUser("postgres", getInstallDir() + "/bin/psql -p " + entity.getAttribute(PostgreSqlNode.POSTGRESQL_PORT) + " --file " + filenameAlreadyInstalledAtServer))
+                .summary("executing datastore script "+filenameAlreadyInstalledAtServer));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepDriver.java
new file mode 100644
index 0000000..056dd3d
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepDriver.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.entity.database.rubyrep;
+
+import brooklyn.entity.basic.SoftwareProcessDriver;
+
+/**
+ * The driver interface for {@link RubyRepNode}.
+ */
+public interface RubyRepDriver extends SoftwareProcessDriver {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..207d233
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNode.java
@@ -0,0 +1,109 @@
+/*
+ * 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.entity.database.rubyrep;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import org.apache.brooklyn.entity.database.DatastoreMixins;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+
+@Catalog(name = "RubyRep Node", description = "RubyRep is a database replication system", iconUrl = "classpath:///rubyrep-logo.jpeg")
+@ImplementedBy(RubyRepNodeImpl.class)
+public interface RubyRepNode extends SoftwareProcess {
+
+    @SetFromFlag("version")
+    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "1.2.0");
+
+    @SetFromFlag("downloadUrl")
+    public static final BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new StringAttributeSensorAndConfigKey(
+            Attributes.DOWNLOAD_URL, "http://files.rubyforge.vm.bytemark.co.uk/rubyrep/rubyrep-${version}.zip");
+
+    @SetFromFlag("configurationScriptUrl")
+    ConfigKey<String> CONFIGURATION_SCRIPT_URL = ConfigKeys.newStringConfigKey(
+            "database.rubyrep.configScriptUrl",
+            "URL where RubyRep configuration can be found - disables other configuration options (except version)");
+
+    @SetFromFlag("templateUrl")
+    ConfigKey<String> TEMPLATE_CONFIGURATION_URL = ConfigKeys.newStringConfigKey(
+            "database.rubyrep.templateConfigurationUrl", "Template file (in freemarker format) for the rubyrep.conf file",
+            "classpath://org/apache/brooklyn/entity/database/rubyrep/rubyrep.conf");
+
+    @SetFromFlag("tables")
+    ConfigKey<String> TABLE_REGEXP = ConfigKeys.newStringConfigKey(
+            "database.rubyrep.tableRegex", "Regular expression to select tables to sync using RubyRep", ".");
+
+    @SetFromFlag("replicationInterval")
+    ConfigKey<Integer> REPLICATION_INTERVAL = ConfigKeys.newIntegerConfigKey(
+            "database.rubyrep.replicationInterval", "Replication Interval", 30);
+
+    @SetFromFlag("startupTimeout")
+    ConfigKey<Integer> DATABASE_STARTUP_TIMEOUT = ConfigKeys.newIntegerConfigKey(
+            "database.rubyrep.startupTimeout", "Time to wait until databases have started up (in seconds)", 120);
+
+    // Left database
+
+    AttributeSensor<String> LEFT_DATASTORE_URL = Sensors.newSensorWithPrefix("left", DatastoreMixins.DATASTORE_URL);
+
+    @SetFromFlag("leftDatabase")
+    ConfigKey<? extends DatastoreCommon> LEFT_DATABASE = ConfigKeys.newConfigKey(DatastoreCommon.class,
+            "database.rubyrep.leftDatabase", "Brooklyn database entity to use as the left DBMS");
+
+    @SetFromFlag("leftDatabaseName")
+    ConfigKey<String> LEFT_DATABASE_NAME = ConfigKeys.newStringConfigKey(
+            "database.rubyrep.leftDatabaseName", "name of database to use for left db");
+
+    @SetFromFlag("leftUsername")
+    ConfigKey<String> LEFT_USERNAME = ConfigKeys.newStringConfigKey(
+            "database.rubyrep.leftUsername", "username to connect to left db");
+
+    @SetFromFlag("leftPassword")
+    ConfigKey<String> LEFT_PASSWORD = ConfigKeys.newStringConfigKey(
+            "database.rubyrep.leftPassword", "password to connect to left db");
+
+    // Right database
+
+    AttributeSensor<String> RIGHT_DATASTORE_URL = Sensors.newSensorWithPrefix("right", DatastoreMixins.DATASTORE_URL);
+
+    @SetFromFlag("rightDatabase")
+    ConfigKey<? extends DatastoreCommon> RIGHT_DATABASE = ConfigKeys.newConfigKey(DatastoreCommon.class,
+            "database.rubyrep.rightDatabase", "Brooklyn database entity to use as the right DBMS");
+
+    @SetFromFlag("rightDatabaseName")
+    ConfigKey<String> RIGHT_DATABASE_NAME = ConfigKeys.newStringConfigKey(
+            "database.rubyrep.rightDatabaseName", "name of database to use for right db");
+
+    @SetFromFlag("rightUsername")
+    ConfigKey<String> RIGHT_USERNAME = ConfigKeys.newStringConfigKey(
+            "database.rubyrep.rightUsername", "username to connect to right db");
+
+    @SetFromFlag("rightPassword")
+    ConfigKey<String> RIGHT_PASSWORD = ConfigKeys.newStringConfigKey(
+            "database.rubyrep.rightPassword", "password to connect to right db");
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..282608f
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepNodeImpl.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.entity.database.rubyrep;
+
+import java.net.URI;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import brooklyn.event.basic.DependentConfiguration;
+import brooklyn.util.time.Duration;
+
+public class RubyRepNodeImpl extends SoftwareProcessImpl implements RubyRepNode {
+
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+        connectServiceUpIsRunning();
+    }
+
+    @Override
+    public void disconnectSensors() {
+        disconnectServiceUpIsRunning();
+        super.disconnectSensors();
+    }
+
+    /**
+     * Set the database {@link DatastoreCommon#DATASTORE_URL urls} as attributes when they become available on the entities.
+     */
+    @Override
+    protected void preStart() {
+        super.preStart();
+
+        DatastoreCommon leftNode = getConfig(LEFT_DATABASE);
+        if (leftNode != null) {
+            setAttribute(LEFT_DATASTORE_URL, Entities.submit(this, DependentConfiguration.attributeWhenReady(leftNode, DatastoreCommon.DATASTORE_URL)).getUnchecked(getDatabaseStartupDelay()));
+        }
+
+        DatastoreCommon rightNode = getConfig(RIGHT_DATABASE);
+        if (rightNode != null) {
+            setAttribute(RIGHT_DATASTORE_URL, Entities.submit(this, DependentConfiguration.attributeWhenReady(rightNode, DatastoreCommon.DATASTORE_URL)).getUnchecked(getDatabaseStartupDelay()));
+        }
+    }
+
+    @Override
+    public Class<?> getDriverInterface() {
+        return RubyRepDriver.class;
+    }
+
+    public Duration getDatabaseStartupDelay() {
+        return Duration.seconds(getConfig(DATABASE_STARTUP_TIMEOUT));
+    }
+
+    // Accessors used in freemarker template processing
+
+    public int getReplicationInterval() {
+        return getConfig(REPLICATION_INTERVAL);
+    }
+    
+    public String getTableRegex() {
+        return getConfig(TABLE_REGEXP);
+    }
+    
+    public URI getLeftDatabaseUrl() {
+        return URI.create(getAttribute(LEFT_DATASTORE_URL));
+    }
+    
+    public String getLeftDatabaseName() {
+        return getConfig(LEFT_DATABASE_NAME);
+    }
+
+    public String getLeftUsername() {
+        return getConfig(LEFT_USERNAME);
+    }
+
+    public String getLeftPassword() {
+        return getConfig(LEFT_PASSWORD);
+    }
+
+    public URI getRightDatabaseUrl() {
+        return URI.create(getAttribute(RIGHT_DATASTORE_URL));
+    }
+
+    public String getRightDatabaseName() {
+        return getConfig(RIGHT_DATABASE_NAME);
+    }
+
+    public String getRightUsername() {
+        return getConfig(RIGHT_USERNAME);
+    }
+
+    public String getRightPassword() {
+        return getConfig(RIGHT_PASSWORD);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepSshDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepSshDriver.java
new file mode 100644
index 0000000..ad8bfde
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/rubyrep/RubyRepSshDriver.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.entity.database.rubyrep;
+
+import static java.lang.String.format;
+
+import java.io.Reader;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.stream.Streams;
+
+import com.google.common.collect.ImmutableList;
+
+public class RubyRepSshDriver extends AbstractSoftwareProcessSshDriver implements RubyRepDriver {
+
+    public static final Logger log = LoggerFactory.getLogger(RubyRepSshDriver.class);
+
+    public RubyRepSshDriver(EntityLocal entity, SshMachineLocation machine) {
+        super(entity, machine);
+
+        entity.setAttribute(Attributes.LOG_FILE_LOCATION, getLogFileLocation());
+    }
+
+    protected String getLogFileLocation() {
+        return Os.mergePaths(getRunDir(), "log", "rubyrep.log");
+    }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this);
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("rubyrep-%s", getVersion()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+
+        List<String> commands = ImmutableList.<String>builder()
+                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
+                .add(BashCommands.INSTALL_UNZIP)
+                .add("unzip " + saveAs)
+                .build();
+
+        newScript(INSTALLING)
+                .body.append(commands)
+                .failOnNonZeroResultCode()
+                .execute();
+    }
+
+    @Override
+    public void customize() {
+        newScript(CUSTOMIZING)
+                .body.append(format("cp -R %s %s", getExpandedInstallDir(), getRunDir()))
+                .failOnNonZeroResultCode()
+                .execute();
+        try {
+            customizeConfiguration();
+        } catch (Exception e) {
+            log.error("Failed to configure rubyrep, replication is unlikely to succeed", e);
+        }
+    }
+
+    protected void customizeConfiguration() throws ExecutionException, InterruptedException, URISyntaxException {
+        log.info("Copying creation script " + getEntity().toString());
+
+        // TODO check these semantics are what we really want?
+        String configScriptUrl = entity.getConfig(RubyRepNode.CONFIGURATION_SCRIPT_URL);
+        Reader configContents;
+        if (configScriptUrl != null) {
+            // If set accept as-is
+            configContents = Streams.reader(resource.getResourceFromUrl(configScriptUrl));
+        } else {
+            String configScriptContents = processTemplate(entity.getConfig(RubyRepNode.TEMPLATE_CONFIGURATION_URL));
+            configContents = Streams.newReaderWithContents(configScriptContents);
+        }
+
+        getMachine().copyTo(configContents, getRunDir() + "/rubyrep.conf");
+    }
+
+    @Override
+    public void launch() {
+        newScript(MutableMap.of("usePidFile", true), LAUNCHING)
+                .body.append(format("nohup rubyrep-%s/jruby/bin/jruby rubyrep-%s/bin/rubyrep replicate -c rubyrep.conf > ./console 2>&1 &", getVersion(), getVersion()))
+                .execute();
+    }
+
+    @Override
+    public boolean isRunning() {
+        return newScript(MutableMap.of("usePidFile", true), CHECK_RUNNING).execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(MutableMap.of("usePidFile", true), STOPPING).execute();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/crate/crate.yaml
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/crate/crate.yaml b/software/database/src/main/resources/brooklyn/entity/database/crate/crate.yaml
deleted file mode 100644
index 42fcee5..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/crate/crate.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-# The Crate distribution comes with comprehensive instructions on available
-# configuration. Select sections are reproduced here.
-
-
-############################## Network And HTTP ###############################
-
-# Crate, by default, binds itself to the 0.0.0.0 address, and listens
-# on port [4200-4300] for HTTP traffic and on port [4300-4400] for node-to-node
-# communication. (the range means that if the port is busy, it will automatically
-# try the next port).
-
-# Set both 'bind_host' and 'publish_host':
-network.host: ${driver.subnetHostname}
-
-# Set a custom port for the node to node communication (4300 by default):
-transport.tcp.port: ${entity.port?c}
-
-# Set a custom port to listen for HTTP traffic:
-http.port: ${entity.httpPort?c}
-
-
-#################################### Paths ####################################
-
-# Path to directory where to store table data allocated for this node.
-path.data: ${driver.dataLocation}
-
-# Path to log files:
-path.logs: ${driver.runDir}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mariadb/my.cnf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mariadb/my.cnf b/software/database/src/main/resources/brooklyn/entity/database/mariadb/my.cnf
deleted file mode 100644
index d78f88e..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mariadb/my.cnf
+++ /dev/null
@@ -1,19 +0,0 @@
-[client]
-port            = ${driver.port?c}
-socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
-user            = root
-password        = ${entity.password}
-
-# Here follows entries for some specific programs
-
-# The MariaDB server, which (confusingly) uses MySQL terminology for backwards compatibility
-[mysqld]
-port            = ${driver.port?c}
-socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
-basedir         = ${driver.baseDir}
-datadir         = ${driver.dataDir}
-bind-address    = 0.0.0.0
-# skip-networking
-
-# Custom configuration options
-${driver.mariaDbServerOptionsString}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mssql/ConfigurationFile.ini
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mssql/ConfigurationFile.ini b/software/database/src/main/resources/brooklyn/entity/database/mssql/ConfigurationFile.ini
deleted file mode 100644
index ee437ac..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mssql/ConfigurationFile.ini
+++ /dev/null
@@ -1,390 +0,0 @@
-;SQL Server 2012 Configuration File
-
-
-[OPTIONS]
-
-
-
-; Specifies a Setup work flow, like INSTALL, UNINSTALL, or UPGRADE. This is a required parameter. 
-
-
-
-ACTION="Install"
-
-; Detailed help for command line argument ROLE has not been defined yet.
-
-ROLE="AllFeatures_WithDefaults"
-
-
-; Detailed help for command line argument ENU has not been defined yet. 
-
-
-
-ENU="True"
-
-
-
-; Setup will not display any user interface. 
-
-
-
-QUIET="True"
-
- 
-
-; Setup will display progress only, without any user interaction. 
-
-
-
-QUIETSIMPLE="False"
-
-
-
-; Specify whether SQL Server Setup should discover and include product updates. The valid values are True and False or 1 and 0. By default SQL Server Setup will include updates that are found. 
-
-
-
-UpdateEnabled="False"
-
-
-
-; Specifies features to install, uninstall, or upgrade. The list of top-level features include SQL, AS, RS, IS, MDS, and Tools. The SQL feature will install the Database Engine, Replication, Full-Text, and Data Quality Services (DQS) server. The Tools feature will install Management Tools, Books online components, SQL Server Data Tools, and other shared components. 
-
-
-
-FEATURES="${config['mssql.features']}"
-
-
-
-; Specify the location where SQL Server Setup will obtain product updates. The valid values are "MU" to search Microsoft Update, a valid folder path, a relative path such as .\MyUpdates or a UNC share. By default SQL Server Setup will search Microsoft Update or a Windows Update service through the Window Server Update Services. 
-
-
-
-UpdateSource="MU"
-
-
-
-; Displays the command line parameters usage 
-
-
-
-HELP="False"
-
-
-
-; Specifies that the detailed Setup log should be piped to the console. 
-
-
-
-INDICATEPROGRESS="True"
-
-
-
-; Specifies that Setup should install into WOW64. This command line argument is not supported on an IA64 or a 32-bit system. 
-
-
-
-X86="False"
-
-
-
-; Specify the root installation directory for shared components.  This directory remains unchanged after shared components are already installed. 
-
-
-
-INSTALLSHAREDDIR="C:\Program Files\Microsoft SQL Server"
-
-
-
-; Specify the root installation directory for the WOW64 shared components.  This directory remains unchanged after WOW64 shared components are already installed. 
-
-
-
-INSTALLSHAREDWOWDIR="C:\Program Files (x86)\Microsoft SQL Server"
-
-
-
-; Specify a default or named instance. MSSQLSERVER is the default instance for non-Express editions and SQLExpress for Express editions. This parameter is required when installing the SQL Server Database Engine (SQL), Analysis Services (AS), or Reporting Services (RS). 
-
-
-
-INSTANCENAME="MSSQLSERVER"
-
-
-
-; Specify the Instance ID for the SQL Server features you have specified. SQL Server directory structure, registry structure, and service names will incorporate the instance ID of the SQL Server instance. 
-
-
-
-INSTANCEID="MSSQLSERVER"
-
-
-
-; Specify that SQL Server feature usage data can be collected and sent to Microsoft. Specify 1 or True to enable and 0 or False to disable this feature. 
-
-
-
-SQMREPORTING="False"
-
-
-; The account used by the Distributed Replay Controller service.
-
-CTLRSVCACCOUNT="NT Service\SQL Server Distributed Replay Controller"
-
-; The startup type for the Distributed Replay Controller service.
-
-CTLRSTARTUPTYPE="Manual"
-
-; The account used by the Distributed Replay Client service.
-
-CLTSVCACCOUNT="NT Service\SQL Server Distributed Replay Client"
-
-; The startup type for the Distributed Replay Client service.
-
-CLTSTARTUPTYPE="Manual"
-
-; The result directory for the Distributed Replay Client service.
-
-CLTRESULTDIR="C:\Program Files (x86)\Microsoft SQL Server\DReplayClient\ResultDir"
-
-; The working directory for the Distributed Replay Client service.
-
-CLTWORKINGDIR="C:\Program Files (x86)\Microsoft SQL Server\DReplayClient\WorkingDir"
-
-; RSInputSettings_RSInstallMode_Description
-
-RSINSTALLMODE="DefaultNativeMode"
-
-; RSInputSettings_RSInstallMode_Description
-
-RSSHPINSTALLMODE="SharePointFilesOnlyMode"
-
-; Specify if errors can be reported to Microsoft to improve future SQL Server releases. Specify 1 or True to enable and 0 or False to disable this feature.
-
-
-
-; Specify if errors can be reported to Microsoft to improve future SQL Server releases. Specify 1 or True to enable and 0 or False to disable this feature. 
-
-
-
-ERRORREPORTING="False"
-
-
-
-; Specify the installation directory. 
-
-
-
-INSTANCEDIR="C:\Program Files\Microsoft SQL Server"
-
-
-
-; Agent account name 
-
-
-
-AGTSVCACCOUNT="NT Service\SQLSERVERAGENT"
-
-
-
-; Auto-start service after installation.  
-
-
-
-AGTSVCSTARTUPTYPE="Automatic"
-
-
-; Startup type for Integration Services.
-
-ISSVCSTARTUPTYPE="Automatic"
-
-; Account for Integration Services: Domain\User or system account.
-
-ISSVCACCOUNT="NT Service\MsDtsServer110"
-
-; The name of the account that the Analysis Services service runs under.
-
-ASSVCACCOUNT="NT Service\MSSQLServerOLAPService"
-
-; Controls the service startup type setting after the service has been created.
-
-ASSVCSTARTUPTYPE="Automatic"
-
-; The collation to be used by Analysis Services.
-
-ASCOLLATION="Latin1_General_CI_AS"
-
-; The location for the Analysis Services data files.
-
-ASDATADIR="C:\Program Files\Microsoft SQL Server\MSAS11.MSSQLSERVER\OLAP\Data"
-
-; The location for the Analysis Services log files.
-
-ASLOGDIR="C:\Program Files\Microsoft SQL Server\MSAS11.MSSQLSERVER\OLAP\Log"
-
-; The location for the Analysis Services backup files.
-
-ASBACKUPDIR="C:\Program Files\Microsoft SQL Server\MSAS11.MSSQLSERVER\OLAP\Backup"
-
-; The location for the Analysis Services temporary files.
-
-ASTEMPDIR="C:\Program Files\Microsoft SQL Server\MSAS11.MSSQLSERVER\OLAP\Temp"
-
-; The location for the Analysis Services configuration files.
-
-ASCONFIGDIR="C:\Program Files\Microsoft SQL Server\MSAS11.MSSQLSERVER\OLAP\Config"
-
-; Specifies whether or not the MSOLAP provider is allowed to run in process.
-
-ASPROVIDERMSOLAP="1"
-
-; Specifies the list of administrator accounts that need to be provisioned.
-
-ASSYSADMINACCOUNTS="BUILTIN\Administrators"
-
-; Specifies the server mode of the Analysis Services instance. Valid values are MULTIDIMENSIONAL and TABULAR. The default value is MULTIDIMENSIONAL.
-
-ASSERVERMODE="MULTIDIMENSIONAL"
-
-; CM brick TCP communication port 
-
-
-
-COMMFABRICPORT="0"
-
-
-
-; How matrix will use private networks 
-
-
-
-COMMFABRICNETWORKLEVEL="0"
-
-
-
-; How inter brick communication will be protected 
-
-
-
-COMMFABRICENCRYPTION="0"
-
-
-
-; TCP port used by the CM brick 
-
-
-
-MATRIXCMBRICKCOMMPORT="0"
-
-
-
-; Startup type for the SQL Server service. 
-
-
-
-SQLSVCSTARTUPTYPE="Automatic"
-
-
-
-; Level to enable FILESTREAM feature at (0, 1, 2 or 3). 
-
-
-
-FILESTREAMLEVEL="0"
-
-
-
-; Set to "1" to enable RANU for SQL Server Express. 
-
-
-
-ENABLERANU="False"
-
-
-
-; Specifies a Windows collation or an SQL collation to use for the Database Engine. 
-
-
-
-SQLCOLLATION="SQL_Latin1_General_CP1_CI_AS"
-
-
-
-; Account for SQL Server service: Domain\User or system account. 
-
-
-
-SQLSVCACCOUNT="NT Service\MSSQLSERVER"
-
-
-
-; Windows account(s) to provision as SQL Server system administrators. 
-
-
-
-SQLSYSADMINACCOUNTS="BUILTIN\Administrators"
-
-
-
-; The default is Windows Authentication. Use "SQL" for Mixed Mode Authentication. 
-
-
-
-SECURITYMODE="SQL"
-
-
-SAPWD="${config['mssql.sa.password']}"
-
-
-
-; Provision current user as a Database Engine system administrator for SQL Server 2012 Express. 
-
-
-
-ADDCURRENTUSERASSQLADMIN="False"
-
-
-
-; Specify 0 to disable or 1 to enable the TCP/IP protocol. 
-
-
-
-TCPENABLED="1"
-
-
-
-; Specify 0 to disable or 1 to enable the Named Pipes protocol. 
-
-
-
-NPENABLED="0"
-
-
-
-; Startup type for Browser Service. 
-
-
-
-BROWSERSVCSTARTUPTYPE="Disabled"
-
-
-; Specifies which account the report server NT service should execute under.  When omitted or when the value is empty string, the default built-in account for the current operating system.
-; The username part of RSSVCACCOUNT is a maximum of 20 characters long and
-; The domain part of RSSVCACCOUNT is a maximum of 254 characters long.
-
-RSSVCACCOUNT="NT Service\ReportServer"
-
-; Specifies how the startup mode of the report server NT service.  When
-; Manual - Service startup is manual mode (default).
-; Automatic - Service startup is automatic mode.
-; Disabled - Service is disabled
-
-RSSVCSTARTUPTYPE="Automatic"
-
-; Add description of input argument FTSVCACCOUNT
-
-FTSVCACCOUNT="NT Service\MSSQLFDLauncher"
-
-
-
-IAcceptSQLServerLicenseTerms="True"

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mssql/checkrunningmssql.bat
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mssql/checkrunningmssql.bat b/software/database/src/main/resources/brooklyn/entity/database/mssql/checkrunningmssql.bat
deleted file mode 100644
index 34512c8..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mssql/checkrunningmssql.bat
+++ /dev/null
@@ -1,23 +0,0 @@
-[#ftl]
-@echo off
-REM Licensed to the Apache Software Foundation (ASF) under one
-REM or more contributor license agreements.  See the NOTICE file
-REM distributed with this work for additional information
-REM regarding copyright ownership.  The ASF licenses this file
-REM to you under the Apache License, Version 2.0 (the
-REM "License"); you may not use this file except in compliance
-REM with the License.  You may obtain a copy of the License at
-REM
-REM   http://www.apache.org/licenses/LICENSE-2.0
-REM
-REM Unless required by applicable law or agreed to in writing,
-REM software distributed under the License is distributed on an
-REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-REM KIND, either express or implied.  See the License for the
-REM specific language governing permissions and limitations
-REM under the License.
-
-set serviceName=MSSQL\$${config['mssql.instance.name']}
-
-[#noparse]
-sc query %serviceName% | find "RUNNING"

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mssql/configuremssql.ps1
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mssql/configuremssql.ps1 b/software/database/src/main/resources/brooklyn/entity/database/mssql/configuremssql.ps1
deleted file mode 100644
index 06522fd..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mssql/configuremssql.ps1
+++ /dev/null
@@ -1,22 +0,0 @@
-[#ftl]
-#!ps1
-#
-# 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.
-#
-netsh advfirewall firewall add rule name=SQLPort dir=in protocol=tcp action=allow localport=1433 remoteip=any profile=any
-( Get-WmiObject -Namespace "root\Microsoft\SqlServer\ComputerManagement11" -Query "Select * from ServerNetworkProtocolProperty where ProtocolName='Tcp' and IPAddressName='IPAll' and PropertyName='TcpPort'" ).SetStringValue("1433")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mssql/installmssql.ps1
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mssql/installmssql.ps1 b/software/database/src/main/resources/brooklyn/entity/database/mssql/installmssql.ps1
deleted file mode 100644
index 6c1f30b..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mssql/installmssql.ps1
+++ /dev/null
@@ -1,49 +0,0 @@
-[#ftl]
-#!ps1
-#
-# 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.
-#
-
-$Url = "${config['mssql.download.url']}"
-$Path = "C:\sql2008.iso"
-$Username = "${config['mssql.download.user']}"
-$Password = '${config['mssql.download.password']}'
-
-
-$WebClient = New-Object System.Net.WebClient
-$WebClient.Credentials = New-Object System.Net.Networkcredential($Username, $Password)
-$WebClient.DownloadFile( $url, $path )
-
-$mountResult = Mount-DiskImage $Path -PassThru
-$driveLetter = (($mountResult | Get-Volume).DriveLetter) + ":\"
-
-New-Item -ItemType Directory -Force -Path "C:\Program Files (x86)\Microsoft SQL Server\DReplayClient\ResultDir"
-New-Item -ItemType Directory -Force -Path "C:\Program Files (x86)\Microsoft SQL Server\DReplayClient\WorkingDir"
-
-Install-WindowsFeature NET-Framework-Core
-
-$pass = '${attribute['windows.password']}'
-$secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force
-$mycreds = New-Object System.Management.Automation.PSCredential ($($env:COMPUTERNAME + "\Administrator"), $secpasswd)
-
-Invoke-Command -ComputerName localhost -credential $mycreds -scriptblock {
-    param($driveLetter)
-    Start-Process ( $driveLetter + "setup.exe") -ArgumentList "/ConfigurationFile=C:\ConfigurationFile.ini" -RedirectStandardOutput "C:\sqlout.txt" -RedirectStandardError "C:\sqlerr.txt" -Wait
-} -Authentication CredSSP -argumentlist $driveLetter
-
-## Process complete
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mssql/launchmssql.bat
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mssql/launchmssql.bat b/software/database/src/main/resources/brooklyn/entity/database/mssql/launchmssql.bat
deleted file mode 100644
index ad0deff..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mssql/launchmssql.bat
+++ /dev/null
@@ -1,25 +0,0 @@
-[#ftl]
-@echo off
-REM Licensed to the Apache Software Foundation (ASF) under one
-REM or more contributor license agreements.  See the NOTICE file
-REM distributed with this work for additional information
-REM regarding copyright ownership.  The ASF licenses this file
-REM to you under the Apache License, Version 2.0 (the
-REM "License"); you may not use this file except in compliance
-REM with the License.  You may obtain a copy of the License at
-REM
-REM   http://www.apache.org/licenses/LICENSE-2.0
-REM
-REM Unless required by applicable law or agreed to in writing,
-REM software distributed under the License is distributed on an
-REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-REM KIND, either express or implied.  See the License for the
-REM specific language governing permissions and limitations
-REM under the License.
-
-set serviceName=MSSQL\$${config['mssql.instance.name']}
-
-[#noparse]
-sc stop %serviceName%
-sc config %serviceName% start=auto
-sc start %serviceName%

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml b/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml
deleted file mode 100644
index d82a7f7..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml
+++ /dev/null
@@ -1,40 +0,0 @@
-name: mssql
-
-location:
-  jclouds:aws-ec2:us-west-2:
-    displayName: AWS Oregon (Windows)
-    imageId: us-west-2/ami-8fd3f9bf
-    hardwareId:  m3.medium
-    useJcloudsSshInit: false
-    templateOptions:
-      subnetId: subnet-a10e96c4
-      securityGroupIds: [['sg-a2d0c2c7']]
-      mapNewVolumeToDeviceName: ["/dev/sda1", 100, true]
-
-services:
-- type: brooklyn.entity.basic.VanillaWindowsProcess
-  brooklyn.config:
-    templates.install:
-      classpath://brooklyn/entity/database/mssql/ConfigurationFile.ini: "C:\\ConfigurationFile.ini"
-      classpath://brooklyn/entity/database/mssql/installmssql.ps1: "C:\\installmssql.ps1"
-      classpath://brooklyn/entity/database/mssql/configuremssql.ps1: "C:\\configuremssql.ps1"
-      classpath://brooklyn/entity/database/mssql/launchmssql.bat: "C:\\launchmssql.bat"
-      classpath://brooklyn/entity/database/mssql/stopmssql.bat: "C:\\stopmssql.bat"
-    install.command: powershell -command "C:\\installmssql.ps1"
-    customize.command: powershell -command "C:\\configuremssql.ps1"
-    launch.command: "C:\\launchmssql.bat"
-    stop.command: "C:\\stopmssql.bat"
-    checkRunning.command: echo true
-
-    ## NOTE: Values must be supplied for the following
-    mssql.download.url:
-    mssql.download.user:
-    mssql.download.password:
-    mssql.sa.password:
-    mssql.instance.name:
-
-    ## The following is a list of *all* MSSQL features. Installation time and footprint can be greatly
-    ## reduced by removing unnecessary features
-    mssql.features: "SQLENGINE,REPLICATION,FULLTEXT,DQ,AS,RS,RS_SHP,DQC,BIDS,CONN,IS,BC,SDK,BOL,SSMS,ADV_SSMS,DREPLAY_CTLR,DREPLAY_CLT,SNAC_SDK"
-  provisioning.properties:
-    required.ports: 1433
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mssql/stopmssql.bat
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mssql/stopmssql.bat b/software/database/src/main/resources/brooklyn/entity/database/mssql/stopmssql.bat
deleted file mode 100644
index 68358f1..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mssql/stopmssql.bat
+++ /dev/null
@@ -1,24 +0,0 @@
-[#ftl]
-@echo off
-REM Licensed to the Apache Software Foundation (ASF) under one
-REM or more contributor license agreements.  See the NOTICE file
-REM distributed with this work for additional information
-REM regarding copyright ownership.  The ASF licenses this file
-REM to you under the Apache License, Version 2.0 (the
-REM "License"); you may not use this file except in compliance
-REM with the License.  You may obtain a copy of the License at
-REM
-REM   http://www.apache.org/licenses/LICENSE-2.0
-REM
-REM Unless required by applicable law or agreed to in writing,
-REM software distributed under the License is distributed on an
-REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-REM KIND, either express or implied.  See the License for the
-REM specific language governing permissions and limitations
-REM under the License.
-
-set serviceName=MSSQL\$${config['mssql.instance.name']}
-
-[#noparse]
-sc config %serviceName% start=demand
-sc stop %serviceName%

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql.conf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql.conf b/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql.conf
deleted file mode 100644
index 85f55ab..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-[client]
-port            = ${driver.port?c}
-socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
-user            = root
-password        = ${entity.password}
-
-# Here follows entries for some specific programs
-
-# The MySQL server
-[mysqld]
-port            = ${driver.port?c}
-socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
-basedir         = ${driver.baseDir}
-datadir         = ${driver.dataDir}
-bind-address    = 0.0.0.0
-# skip-networking
-
-# Custom configuration options
-${driver.mySqlServerOptionsString}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql_master.conf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql_master.conf b/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql_master.conf
deleted file mode 100644
index 791f2da..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql_master.conf
+++ /dev/null
@@ -1,26 +0,0 @@
-[client]
-port            = ${driver.port?c}
-socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
-user            = root
-password        = ${entity.password}
-
-# Here follows entries for some specific programs
-
-# The MySQL server
-[mysqld]
-port            = ${driver.port?c}
-socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
-basedir         = ${driver.baseDir}
-datadir         = ${driver.dataDir}
-bind-address    = 0.0.0.0
-# skip-networking
-
-# Replication config
-server-id       = 1
-binlog-format   = mixed
-log-bin         = mysql-bin
-sync_binlog     = 1
-innodb_flush_log_at_trx_commit=1
-
-# Custom configuration options
-${driver.mySqlServerOptionsString}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql_slave.conf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql_slave.conf b/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql_slave.conf
deleted file mode 100644
index 2e1e945..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/mysql/mysql_slave.conf
+++ /dev/null
@@ -1,33 +0,0 @@
-[#ftl]
-[client]
-port            = ${driver.port?c}
-socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
-user            = root
-password        = ${entity.password}
-
-# Here follows entries for some specific programs
-
-# The MySQL server
-[mysqld]
-port            = ${driver.port?c}
-socket          = /tmp/mysql.sock.${entity.socketUid}.${driver.port?c}
-basedir         = ${driver.baseDir}
-datadir         = ${driver.dataDir}
-bind-address    = 0.0.0.0
-# skip-networking
-
-# Replication config
-server-id       = ${config["mysql.server_id"]}
-relay-log       = mysql-slave-${config["mysql.server_id"]}-relay
-relay-log-recovery = 1
-relay-log-info-repository = TABLE
-relay-log-purge = 1
-[#if !config["mysql.slave.replicate_do_db"]??            ]#[/#if]replicate-do-db             = ${config["mysql.slave.replicate_do_db"]!}
-[#if !config["mysql.slave.replicate_ignore_db"]??        ]#[/#if]replicate-ignore-db         = ${config["mysql.slave.replicate_ignore_db"]!}
-[#if !config["mysql.slave.replicate_do_table"]??         ]#[/#if]replicate-do-table          = ${config["mysql.slave.replicate_do_table"]!}
-[#if !config["mysql.slave.replicate_ignore_table"]??     ]#[/#if]replicate-ignore-table      = ${config["mysql.slave.replicate_ignore_table"]!}
-[#if !config["mysql.slave.replicate_wild_do_table"]??    ]#[/#if]replicate-wild-do-table     = ${config["mysql.slave.replicate_wild_do_table"]!}
-[#if !config["mysql.slave.replicate_wild_ignore_table"]??]#[/#if]replicate-wild-ignore-table = ${config["mysql.slave.replicate_wild_ignore_table"]!}
-
-# Custom configuration options
-${driver.mySqlServerOptionsString}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/postgresql/postgresql.conf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/postgresql/postgresql.conf b/software/database/src/main/resources/brooklyn/entity/database/postgresql/postgresql.conf
deleted file mode 100644
index b6234c9..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/postgresql/postgresql.conf
+++ /dev/null
@@ -1,513 +0,0 @@
-[#ftl]
-#
-
-# -----------------------------
-# PostgreSQL configuration file
-# -----------------------------
-#
-# This file consists of lines of the form:
-#
-#   name = value
-#
-# (The "=" is optional.)  Whitespace may be used.  Comments are introduced with
-# "#" anywhere on a line.  The complete list of parameter names and allowed
-# values can be found in the PostgreSQL documentation.
-#
-# The commented-out settings shown in this file represent the default values.
-# Re-commenting a setting is NOT sufficient to revert it to the default value;
-# you need to reload the server.
-#
-# This file is read on server startup and when the server receives a SIGHUP
-# signal.  If you edit the file on a running system, you have to SIGHUP the
-# server for the changes to take effect, or use "pg_ctl reload".  Some
-# parameters, which are marked below, require a server shutdown and restart to
-# take effect.
-#
-# Any parameter can also be given as a command-line option to the server, e.g.,
-# "postgres -c log_connections=on".  Some parameters can be changed at run time
-# with the "SET" SQL command.
-#
-# Memory units:  kB = kilobytes        Time units:  ms  = milliseconds
-#                MB = megabytes                     s   = seconds
-#                GB = gigabytes                     min = minutes
-#                                                   h   = hours
-#                                                   d   = days
-
-
-#------------------------------------------------------------------------------
-# FILE LOCATIONS
-#------------------------------------------------------------------------------
-
-# The default values of these variables are driven from the -D command-line
-# option or PGDATA environment variable.
-
-data_directory = '${driver.dataDir}'       # use data in another directory
-                    # (change requires restart)
-#hba_file = '${driver.dataDir}/pg_hba.conf' # host-based authentication file
-                    # (change requires restart)
-#ident_file = '${driver.dataDir}/pg_ident.conf' # ident configuration file
-                    # (change requires restart)
-
-# If external_pid_file is not explicitly set, no extra PID file is written.
-external_pid_file = '${driver.pidFile}'       # write an extra PID file
-                    # (change requires restart)
-
-
-#------------------------------------------------------------------------------
-# CONNECTIONS AND AUTHENTICATION
-#------------------------------------------------------------------------------
-
-# - Connection Settings -
-
-listen_addresses = '${driver.hostname}'     # what IP address(es) to listen on;
-                    # comma-separated list of addresses;
-                    # defaults to 'localhost', '*' = all
-                    # (change requires restart)
-port = ${entity.postgreSqlPort?c}                # (change requires restart)
-max_connections = ${entity.maxConnections?c}           # (change requires restart)
-# Note:  Increasing max_connections costs ~400 bytes of shared memory per 
-# connection slot, plus lock space (see max_locks_per_transaction).
-#superuser_reserved_connections = 3 # (change requires restart)
-#unix_socket_directory = ''     # (change requires restart)
-#unix_socket_group = ''         # (change requires restart)
-#unix_socket_permissions = 0777     # begin with 0 to use octal notation
-                    # (change requires restart)
-#bonjour = off              # advertise server via Bonjour
-                    # (change requires restart)
-#bonjour_name = ''          # defaults to the computer name
-                    # (change requires restart)
-
-# - Security and Authentication -
-
-#authentication_timeout = 1min      # 1s-600s
-#ssl = off              # (change requires restart)
-#ssl_ciphers = 'ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH'  # allowed SSL ciphers
-                    # (change requires restart)
-#password_encryption = on
-#db_user_namespace = off
-
-# Kerberos and GSSAPI
-#krb_server_keyfile = ''
-#krb_srvname = 'postgres'       # (Kerberos only)
-#krb_caseins_users = off
-
-# - TCP Keepalives -
-# see "man 7 tcp" for details
-
-#tcp_keepalives_idle = 0        # TCP_KEEPIDLE, in seconds;
-                    # 0 selects the system default
-#tcp_keepalives_interval = 0        # TCP_KEEPINTVL, in seconds;
-                    # 0 selects the system default
-#tcp_keepalives_count = 0       # TCP_KEEPCNT;
-                    # 0 selects the system default
-
-
-#------------------------------------------------------------------------------
-# RESOURCE USAGE (except WAL)
-#------------------------------------------------------------------------------
-
-# - Memory -
-
-shared_buffers = ${entity.sharedMemory}           # min 128kB
-                    # (change requires restart)
-#temp_buffers = 8MB         # min 800kB
-#max_prepared_transactions = 0      # zero disables the feature
-                    # (change requires restart)
-# Note:  Increasing max_prepared_transactions costs ~600 bytes of shared memory
-# per transaction slot, plus lock space (see max_locks_per_transaction).
-# It is not advisable to set max_prepared_transactions nonzero unless you
-# actively intend to use prepared transactions.
-#work_mem = 1MB             # min 64kB
-#maintenance_work_mem = 16MB        # min 1MB
-#max_stack_depth = 2MB          # min 100kB
-
-# - Kernel Resource Usage -
-
-#max_files_per_process = 1000       # min 25
-                    # (change requires restart)
-#shared_preload_libraries = ''      # (change requires restart)
-
-# - Cost-Based Vacuum Delay -
-
-#vacuum_cost_delay = 0ms        # 0-100 milliseconds
-#vacuum_cost_page_hit = 1       # 0-10000 credits
-#vacuum_cost_page_miss = 10     # 0-10000 credits
-#vacuum_cost_page_dirty = 20        # 0-10000 credits
-#vacuum_cost_limit = 200        # 1-10000 credits
-
-# - Background Writer -
-
-#bgwriter_delay = 200ms         # 10-10000ms between rounds
-#bgwriter_lru_maxpages = 100        # 0-1000 max buffers written/round
-#bgwriter_lru_multiplier = 2.0      # 0-10.0 multipler on buffers scanned/round
-
-# - Asynchronous Behavior -
-
-#effective_io_concurrency = 1       # 1-1000. 0 disables prefetching
-
-
-#------------------------------------------------------------------------------
-# WRITE AHEAD LOG
-#------------------------------------------------------------------------------
-
-# - Settings -
-
-#fsync = on             # turns forced synchronization on or off
-#synchronous_commit = on        # immediate fsync at commit
-#wal_sync_method = fsync        # the default is the first option 
-                    # supported by the operating system:
-                    #   open_datasync
-                    #   fdatasync
-                    #   fsync
-                    #   fsync_writethrough
-                    #   open_sync
-#full_page_writes = on          # recover from partial page writes
-#wal_buffers = 64kB         # min 32kB
-                    # (change requires restart)
-#wal_writer_delay = 200ms       # 1-10000 milliseconds
-
-#commit_delay = 0           # range 0-100000, in microseconds
-#commit_siblings = 5            # range 1-1000
-
-# - Checkpoints -
-
-#checkpoint_segments = 3        # in logfile segments, min 1, 16MB each
-#checkpoint_timeout = 5min      # range 30s-1h
-#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0
-#checkpoint_warning = 30s       # 0 disables
-
-# - Archiving -
-
-#archive_mode = off     # allows archiving to be done
-                # (change requires restart)
-#archive_command = ''       # command to use to archive a logfile segment
-#archive_timeout = 0        # force a logfile segment switch after this
-                # number of seconds; 0 disables
-
-
-#------------------------------------------------------------------------------
-# QUERY TUNING
-#------------------------------------------------------------------------------
-
-# - Planner Method Configuration -
-
-#enable_bitmapscan = on
-#enable_hashagg = on
-#enable_hashjoin = on
-#enable_indexscan = on
-#enable_mergejoin = on
-#enable_nestloop = on
-#enable_seqscan = on
-#enable_sort = on
-#enable_tidscan = on
-
-# - Planner Cost Constants -
-
-#seq_page_cost = 1.0            # measured on an arbitrary scale
-#random_page_cost = 4.0         # same scale as above
-#cpu_tuple_cost = 0.01          # same scale as above
-#cpu_index_tuple_cost = 0.005       # same scale as above
-#cpu_operator_cost = 0.0025     # same scale as above
-#effective_cache_size = 128MB
-
-# - Genetic Query Optimizer -
-
-#geqo = on
-#geqo_threshold = 12
-#geqo_effort = 5            # range 1-10
-#geqo_pool_size = 0         # selects default based on effort
-#geqo_generations = 0           # selects default based on effort
-#geqo_selection_bias = 2.0      # range 1.5-2.0
-#geqo_seed = 0.0            # range 0.0-1.0
-
-# - Other Planner Options -
-
-#default_statistics_target = 100    # range 1-10000
-#constraint_exclusion = partition   # on, off, or partition
-#cursor_tuple_fraction = 0.1        # range 0.0-1.0
-#from_collapse_limit = 8
-#join_collapse_limit = 8        # 1 disables collapsing of explicit 
-                    # JOIN clauses
-
-
-#------------------------------------------------------------------------------
-# ERROR REPORTING AND LOGGING
-#------------------------------------------------------------------------------
-
-# - Where to Log -
-
-#log_destination = 'stderr'     # Valid values are combinations of
-                    # stderr, csvlog, syslog and eventlog,
-                    # depending on platform.  csvlog
-                    # requires logging_collector to be on.
-
-# This is used when logging to stderr:
-#logging_collector = off        # Enable capturing of stderr and csvlog
-                    # into log files. Required to be on for
-                    # csvlogs.
-                    # (change requires restart)
-
-# These are only used if logging_collector is on:
-#log_directory = 'pg_log'       # directory where log files are written,
-                    # can be absolute or relative to PGDATA
-#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'    # log file name pattern,
-                    # can include strftime() escapes
-#log_truncate_on_rotation = off     # If on, an existing log file of the
-                    # same name as the new log file will be
-                    # truncated rather than appended to.
-                    # But such truncation only occurs on
-                    # time-driven rotation, not on restarts
-                    # or size-driven rotation.  Default is
-                    # off, meaning append to existing files
-                    # in all cases.
-#log_rotation_age = 1d          # Automatic rotation of logfiles will
-                    # happen after that time.  0 disables.
-#log_rotation_size = 10MB       # Automatic rotation of logfiles will 
-                    # happen after that much log output.
-                    # 0 disables.
-
-# These are relevant when logging to syslog:
-#syslog_facility = 'LOCAL0'
-#syslog_ident = 'postgres'
-
-#silent_mode = off          # Run server silently.
-                    # DO NOT USE without syslog or
-                    # logging_collector
-                    # (change requires restart)
-
-
-# - When to Log -
-
-#client_min_messages = notice       # values in order of decreasing detail:
-                    #   debug5
-                    #   debug4
-                    #   debug3
-                    #   debug2
-                    #   debug1
-                    #   log
-                    #   notice
-                    #   warning
-                    #   error
-
-#log_min_messages = warning     # values in order of decreasing detail:
-                    #   debug5
-                    #   debug4
-                    #   debug3
-                    #   debug2
-                    #   debug1
-                    #   info
-                    #   notice
-                    #   warning
-                    #   error
-                    #   log
-                    #   fatal
-                    #   panic
-
-#log_error_verbosity = default      # terse, default, or verbose messages
-
-#log_min_error_statement = error    # values in order of decreasing detail:
-                    #   debug5
-                    #   debug4
-                    #   debug3
-                    #   debug2
-                    #   debug1
-                    #   info
-                    #   notice
-                    #   warning
-                    #   error
-                    #   log
-                    #   fatal
-                    #   panic (effectively off)
-
-#log_min_duration_statement = -1    # -1 is disabled, 0 logs all statements
-                    # and their durations, > 0 logs only
-                    # statements running at least this number
-                    # of milliseconds
-
-
-# - What to Log -
-
-#debug_print_parse = off
-#debug_print_rewritten = off
-#debug_print_plan = off
-#debug_pretty_print = on
-#log_checkpoints = off
-#log_connections = off
-#log_disconnections = off
-#log_duration = off
-#log_hostname = off
-#log_line_prefix = ''           # special values:
-                    #   %u = user name
-                    #   %d = database name
-                    #   %r = remote host and port
-                    #   %h = remote host
-                    #   %p = process ID
-                    #   %t = timestamp without milliseconds
-                    #   %m = timestamp with milliseconds
-                    #   %i = command tag
-                    #   %e = SQL state
-                    #   %c = session ID
-                    #   %l = session line number
-                    #   %s = session start timestamp
-                    #   %v = virtual transaction ID
-                    #   %x = transaction ID (0 if none)
-                    #   %q = stop here in non-session
-                    #        processes
-                    #   %% = '%'
-                    # e.g. '<%u%%%d> '
-#log_lock_waits = off           # log lock waits >= deadlock_timeout
-#log_statement = 'none'         # none, ddl, mod, all
-#log_temp_files = -1            # log temporary files equal or larger
-                    # than the specified size in kilobytes;
-                    # -1 disables, 0 logs all temp files
-#log_timezone = unknown         # actually, defaults to TZ environment
-                    # setting
-
-
-#------------------------------------------------------------------------------
-# RUNTIME STATISTICS
-#------------------------------------------------------------------------------
-
-# - Query/Index Statistics Collector -
-
-#track_activities = on
-#track_counts = on
-#track_functions = none         # none, pl, all
-#track_activity_query_size = 1024
-#update_process_title = on
-#stats_temp_directory = 'pg_stat_tmp'
-
-
-# - Statistics Monitoring -
-
-#log_parser_stats = off
-#log_planner_stats = off
-#log_executor_stats = off
-#log_statement_stats = off
-
-
-#------------------------------------------------------------------------------
-# AUTOVACUUM PARAMETERS
-#------------------------------------------------------------------------------
-
-#autovacuum = on            # Enable autovacuum subprocess?  'on' 
-                    # requires track_counts to also be on.
-#log_autovacuum_min_duration = -1   # -1 disables, 0 logs all actions and
-                    # their durations, > 0 logs only
-                    # actions running at least this number
-                    # of milliseconds.
-#autovacuum_max_workers = 3     # max number of autovacuum subprocesses
-#autovacuum_naptime = 1min      # time between autovacuum runs
-#autovacuum_vacuum_threshold = 50   # min number of row updates before
-                    # vacuum
-#autovacuum_analyze_threshold = 50  # min number of row updates before 
-                    # analyze
-#autovacuum_vacuum_scale_factor = 0.2   # fraction of table size before vacuum
-#autovacuum_analyze_scale_factor = 0.1  # fraction of table size before analyze
-#autovacuum_freeze_max_age = 200000000  # maximum XID age before forced vacuum
-                    # (change requires restart)
-#autovacuum_vacuum_cost_delay = 20ms    # default vacuum cost delay for
-                    # autovacuum, in milliseconds;
-                    # -1 means use vacuum_cost_delay
-#autovacuum_vacuum_cost_limit = -1  # default vacuum cost limit for
-                    # autovacuum, -1 means use
-                    # vacuum_cost_limit
-
-
-#------------------------------------------------------------------------------
-# CLIENT CONNECTION DEFAULTS
-#------------------------------------------------------------------------------
-
-# - Statement Behavior -
-
-#search_path = '"[#noparse]$user[/#noparse]",public'     # schema names
-#default_tablespace = ''        # a tablespace name, '' uses the default
-#temp_tablespaces = ''          # a list of tablespace names, '' uses
-                    # only default tablespace
-#check_function_bodies = on
-#default_do_language = 'plpgsql'
-#default_transaction_isolation = 'read committed'
-#default_transaction_read_only = off
-#session_replication_role = 'origin'
-#statement_timeout = 0          # in milliseconds, 0 is disabled
-#vacuum_freeze_min_age = 50000000
-#vacuum_freeze_table_age = 150000000
-#bytea_output = 'hex'           # hex, escape
-#xmlbinary = 'base64'
-#xmloption = 'content'
-
-# - Locale and Formatting -
-
-datestyle = 'iso, mdy'
-#intervalstyle = 'postgres'
-#timezone = unknown         # actually, defaults to TZ environment
-                    # setting
-#timezone_abbreviations = 'Default'     # Select the set of available time zone
-                    # abbreviations.  Currently, there are
-                    #   Default
-                    #   Australia
-                    #   India
-                    # You can create your own file in
-                    # share/timezonesets/.
-#extra_float_digits = 0         # min -15, max 3
-#client_encoding = sql_ascii        # actually, defaults to database
-                    # encoding
-
-# These settings are initialized by initdb, but they can be changed.
-lc_messages = 'en_US.UTF-8'         # locale for system error message
-                    # strings
-lc_monetary = 'en_US.UTF-8'         # locale for monetary formatting
-lc_numeric = 'en_US.UTF-8'          # locale for number formatting
-lc_time = 'en_US.UTF-8'             # locale for time formatting
-
-# default configuration for text search
-default_text_search_config = 'pg_catalog.english'
-
-# - Other Defaults -
-
-#dynamic_library_path = '[#noparse]$libdir[/#noparse]'
-#local_preload_libraries = ''
-
-
-#------------------------------------------------------------------------------
-# LOCK MANAGEMENT
-#------------------------------------------------------------------------------
-
-#deadlock_timeout = 1s
-#max_locks_per_transaction = 64     # min 10
-                    # (change requires restart)
-# Note:  Each lock table slot uses ~270 bytes of shared memory, and there are
-# max_locks_per_transaction * (max_connections + max_prepared_transactions)
-# lock table slots.
-
-
-#------------------------------------------------------------------------------
-# VERSION/PLATFORM COMPATIBILITY
-#------------------------------------------------------------------------------
-
-# - Previous PostgreSQL Versions -
-
-#add_missing_from = off
-#array_nulls = on
-#backslash_quote = safe_encoding    # on, off, or safe_encoding
-#default_with_oids = off
-#escape_string_warning = on
-#regex_flavor = advanced        # advanced, extended, or basic
-#sql_inheritance = on
-#standard_conforming_strings = off
-#synchronize_seqscans = on
-
-# - Other Platforms and Clients -
-
-#transform_null_equals = off
-
-
-#------------------------------------------------------------------------------
-# CUSTOMIZED OPTIONS
-#------------------------------------------------------------------------------
-
-#custom_variable_classes = ''       # list of custom variable class names
-
-# Lines that pgtune has had problems parsing
-
-log_line_prefix = 'user=%u,db=%d '

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/resources/brooklyn/entity/database/rubyrep/rubyrep.conf
----------------------------------------------------------------------
diff --git a/software/database/src/main/resources/brooklyn/entity/database/rubyrep/rubyrep.conf b/software/database/src/main/resources/brooklyn/entity/database/rubyrep/rubyrep.conf
deleted file mode 100644
index 12fed6f..0000000
--- a/software/database/src/main/resources/brooklyn/entity/database/rubyrep/rubyrep.conf
+++ /dev/null
@@ -1,28 +0,0 @@
-[#ftl]
-#
-
-RR::Initializer::run do |config|
-config.left = {
-:adapter  => '${entity.leftDatabaseUrl.scheme}', 
-:database => '${entity.leftDatabaseName}',
-:username => '${entity.leftUsername}',
-:password => '${entity.leftPassword}',
-:host     => '${entity.leftDatabaseUrl.host}',
-:port     => ${entity.leftDatabaseUrl.port?c}
-}
- 
-config.right ={
-:adapter  => '${entity.rightDatabaseUrl.scheme}', 
-:database => '${entity.rightDatabaseName}',
-:username => '${entity.rightUsername}',
-:password => '${entity.rightPassword}',
-:host     => '${entity.rightDatabaseUrl.host}',
-:port     => ${entity.rightDatabaseUrl.port?c}
-}
- 
-config.include_tables /${entity.tableRegex}/
-config.options[:replication_interval] = ${entity.replicationInterval?c}
-config.options[:logged_replication_events] = [
-:all_changes, 
-:all_conflicts
-]end



[08/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/osgi/OsgisTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/osgi/OsgisTest.java b/core/src/test/java/org/apache/brooklyn/core/util/osgi/OsgisTest.java
new file mode 100644
index 0000000..cdaf433
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/osgi/OsgisTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.util.osgi;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import org.apache.brooklyn.core.util.osgi.Osgis;
+import org.apache.brooklyn.core.util.osgi.Osgis.VersionedName;
+import org.osgi.framework.Version;
+import org.testng.annotations.Test;
+
+public class OsgisTest {
+
+    @Test
+    public void testParseOsgiIdentifier() throws Exception {
+        assertEquals(Osgis.parseOsgiIdentifier("a.b").get(), new VersionedName("a.b", null));
+        assertEquals(Osgis.parseOsgiIdentifier("a.b:0.1.2").get(), new VersionedName("a.b", Version.parseVersion("0.1.2")));
+        assertEquals(Osgis.parseOsgiIdentifier("a.b:0.0.0.SNAPSHOT").get(), new VersionedName("a.b", Version.parseVersion("0.0.0.SNAPSHOT")));
+        assertFalse(Osgis.parseOsgiIdentifier("a.b:0.notanumber.2").isPresent()); // invalid version
+        assertFalse(Osgis.parseOsgiIdentifier("a.b:0.1.2:3.4.5").isPresent());    // too many colons
+        assertFalse(Osgis.parseOsgiIdentifier("a.b:0.0.0_SNAPSHOT").isPresent()); // invalid version
+        assertFalse(Osgis.parseOsgiIdentifier("").isPresent());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/ssh/BashCommandsIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/ssh/BashCommandsIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/util/ssh/BashCommandsIntegrationTest.java
new file mode 100644
index 0000000..77f91f6
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/ssh/BashCommandsIntegrationTest.java
@@ -0,0 +1,504 @@
+/*
+ * 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.util.ssh;
+
+import static brooklyn.util.ssh.BashCommands.sudo;
+import static java.lang.String.format;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
+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 brooklyn.entity.basic.Entities;
+
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.javalang.JavaClassNames;
+import brooklyn.util.net.Networking;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.Files;
+
+public class BashCommandsIntegrationTest {
+
+    private static final Logger log = LoggerFactory.getLogger(BashCommandsIntegrationTest.class);
+    
+    private ManagementContext mgmt;
+    private BasicExecutionContext exec;
+    
+    private File destFile;
+    private File sourceNonExistantFile;
+    private File sourceFile1;
+    private File sourceFile2;
+    private String sourceNonExistantFileUrl;
+    private String sourceFileUrl1;
+    private String sourceFileUrl2;
+    private SshMachineLocation loc;
+
+    private String localRepoFilename = "localrepofile.txt";
+    private File localRepoBasePath;
+    private File localRepoEntityBasePath;
+    private String localRepoEntityVersionPath;
+    private File localRepoEntityFile;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        mgmt = new LocalManagementContextForTests();
+        exec = new BasicExecutionContext(mgmt.getExecutionManager());
+        
+        destFile = Os.newTempFile(getClass(), "commoncommands-test-dest.txt");
+        
+        sourceNonExistantFile = new File("/this/does/not/exist/ERQBETJJIG1234");
+        sourceNonExistantFileUrl = sourceNonExistantFile.toURI().toString();
+        
+        sourceFile1 = Os.newTempFile(getClass(), "commoncommands-test.txt");
+        sourceFileUrl1 = sourceFile1.toURI().toString();
+        Files.write("mysource1".getBytes(), sourceFile1);
+        
+        sourceFile2 = Os.newTempFile(getClass(), "commoncommands-test2.txt");
+        sourceFileUrl2 = sourceFile2.toURI().toString();
+        Files.write("mysource2".getBytes(), sourceFile2);
+
+        localRepoEntityVersionPath = JavaClassNames.simpleClassName(this)+"-test-dest-"+Identifiers.makeRandomId(8);
+        localRepoBasePath = new File(format("%s/.brooklyn/repository", System.getProperty("user.home")));
+        localRepoEntityBasePath = new File(localRepoBasePath, localRepoEntityVersionPath);
+        localRepoEntityFile = new File(localRepoEntityBasePath, localRepoFilename);
+        localRepoEntityBasePath.mkdirs();
+        Files.write("mylocal1".getBytes(), localRepoEntityFile);
+
+        loc = mgmt.getLocationManager().createLocation(LocalhostMachineProvisioningLocation.spec()).obtain();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (sourceFile1 != null) sourceFile1.delete();
+        if (sourceFile2 != null) sourceFile2.delete();
+        if (destFile != null) destFile.delete();
+        if (localRepoEntityFile != null) localRepoEntityFile.delete();
+        if (localRepoEntityBasePath != null) FileUtils.deleteDirectory(localRepoEntityBasePath);
+        if (loc != null) loc.close();
+        if (mgmt != null) Entities.destroyAll(mgmt);
+    }
+    
+    @Test(groups="Integration")
+    public void testSudo() throws Exception {
+        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+        ByteArrayOutputStream errStream = new ByteArrayOutputStream();
+        String cmd = sudo("whoami");
+        int exitcode = loc.execCommands(ImmutableMap.of("out", outStream, "err", errStream), "test", ImmutableList.of(cmd));
+        String outstr = new String(outStream.toByteArray());
+        String errstr = new String(errStream.toByteArray());
+        
+        assertEquals(exitcode, 0, "out="+outstr+"; err="+errstr);
+        assertTrue(outstr.contains("root"), "out="+outstr+"; err="+errstr);
+    }
+    
+    public void testDownloadUrl() throws Exception {
+        List<String> cmds = BashCommands.commandsToDownloadUrlsAs(
+                ImmutableList.of(sourceFileUrl1), 
+                destFile.getAbsolutePath());
+        int exitcode = loc.execCommands("test", cmds);
+        
+        assertEquals(0, exitcode);
+        assertEquals(Files.readLines(destFile, Charsets.UTF_8), ImmutableList.of("mysource1"));
+    }
+    
+    @Test(groups="Integration")
+    public void testDownloadFirstSuccessfulFile() throws Exception {
+        List<String> cmds = BashCommands.commandsToDownloadUrlsAs(
+                ImmutableList.of(sourceNonExistantFileUrl, sourceFileUrl1, sourceFileUrl2), 
+                destFile.getAbsolutePath());
+        int exitcode = loc.execCommands("test", cmds);
+        
+        assertEquals(0, exitcode);
+        assertEquals(Files.readLines(destFile, Charsets.UTF_8), ImmutableList.of("mysource1"));
+    }
+    
+    @Test(groups="Integration")
+    public void testDownloadToStdout() throws Exception {
+        ProcessTaskWrapper<String> t = SshTasks.newSshExecTaskFactory(loc, 
+                "cd "+destFile.getParentFile().getAbsolutePath(),
+                BashCommands.downloadToStdout(Arrays.asList(sourceFileUrl1))+" | sed s/my/your/")
+            .requiringZeroAndReturningStdout().newTask();
+
+        String result = exec.submit(t).get();
+        assertTrue(result.trim().equals("yoursource1"), "Wrong contents of stdout download: "+result);
+    }
+
+    @Test(groups="Integration")
+    public void testAlternativesWhereFirstSucceeds() throws Exception {
+        ProcessTaskWrapper<Integer> t = SshTasks.newSshExecTaskFactory(loc)
+                .add(BashCommands.alternatives(Arrays.asList("echo first", "exit 88")))
+                .newTask();
+
+        Integer returnCode = exec.submit(t).get();
+        String stdout = t.getStdout();
+        String stderr = t.getStderr();
+        log.info("alternatives for good first command gave: "+returnCode+"; err="+stderr+"; out="+stdout);
+        assertTrue(stdout.contains("first"), "errcode="+returnCode+"; stdout="+stdout+"; stderr="+stderr);
+        assertEquals(returnCode, (Integer)0);
+    }
+
+    @Test(groups="Integration")
+    public void testAlternatives() throws Exception {
+        ProcessTaskWrapper<Integer> t = SshTasks.newSshExecTaskFactory(loc)
+                .add(BashCommands.alternatives(Arrays.asList("asdfj_no_such_command_1", "exit 88")))
+                .newTask();
+
+        Integer returnCode = exec.submit(t).get();
+        log.info("alternatives for bad commands gave: "+returnCode+"; err="+new String(t.getStderr())+"; out="+new String(t.getStdout()));
+        assertEquals(returnCode, (Integer)88);
+    }
+
+    @Test(groups="Integration")
+    public void testRequireTestHandlesFailure() throws Exception {
+        ProcessTaskWrapper<?> t = SshTasks.newSshExecTaskFactory(loc)
+            .add(BashCommands.requireTest("-f "+sourceNonExistantFile.getPath(),
+                    "The requested file does not exist")).newTask();
+
+        exec.submit(t).get();
+        assertNotEquals(t.getExitCode(), (Integer)0);
+        assertTrue(t.getStderr().contains("The requested file"), "Expected message in: "+t.getStderr());
+        assertTrue(t.getStdout().contains("The requested file"), "Expected message in: "+t.getStdout());
+    }
+
+    @Test(groups="Integration")
+    public void testRequireTestHandlesSuccess() throws Exception {
+        ProcessTaskWrapper<?> t = SshTasks.newSshExecTaskFactory(loc)
+            .add(BashCommands.requireTest("-f "+sourceFile1.getPath(),
+                    "The requested file does not exist")).newTask();
+
+        exec.submit(t).get();
+        assertEquals(t.getExitCode(), (Integer)0);
+        assertTrue(t.getStderr().equals(""), "Expected no stderr messages, but got: "+t.getStderr());
+    }
+
+    @Test(groups="Integration")
+    public void testRequireFileHandlesFailure() throws Exception {
+        ProcessTaskWrapper<?> t = SshTasks.newSshExecTaskFactory(loc)
+            .add(BashCommands.requireFile(sourceNonExistantFile.getPath())).newTask();
+
+        exec.submit(t).get();
+        assertNotEquals(t.getExitCode(), (Integer)0);
+        assertTrue(t.getStderr().contains("required file"), "Expected message in: "+t.getStderr());
+        assertTrue(t.getStderr().contains(sourceNonExistantFile.getPath()), "Expected message in: "+t.getStderr());
+        assertTrue(t.getStdout().contains("required file"), "Expected message in: "+t.getStdout());
+        assertTrue(t.getStdout().contains(sourceNonExistantFile.getPath()), "Expected message in: "+t.getStdout());
+    }
+
+    @Test(groups="Integration")
+    public void testRequireFileHandlesSuccess() throws Exception {
+        ProcessTaskWrapper<?> t = SshTasks.newSshExecTaskFactory(loc)
+            .add(BashCommands.requireFile(sourceFile1.getPath())).newTask();
+
+        exec.submit(t).get();
+        assertEquals(t.getExitCode(), (Integer)0);
+        assertTrue(t.getStderr().equals(""), "Expected no stderr messages, but got: "+t.getStderr());
+    }
+
+    @Test(groups="Integration")
+    public void testRequireFailureExitsImmediately() throws Exception {
+        ProcessTaskWrapper<?> t = SshTasks.newSshExecTaskFactory(loc)
+            .add(BashCommands.requireTest("-f "+sourceNonExistantFile.getPath(),
+                    "The requested file does not exist"))
+            .add("echo shouldnae come here").newTask();
+
+        exec.submit(t).get();
+        assertNotEquals(t.getExitCode(), (Integer)0);
+        assertTrue(t.getStderr().contains("The requested file"), "Expected message in: "+t.getStderr());
+        assertTrue(t.getStdout().contains("The requested file"), "Expected message in: "+t.getStdout());
+        Assert.assertFalse(t.getStdout().contains("shouldnae"), "Expected message in: "+t.getStdout());
+    }
+
+    @Test(groups="Integration")
+    public void testPipeMultiline() throws Exception {
+        String output = execRequiringZeroAndReturningStdout(loc,
+                BashCommands.pipeTextTo("hello world\n"+"and goodbye\n", "wc")).get();
+
+        assertEquals(Strings.replaceAllRegex(output, "\\s+", " ").trim(), "3 4 25");
+    }
+
+    @Test(groups="Integration")
+    public void testWaitForFileContentsWhenAbortingOnFail() throws Exception {
+        String fileContent = "mycontents";
+        String cmd = BashCommands.waitForFileContents(destFile.getAbsolutePath(), fileContent, Duration.ONE_SECOND, true);
+
+        int exitcode = loc.execCommands("test", ImmutableList.of(cmd));
+        assertEquals(exitcode, 1);
+        
+        Files.write(fileContent, destFile, Charsets.UTF_8);
+        int exitcode2 = loc.execCommands("test", ImmutableList.of(cmd));
+        assertEquals(exitcode2, 0);
+    }
+
+    @Test(groups="Integration")
+    public void testWaitForFileContentsWhenNotAbortingOnFail() throws Exception {
+        String fileContent = "mycontents";
+        String cmd = BashCommands.waitForFileContents(destFile.getAbsolutePath(), fileContent, Duration.ONE_SECOND, false);
+
+        String output = execRequiringZeroAndReturningStdout(loc, cmd).get();
+        assertTrue(output.contains("Couldn't find"), "output="+output);
+
+        Files.write(fileContent, destFile, Charsets.UTF_8);
+        String output2 = execRequiringZeroAndReturningStdout(loc, cmd).get();
+        assertFalse(output2.contains("Couldn't find"), "output="+output2);
+    }
+    
+    @Test(groups="Integration")
+    public void testWaitForFileContentsWhenContentsAppearAfterStart() throws Exception {
+        String fileContent = "mycontents";
+
+        String cmd = BashCommands.waitForFileContents(destFile.getAbsolutePath(), fileContent, Duration.THIRTY_SECONDS, false);
+        ProcessTaskWrapper<String> t = execRequiringZeroAndReturningStdout(loc, cmd);
+        exec.submit(t);
+        
+        // sleep for long enough to ensure the ssh command is definitely executing
+        Thread.sleep(5*1000);
+        assertFalse(t.isDone());
+        
+        Files.write(fileContent, destFile, Charsets.UTF_8);
+        String output = t.get();
+        assertFalse(output.contains("Couldn't find"), "output="+output);
+    }
+    
+    @Test(groups="Integration", dependsOnMethods="testSudo")
+    public void testWaitForPortFreeWhenAbortingOnTimeout() throws Exception {
+        ServerSocket serverSocket = openServerSocket();
+        try {
+            int port = serverSocket.getLocalPort();
+            String cmd = BashCommands.waitForPortFree(port, Duration.ONE_SECOND, true);
+    
+            int exitcode = loc.execCommands("test", ImmutableList.of(cmd));
+            assertEquals(exitcode, 1);
+            
+            serverSocket.close();
+            assertTrue(Networking.isPortAvailable(port));
+            int exitcode2 = loc.execCommands("test", ImmutableList.of(cmd));
+            assertEquals(exitcode2, 0);
+        } finally {
+            serverSocket.close();
+        }
+    }
+
+    @Test(groups="Integration", dependsOnMethods="testSudo")
+    public void testWaitForPortFreeWhenNotAbortingOnTimeout() throws Exception {
+        ServerSocket serverSocket = openServerSocket();
+        try {
+            int port = serverSocket.getLocalPort();
+            String cmd = BashCommands.waitForPortFree(port, Duration.ONE_SECOND, false);
+    
+            String output = execRequiringZeroAndReturningStdout(loc, cmd).get();
+            assertTrue(output.contains(port+" still in use"), "output="+output);
+    
+            serverSocket.close();
+            assertTrue(Networking.isPortAvailable(port));
+            String output2 = execRequiringZeroAndReturningStdout(loc, cmd).get();
+            assertFalse(output2.contains("still in use"), "output="+output2);
+        } finally {
+            serverSocket.close();
+        }
+    }
+    
+    @Test(groups="Integration", dependsOnMethods="testSudo")
+    public void testWaitForPortFreeWhenFreedAfterStart() throws Exception {
+        ServerSocket serverSocket = openServerSocket();
+        try {
+            int port = serverSocket.getLocalPort();
+    
+            String cmd = BashCommands.waitForPortFree(port, Duration.THIRTY_SECONDS, false);
+            ProcessTaskWrapper<String> t = execRequiringZeroAndReturningStdout(loc, cmd);
+            exec.submit(t);
+            
+            // sleep for long enough to ensure the ssh command is definitely executing
+            Thread.sleep(5*1000);
+            assertFalse(t.isDone());
+            
+            serverSocket.close();
+            assertTrue(Networking.isPortAvailable(port));
+            String output = t.get();
+            assertFalse(output.contains("still in use"), "output="+output);
+        } finally {
+            serverSocket.close();
+        }
+    }
+
+    
+    // Disabled by default because of risk of overriding /etc/hosts in really bad way if doesn't work properly!
+    // As a manual visual inspection test, consider first manually creating /etc/hostname and /etc/sysconfig/network
+    // so that it looks like debian+ubuntu / CentOS/RHEL.
+    @Test(groups={"Integration"}, enabled=false)
+    public void testSetHostnameUnqualified() throws Exception {
+        runSetHostname("br-"+Identifiers.makeRandomId(8).toLowerCase(), null, false);
+    }
+
+    @Test(groups={"Integration"}, enabled=false)
+    public void testSetHostnameQualified() throws Exception {
+        runSetHostname("br-"+Identifiers.makeRandomId(8).toLowerCase()+".brooklyn.incubator.apache.org", null, false);
+    }
+
+    @Test(groups={"Integration"}, enabled=false)
+    public void testSetHostnameNullDomain() throws Exception {
+        runSetHostname("br-"+Identifiers.makeRandomId(8).toLowerCase(), null, true);
+    }
+
+    @Test(groups={"Integration"}, enabled=false)
+    public void testSetHostnameNonNullDomain() throws Exception {
+        runSetHostname("br-"+Identifiers.makeRandomId(8).toLowerCase(), "brooklyn.incubator.apache.org", true);
+    }
+
+    protected void runSetHostname(String newHostname, String newDomain, boolean includeDomain) throws Exception {
+        String fqdn = (includeDomain && Strings.isNonBlank(newDomain)) ? newHostname + "." + newDomain : newHostname;
+        
+        LocalManagementContextForTests mgmt = new LocalManagementContextForTests();
+        SshMachineLocation loc = mgmt.getLocationManager().createLocation(LocalhostMachineProvisioningLocation.spec()).obtain();
+
+        execRequiringZeroAndReturningStdout(loc, sudo("cp /etc/hosts /etc/hosts-orig-testSetHostname")).get();
+        execRequiringZeroAndReturningStdout(loc, BashCommands.ifFileExistsElse0("/etc/hostname", sudo("cp /etc/hostname /etc/hostname-orig-testSetHostname"))).get();
+        execRequiringZeroAndReturningStdout(loc, BashCommands.ifFileExistsElse0("/etc/sysconfig/network", sudo("cp /etc/sysconfig/network /etc/sysconfig/network-orig-testSetHostname"))).get();
+        
+        String origHostname = getHostnameNoArgs(loc);
+        assertTrue(Strings.isNonBlank(origHostname));
+        
+        try {
+            List<String> cmd = (includeDomain) ? BashCommands.setHostname(newHostname, newDomain) : BashCommands.setHostname(newHostname);
+            execRequiringZeroAndReturningStdout(loc, cmd).get();
+
+            String actualHostnameUnqualified = getHostnameUnqualified(loc);
+            String actualHostnameFullyQualified = getHostnameFullyQualified(loc);
+
+            // TODO On OS X at least, we aren't actually setting the domain name; we're just letting 
+            //      the user pass in what the domain name is. We do add this properly to /etc/hosts
+            //      (e.g. first line is "127.0.0.1 br-g4x5wgx8.brooklyn.incubator.apache.org br-g4x5wgx8 localhost")
+            //      but subsequent calls to `hostname -f` returns the unqualified. Similarly, `domainname` 
+            //      returns blank. Therefore we can't assert that it equals our expected val (because we just made  
+            //      it up - "brooklyn.incubator.apache.org").
+            //      assertEquals(actualHostnameFullyQualified, fqdn);
+            assertEquals(actualHostnameUnqualified, Strings.getFragmentBetween(newHostname, null, "."));
+            execRequiringZeroAndReturningStdout(loc, "ping -c1 -n -q "+actualHostnameUnqualified).get();
+            execRequiringZeroAndReturningStdout(loc, "ping -c1 -n -q "+actualHostnameFullyQualified).get();
+            
+            String result = execRequiringZeroAndReturningStdout(loc, "grep -n "+fqdn+" /etc/hosts").get();
+            assertTrue(result.contains("localhost"), "line="+result);
+            log.info("result="+result);
+            
+        } finally {
+            execRequiringZeroAndReturningStdout(loc, sudo("cp /etc/hosts-orig-testSetHostname /etc/hosts")).get();
+            execRequiringZeroAndReturningStdout(loc, BashCommands.ifFileExistsElse0("/etc/hostname-orig-testSetHostname", sudo("cp /etc/hostname-orig-testSetHostname /etc/hostname"))).get();
+            execRequiringZeroAndReturningStdout(loc, BashCommands.ifFileExistsElse0("/etc/sysconfig/network-orig-testSetHostname", sudo("cp /etc/sysconfig/network-orig-testSetHostname /etc/sysconfig/network"))).get();
+            execRequiringZeroAndReturningStdout(loc, sudo("hostname "+origHostname)).get();
+        }
+    }
+
+    // Marked disabled because not safe to run on your normal machine! It modifies /etc/hosts, which is dangerous if things go wrong!
+    @Test(groups={"Integration"}, enabled=false)
+    public void testModifyEtcHosts() throws Exception {
+        LocalManagementContextForTests mgmt = new LocalManagementContextForTests();
+        SshMachineLocation loc = mgmt.getLocationManager().createLocation(LocalhostMachineProvisioningLocation.spec()).obtain();
+
+        execRequiringZeroAndReturningStdout(loc, sudo("cp /etc/hosts /etc/hosts-orig-testModifyEtcHosts")).get();
+        int numLinesOrig = Integer.parseInt(execRequiringZeroAndReturningStdout(loc, "wc -l /etc/hosts").get().trim().split("\\s")[0]);
+        
+        try {
+            String cmd = BashCommands.prependToEtcHosts("1.2.3.4", "myhostnamefor1234.at.start", "myhostnamefor1234b");
+            execRequiringZeroAndReturningStdout(loc, cmd).get();
+            
+            String cmd2 = BashCommands.appendToEtcHosts("5.6.7.8", "myhostnamefor5678.at.end", "myhostnamefor5678");
+            execRequiringZeroAndReturningStdout(loc, cmd2).get();
+            
+            String grepFirst = execRequiringZeroAndReturningStdout(loc, "grep -n myhostnamefor1234 /etc/hosts").get();
+            String grepLast = execRequiringZeroAndReturningStdout(loc, "grep -n myhostnamefor5678 /etc/hosts").get();
+            int numLinesAfter = Integer.parseInt(execRequiringZeroAndReturningStdout(loc, "wc -l /etc/hosts").get().trim().split("\\s")[0]);
+            log.info("result: numLinesBefore="+numLinesOrig+"; numLinesAfter="+numLinesAfter+"; first="+grepFirst+"; last="+grepLast);
+            
+            assertTrue(grepFirst.startsWith("1:") && grepFirst.contains("1.2.3.4 myhostnamefor1234.at.start myhostnamefor1234"), "first="+grepFirst);
+            assertTrue(grepLast.startsWith((numLinesOrig+2)+":") && grepLast.contains("5.6.7.8 myhostnamefor5678.at.end myhostnamefor5678"), "last="+grepLast);
+            assertEquals(numLinesOrig + 2, numLinesAfter, "lines orig="+numLinesOrig+", after="+numLinesAfter);
+        } finally {
+            execRequiringZeroAndReturningStdout(loc, sudo("cp /etc/hosts-orig-testModifyEtcHosts /etc/hosts")).get();
+        }
+    }
+    
+    private String getHostnameNoArgs(SshMachineLocation machine) {
+        String hostnameStdout = execRequiringZeroAndReturningStdout(machine, "echo FOREMARKER; hostname; echo AFTMARKER").get();
+        return Strings.getFragmentBetween(hostnameStdout, "FOREMARKER", "AFTMARKER").trim();
+    }
+
+    private String getHostnameUnqualified(SshMachineLocation machine) {
+        String hostnameStdout = execRequiringZeroAndReturningStdout(machine, "echo FOREMARKER; hostname -s 2> /dev/null || hostname; echo AFTMARKER").get();
+        return Strings.getFragmentBetween(hostnameStdout, "FOREMARKER", "AFTMARKER").trim();
+    }
+
+    private String getHostnameFullyQualified(SshMachineLocation machine) {
+        String hostnameStdout = execRequiringZeroAndReturningStdout(machine, "echo FOREMARKER; hostname --fqdn 2> /dev/null || hostname -f; echo AFTMARKER").get();
+        return Strings.getFragmentBetween(hostnameStdout, "FOREMARKER", "AFTMARKER").trim();
+    }
+
+    private ProcessTaskWrapper<String> execRequiringZeroAndReturningStdout(SshMachineLocation loc, Collection<String> cmds) {
+        return execRequiringZeroAndReturningStdout(loc, cmds.toArray(new String[cmds.size()]));
+    }
+    
+    private ProcessTaskWrapper<String> execRequiringZeroAndReturningStdout(SshMachineLocation loc, String... cmds) {
+        ProcessTaskWrapper<String> t = SshTasks.newSshExecTaskFactory(loc, cmds)
+                .requiringZeroAndReturningStdout().newTask();
+        exec.submit(t);
+        return t;
+    }
+
+    private ServerSocket openServerSocket() {
+        int lowerBound = 40000;
+        int upperBound = 40100;
+        for (int i = lowerBound; i < upperBound; i++) {
+            try {
+                return new ServerSocket(i);
+            } catch (IOException e) {
+                // try next number
+            }
+        }
+        throw new IllegalStateException("No ports available in range "+lowerBound+" to "+upperBound);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTaskExecutionPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTaskExecutionPerformanceTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTaskExecutionPerformanceTest.java
new file mode 100644
index 0000000..71d2586
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTaskExecutionPerformanceTest.java
@@ -0,0 +1,209 @@
+/*
+ * 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.util.task;
+
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.apache.brooklyn.core.util.task.ScheduledTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Callables;
+
+/**
+ * Test the operation of the {@link BasicTask} class.
+ *
+ * TODO clarify test purpose
+ */
+public class BasicTaskExecutionPerformanceTest {
+    private static final Logger log = LoggerFactory.getLogger(BasicTaskExecutionPerformanceTest.class);
+ 
+    private static final int TIMEOUT_MS = 10*1000;
+    
+    private BasicExecutionManager em;
+
+    public static final int MAX_OVERHEAD_MS = 1500; // was 750ms but saw 1.3s on buildhive
+    public static final int EARLY_RETURN_GRACE = 25; // saw 13ms early return on jenkins!
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        em = new BasicExecutionManager("mycontext");
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (em != null) em.shutdownNow();
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testScheduledTaskExecutedAfterDelay() throws Exception {
+        int delay = 100;
+        final CountDownLatch latch = new CountDownLatch(1);
+        
+        Callable<Task<?>> taskFactory = new Callable<Task<?>>() {
+            @Override public Task<?> call() {
+                return new BasicTask<Void>(new Runnable() {
+                    @Override public void run() {
+                        latch.countDown();
+                    }});
+            }};
+        ScheduledTask t = new ScheduledTask(taskFactory).delay(delay);
+
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        em.submit(t);
+        
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        long actualDelay = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+        
+        assertTrue(actualDelay > (delay-EARLY_RETURN_GRACE), "actualDelay="+actualDelay+"; delay="+delay);
+        assertTrue(actualDelay < (delay+MAX_OVERHEAD_MS), "actualDelay="+actualDelay+"; delay="+delay);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testScheduledTaskExecutedAtRegularPeriod() throws Exception {
+        final int period = 100;
+        final int numTimestamps = 4;
+        final CountDownLatch latch = new CountDownLatch(1);
+        final List<Long> timestamps = Collections.synchronizedList(Lists.<Long>newArrayList());
+        final Stopwatch stopwatch = Stopwatch.createStarted();
+        
+        Callable<Task<?>> taskFactory = new Callable<Task<?>>() {
+            @Override public Task<?> call() {
+                return new BasicTask<Void>(new Runnable() {
+                    @Override public void run() {
+                        timestamps.add(stopwatch.elapsed(TimeUnit.MILLISECONDS));
+                        if (timestamps.size() >= numTimestamps) latch.countDown();
+                    }});
+            }};
+        ScheduledTask t = new ScheduledTask(taskFactory).delay(1).period(period);
+        em.submit(t);
+        
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        
+        synchronized (timestamps) {
+            long prev = timestamps.get(0);
+            for (long timestamp : timestamps.subList(1, timestamps.size())) {
+                assertTrue(timestamp > prev+period-EARLY_RETURN_GRACE, "timestamps="+timestamps);
+                assertTrue(timestamp < prev+period+MAX_OVERHEAD_MS, "timestamps="+timestamps);
+                prev = timestamp;
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testCanCancelScheduledTask() throws Exception {
+        final int period = 1;
+        final long checkPeriod = 250;
+        final List<Long> timestamps = Collections.synchronizedList(Lists.<Long>newArrayList());
+        
+        Callable<Task<?>> taskFactory = new Callable<Task<?>>() {
+            @Override public Task<?> call() {
+                return new BasicTask<Void>(new Runnable() {
+                    @Override public void run() {
+                        timestamps.add(System.currentTimeMillis());
+                    }});
+            }};
+        ScheduledTask t = new ScheduledTask(taskFactory).period(period);
+        em.submit(t);
+
+        t.cancel();
+        long cancelTime = System.currentTimeMillis();
+        int countImmediatelyAfterCancel = timestamps.size();
+        Thread.sleep(checkPeriod);
+        int countWellAfterCancel = timestamps.size();
+
+        // should have at most 1 more execution after cancel
+        log.info("testCanCancelScheduledTask saw "+countImmediatelyAfterCancel+" then cancel then "+countWellAfterCancel+" total");                
+        assertTrue(countWellAfterCancel - countImmediatelyAfterCancel <= 2, "timestamps="+timestamps+"; cancelTime="+cancelTime);
+    }
+
+    // Previously, when we used a CopyOnWriteArraySet, performance for submitting new tasks was
+    // terrible, and it degraded significantly as the number of previously executed tasks increased
+    // (e.g. 9s for first 1000; 26s for next 1000; 42s for next 1000).
+    @Test
+    public void testExecutionManagerPerformance() throws Exception {
+        // Was fixed at 1000 tasks, but was running out of virtual memory due to excessive thread creation
+        // on machines which were not able to execute the threads quickly.
+        final int NUM_TASKS = Math.min(500 * Runtime.getRuntime().availableProcessors(), 1000);
+        final int NUM_TIMES = 10;
+        final int MAX_ACCEPTABLE_TIME = 7500; // saw 5601ms on buildhive
+        
+        long tWarmup = execTasksAndWaitForDone(NUM_TASKS, ImmutableList.of("A"));
+        
+        List<Long> times = Lists.newArrayList();
+        for (int i = 1; i <= NUM_TIMES; i++) {
+            times.add(execTasksAndWaitForDone(NUM_TASKS, ImmutableList.of("A")));
+        }
+        
+        Long toobig = Iterables.find(
+                times, 
+                new Predicate<Long>() {
+                    public boolean apply(Long input) {
+                        return input > MAX_ACCEPTABLE_TIME;
+                    }},
+                null);
+        assertNull(toobig, "warmup="+tWarmup+"; times="+times);
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private long execTasksAndWaitForDone(int numTasks, List<?> tags) throws Exception {
+        List<Task<?>> tasks = Lists.newArrayList();
+        long startTimestamp = System.currentTimeMillis();
+        for (int i = 1; i < numTasks; i++) {
+            Task<?> t = new BasicTask(Callables.returning(null)); // no-op
+            em.submit(MutableMap.of("tags", tags), t);
+            tasks.add(t);
+        }
+        long submittedTimestamp = System.currentTimeMillis();
+
+        for (Task t : tasks) {
+            t.get();
+        }
+        long endTimestamp = System.currentTimeMillis();
+        long submitTime = submittedTimestamp - startTimestamp;
+        long totalTime = endTimestamp - startTimestamp;
+        
+        log.info("Executed {} tasks; {}ms total; {}ms to submit", new Object[] {numTasks, totalTime, submitTime});
+
+        return totalTime;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTaskExecutionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTaskExecutionTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTaskExecutionTest.java
new file mode 100644
index 0000000..c730738
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTaskExecutionTest.java
@@ -0,0 +1,462 @@
+/*
+ * 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.util.task;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Callables;
+
+/**
+ * Test the operation of the {@link BasicTask} class.
+ *
+ * TODO clarify test purpose
+ */
+public class BasicTaskExecutionTest {
+    private static final Logger log = LoggerFactory.getLogger(BasicTaskExecutionTest.class);
+ 
+    private static final int TIMEOUT_MS = 10*1000;
+    
+    private BasicExecutionManager em;
+    private Map<Object, Object> data;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() {
+        em = new BasicExecutionManager("mycontext");
+        data = Collections.synchronizedMap(new HashMap<Object, Object>());
+        data.clear();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (em != null) em.shutdownNow();
+        if (data != null) data.clear();
+    }
+    
+    @Test
+    public void runSimpleBasicTask() throws Exception {
+        BasicTask<Object> t = new BasicTask<Object>(newPutCallable(1, "b"));
+        data.put(1, "a");
+        Task<Object> t2 = em.submit(MutableMap.of("tag", "A"), t);
+        assertEquals("a", t.get());
+        assertEquals("a", t2.get());
+        assertEquals("b", data.get(1));
+    }
+    
+    @Test
+    public void runSimpleRunnable() throws Exception {
+        data.put(1, "a");
+        Task<?> t = em.submit(MutableMap.of("tag", "A"), newPutRunnable(1, "b"));
+        assertEquals(null, t.get());
+        assertEquals("b", data.get(1));
+    }
+
+    @Test
+    public void runSimpleCallable() throws Exception {
+        data.put(1, "a");
+        Task<?> t = em.submit(MutableMap.of("tag", "A"), newPutCallable(1, "b"));
+        assertEquals("a", t.get());
+        assertEquals("b", data.get(1));
+    }
+
+    @Test
+    public void runBasicTaskWithWaits() throws Exception {
+        final CountDownLatch signalStarted = new CountDownLatch(1);
+        final CountDownLatch allowCompletion = new CountDownLatch(1);
+        final BasicTask<Object> t = new BasicTask<Object>(new Callable<Object>() {
+            public Object call() throws Exception {
+                Object result = data.put(1, "b");
+                signalStarted.countDown();
+                assertTrue(allowCompletion.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+                return result;
+            }});
+        data.put(1, "a");
+
+        Task<?> t2 = em.submit(MutableMap.of("tag", "A"), t);
+        assertEquals(t, t2);
+        assertFalse(t.isDone());
+        
+        assertTrue(signalStarted.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals("b", data.get(1));
+        assertFalse(t.isDone());
+        
+        log.debug("runBasicTaskWithWaits, BasicTask status: {}", t.getStatusDetail(false));
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                String status = t.getStatusDetail(false);
+                assertTrue(status != null && status.toLowerCase().contains("waiting"), "status="+status);
+            }});
+        
+        allowCompletion.countDown();
+        assertEquals("a", t.get());
+    }
+
+    @Test
+    public void runMultipleBasicTasks() throws Exception {
+        data.put(1, 1);
+        BasicExecutionManager em = new BasicExecutionManager("mycontext");
+        for (int i = 0; i < 2; i++) {
+            em.submit(MutableMap.of("tag", "A"), new BasicTask<Integer>(newIncrementCallable(1)));
+            em.submit(MutableMap.of("tag", "B"), new BasicTask<Integer>(newIncrementCallable((1))));
+        }
+        int total = 0;
+        for (Object tag : em.getTaskTags()) {
+                log.debug("tag {}", tag);
+                for (Task<?> task : em.getTasksWithTag(tag)) {
+                    log.debug("BasicTask {}, has {}", task, task.get());
+                    total += (Integer)task.get();
+                }
+            }
+        assertEquals(10, total);
+        //now that all have completed:
+        assertEquals(5, data.get(1));
+    }
+
+    @Test
+    public void runMultipleBasicTasksMultipleTags() throws Exception {
+        data.put(1, 1);
+        Collection<Task<Integer>> tasks = Lists.newArrayList();
+        tasks.add(em.submit(MutableMap.of("tag", "A"), new BasicTask<Integer>(newIncrementCallable(1))));
+        tasks.add(em.submit(MutableMap.of("tags", ImmutableList.of("A","B")), new BasicTask<Integer>(newIncrementCallable(1))));
+        tasks.add(em.submit(MutableMap.of("tags", ImmutableList.of("B","C")), new BasicTask<Integer>(newIncrementCallable(1))));
+        tasks.add(em.submit(MutableMap.of("tags", ImmutableList.of("D")), new BasicTask<Integer>(newIncrementCallable(1))));
+        int total = 0;
+
+        for (Task<Integer> t : tasks) {
+            log.debug("BasicTask {}, has {}", t, t.get());
+            total += t.get();
+            }
+        assertEquals(10, total);
+ 
+        //now that all have completed:
+        assertEquals(data.get(1), 5);
+        assertEquals(em.getTasksWithTag("A").size(), 2);
+        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A")).size(), 2);
+        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A")).size(), 2);
+
+        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A", "B")).size(), 3);
+        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A", "B")).size(), 1);
+        assertEquals(em.getTasksWithAllTags(ImmutableList.of("B", "C")).size(), 1);
+        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A", "D")).size(), 3);
+    }
+
+    @Test
+    public void testGetTaskById() throws Exception {
+        Task<?> t = new BasicTask<Void>(newNoop());
+        em.submit(MutableMap.of("tag", "A"), t);
+        assertEquals(em.getTask(t.getId()), t);
+    }
+
+    @Test
+    public void testRetrievingTasksWithTagsReturnsExpectedTask() throws Exception {
+        Task<?> t = new BasicTask<Void>(newNoop());
+        em.submit(MutableMap.of("tag", "A"), t);
+        t.get();
+
+        assertEquals(em.getTasksWithTag("A"), ImmutableList.of(t));
+        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A")), ImmutableList.of(t));
+        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A", "B")), ImmutableList.of(t));
+        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A")), ImmutableList.of(t));
+    }
+
+    @Test
+    public void testRetrievingTasksWithTagsExcludesNonMatchingTasks() throws Exception {
+        Task<?> t = new BasicTask<Void>(newNoop());
+        em.submit(MutableMap.of("tag", "A"), t);
+        t.get();
+
+        assertEquals(em.getTasksWithTag("B"), ImmutableSet.of());
+        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("B")), ImmutableSet.of());
+        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A", "B")), ImmutableSet.of());
+    }
+    
+    @Test
+    public void testRetrievingTasksWithMultipleTags() throws Exception {
+        Task<?> t = new BasicTask<Void>(newNoop());
+        em.submit(MutableMap.of("tags", ImmutableList.of("A", "B")), t);
+        t.get();
+
+        assertEquals(em.getTasksWithTag("A"), ImmutableList.of(t));
+        assertEquals(em.getTasksWithTag("B"), ImmutableList.of(t));
+        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A")), ImmutableList.of(t));
+        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("B")), ImmutableList.of(t));
+        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A", "B")), ImmutableList.of(t));
+        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A", "B")), ImmutableList.of(t));
+        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A")), ImmutableList.of(t));
+        assertEquals(em.getTasksWithAllTags(ImmutableList.of("B")), ImmutableList.of(t));
+    }
+
+    // ENGR-1796: if nothing matched first tag, then returned whatever matched second tag!
+    @Test
+    public void testRetrievingTasksWithAllTagsWhenFirstNotMatched() throws Exception {
+        Task<?> t = new BasicTask<Void>(newNoop());
+        em.submit(MutableMap.of("tags", ImmutableList.of("A")), t);
+        t.get();
+
+        assertEquals(em.getTasksWithAllTags(ImmutableList.of("not_there","A")), ImmutableSet.of());
+    }
+    
+    @Test
+    public void testRetrievedTasksIncludesTasksInProgress() throws Exception {
+        final CountDownLatch runningLatch = new CountDownLatch(1);
+        final CountDownLatch finishLatch = new CountDownLatch(1);
+        Task<Void> t = new BasicTask<Void>(new Callable<Void>() {
+            public Void call() throws Exception {
+                runningLatch.countDown();
+                finishLatch.await();
+                return null;
+            }});
+        em.submit(MutableMap.of("tags", ImmutableList.of("A")), t);
+        
+        try {
+            runningLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+    
+            assertEquals(em.getTasksWithTag("A"), ImmutableList.of(t));
+        } finally {
+            finishLatch.countDown();
+        }
+    }
+    
+    @Test
+    public void cancelBeforeRun() throws Exception {
+        final CountDownLatch blockForever = new CountDownLatch(1);
+        
+        BasicTask<Integer> t = new BasicTask<Integer>(new Callable<Integer>() {
+            public Integer call() throws Exception {
+                blockForever.await(); return 42;
+            }});
+        t.cancel(true);
+        assertTrue(t.isCancelled());
+        assertTrue(t.isDone());
+        assertTrue(t.isError());
+        em.submit(MutableMap.of("tag", "A"), t);
+        try {
+            t.get();
+            fail("get should have failed due to cancel");
+        } catch (CancellationException e) {
+            // expected
+        }
+        assertTrue(t.isCancelled());
+        assertTrue(t.isDone());
+        assertTrue(t.isError());
+        
+        log.debug("cancelBeforeRun status: {}", t.getStatusDetail(false));
+        assertTrue(t.getStatusDetail(false).toLowerCase().contains("cancel"));
+    }
+
+    @Test
+    public void cancelDuringRun() throws Exception {
+        final CountDownLatch signalStarted = new CountDownLatch(1);
+        final CountDownLatch blockForever = new CountDownLatch(1);
+        
+        BasicTask<Integer> t = new BasicTask<Integer>(new Callable<Integer>() {
+            public Integer call() throws Exception {
+                synchronized (data) {
+                    signalStarted.countDown();
+                    blockForever.await();
+                }
+                return 42;
+            }});
+        em.submit(MutableMap.of("tag", "A"), t);
+        assertFalse(t.isCancelled());
+        assertFalse(t.isDone());
+        assertFalse(t.isError());
+        
+        assertTrue(signalStarted.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        t.cancel(true);
+        
+        assertTrue(t.isCancelled());
+        assertTrue(t.isError());
+        try {
+            t.get();
+            fail("get should have failed due to cancel");
+        } catch (CancellationException e) {
+            // expected
+        }
+        assertTrue(t.isCancelled());
+        assertTrue(t.isDone());
+        assertTrue(t.isError());
+    }
+    
+    @Test
+    public void cancelAfterRun() throws Exception {
+        BasicTask<Integer> t = new BasicTask<Integer>(Callables.returning(42));
+        em.submit(MutableMap.of("tag", "A"), t);
+
+        assertEquals(t.get(), (Integer)42);
+        t.cancel(true);
+        assertFalse(t.isCancelled());
+        assertFalse(t.isError());
+        assertTrue(t.isDone());
+    }
+    
+    @Test
+    public void errorDuringRun() throws Exception {
+        BasicTask<Void> t = new BasicTask<Void>(new Callable<Void>() {
+            public Void call() throws Exception {
+                throw new IllegalStateException("Simulating failure in errorDuringRun");
+            }});
+        
+        em.submit(MutableMap.of("tag", "A"), t);
+        
+        try {
+            t.get();
+            fail("get should have failed due to error"); 
+        } catch (Exception eo) { 
+            Throwable e = Throwables.getRootCause(eo);
+            assertEquals("Simulating failure in errorDuringRun", e.getMessage());
+        }
+        
+        assertFalse(t.isCancelled());
+        assertTrue(t.isError());
+        assertTrue(t.isDone());
+        
+        log.debug("errorDuringRun status: {}", t.getStatusDetail(false));
+        assertTrue(t.getStatusDetail(false).contains("Simulating failure in errorDuringRun"), "details="+t.getStatusDetail(false));
+    }
+
+    @Test
+    public void fieldsSetForSimpleBasicTask() throws Exception {
+        final CountDownLatch signalStarted = new CountDownLatch(1);
+        final CountDownLatch allowCompletion = new CountDownLatch(1);
+        
+        BasicTask<Integer> t = new BasicTask<Integer>(new Callable<Integer>() {
+            public Integer call() throws Exception {
+                signalStarted.countDown();
+                allowCompletion.await();
+                return 42;
+            }});
+        assertEquals(null, t.getSubmittedByTask());
+        assertEquals(-1, t.submitTimeUtc);
+        assertNull(t.getInternalFuture());
+
+        em.submit(MutableMap.of("tag", "A"), t);
+        assertTrue(signalStarted.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        
+        assertTrue(t.submitTimeUtc > 0);
+        assertTrue(t.startTimeUtc >= t.submitTimeUtc);
+        assertNotNull(t.getInternalFuture());
+        assertEquals(-1, t.endTimeUtc);
+        assertEquals(false, t.isCancelled());
+        
+        allowCompletion.countDown();
+        assertEquals(t.get(), (Integer)42);
+        assertTrue(t.endTimeUtc >= t.startTimeUtc);
+
+        log.debug("BasicTask duration (millis): {}", (t.endTimeUtc - t.submitTimeUtc));
+    }
+
+    @Test
+    public void fieldsSetForBasicTaskSubmittedBasicTask() throws Exception {
+        //submitted BasicTask B is started by A, and waits for A to complete
+        BasicTask<Integer> t = new BasicTask<Integer>(MutableMap.of("displayName", "sample", "description", "some descr"), new Callable<Integer>() {
+            public Integer call() throws Exception {
+                em.submit(MutableMap.of("tag", "B"), new Callable<Integer>() {
+                    public Integer call() throws Exception {
+                        assertEquals(45, em.getTasksWithTag("A").iterator().next().get());
+                        return 46;
+                    }});
+                return 45;
+            }});
+        em.submit(MutableMap.of("tag", "A"), t);
+
+        t.blockUntilEnded();
+ 
+//        assertEquals(em.getAllTasks().size(), 2
+        
+        BasicTask<?> tb = (BasicTask<?>) em.getTasksWithTag("B").iterator().next();
+        assertEquals( 46, tb.get() );
+        assertEquals( t, em.getTasksWithTag("A").iterator().next() );
+        assertNull( t.getSubmittedByTask() );
+        
+        BasicTask<?> submitter = (BasicTask<?>) tb.getSubmittedByTask();
+        assertNotNull(submitter);
+        assertEquals("sample", submitter.displayName);
+        assertEquals("some descr", submitter.description);
+        assertEquals(t, submitter);
+        
+        assertTrue(submitter.submitTimeUtc <= tb.submitTimeUtc);
+        assertTrue(submitter.endTimeUtc <= tb.endTimeUtc);
+        
+        log.debug("BasicTask {} was submitted by {}", tb, submitter);
+    }
+    
+    private Callable<Object> newPutCallable(final Object key, final Object val) {
+        return new Callable<Object>() {
+            public Object call() {
+                return data.put(key, val);
+            }
+        };
+    }
+    
+    private Callable<Integer> newIncrementCallable(final Object key) {
+        return new Callable<Integer>() {
+            public Integer call() {
+                synchronized (data) {
+                    return (Integer) data.put(key, (Integer)data.get(key) + 1);
+                }
+            }
+        };
+    }
+    
+    private Runnable newPutRunnable(final Object key, final Object val) {
+        return new Runnable() {
+            public void run() {
+                data.put(key, val);
+            }
+        };
+    }
+    
+    private Runnable newNoop() {
+        return new Runnable() {
+            public void run() {
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTasksFutureTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTasksFutureTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTasksFutureTest.java
new file mode 100644
index 0000000..020a98c
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/BasicTasksFutureTest.java
@@ -0,0 +1,227 @@
+/*
+ * 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.util.task;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.Tasks;
+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 brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Stopwatch;
+
+public class BasicTasksFutureTest {
+
+    private static final Logger log = LoggerFactory.getLogger(BasicTasksFutureTest.class);
+    
+    private BasicExecutionManager em;
+    private BasicExecutionContext ec;
+    private Map<Object,Object> data;
+    private ExecutorService ex;
+    private Semaphore started;
+    private Semaphore waitInTask;
+    private Semaphore cancelledWhileSleeping;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() {
+        em = new BasicExecutionManager("mycontext");
+        ec = new BasicExecutionContext(em);
+        ex = Executors.newCachedThreadPool();
+        data = Collections.synchronizedMap(new LinkedHashMap<Object,Object>());
+        started = new Semaphore(0);
+        waitInTask = new Semaphore(0);
+        cancelledWhileSleeping = new Semaphore(0);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (em != null) em.shutdownNow();
+        if (ex != null) ex.shutdownNow();
+    }
+
+    @Test
+    public void testBlockAndGetWithTimeoutsAndListenableFuture() throws InterruptedException {
+        Task<String> t = waitForSemaphore(Duration.FIVE_SECONDS, true, "x");
+        
+        Assert.assertFalse(t.blockUntilEnded(Duration.millis(1)));
+        Assert.assertFalse(t.blockUntilEnded(Duration.ZERO));
+        boolean didNotThrow = false;
+        
+        try { t.getUnchecked(Duration.millis(1)); didNotThrow = true; }
+        catch (Exception e) { /* expected */ }
+        Assert.assertFalse(didNotThrow);
+        
+        try { t.getUnchecked(Duration.ZERO); didNotThrow = true; }
+        catch (Exception e) { /* expected */ }
+        Assert.assertFalse(didNotThrow);
+
+        addFutureListener(t, "before");
+        ec.submit(t);
+        
+        Assert.assertFalse(t.blockUntilEnded(Duration.millis(1)));
+        Assert.assertFalse(t.blockUntilEnded(Duration.ZERO));
+        
+        try { t.getUnchecked(Duration.millis(1)); didNotThrow = true; }
+        catch (Exception e) { /* expected */ }
+        Assert.assertFalse(didNotThrow);
+        
+        try { t.getUnchecked(Duration.ZERO); didNotThrow = true; }
+        catch (Exception e) { /* expected */ }
+        Assert.assertFalse(didNotThrow);
+
+        addFutureListener(t, "during");
+            
+        synchronized (data) {
+            // now let it finish
+            waitInTask.release();
+            Assert.assertTrue(t.blockUntilEnded(Duration.TEN_SECONDS));
+
+            Assert.assertEquals(t.getUnchecked(Duration.millis(1)), "x");
+            Assert.assertEquals(t.getUnchecked(Duration.ZERO), "x");
+            
+            Assert.assertNull(data.get("before"));
+            Assert.assertNull(data.get("during"));
+            // can't set the data(above) until we release the lock (in assert call below)
+            assertSoonGetsData("before");
+            assertSoonGetsData("during");
+        }
+
+        // and see that a listener added late also runs
+        synchronized (data) {
+            addFutureListener(t, "after");
+            Assert.assertNull(data.get("after"));
+            assertSoonGetsData("after");
+        }
+    }
+
+    private void addFutureListener(Task<String> t, final String key) {
+        t.addListener(new Runnable() { public void run() {
+            synchronized (data) {
+                log.info("notifying for "+key);
+                data.notifyAll();
+                data.put(key, true);
+            }
+        }}, ex);
+    }
+
+    private void assertSoonGetsData(String key) throws InterruptedException {
+        for (int i=0; i<10; i++) {
+            if (Boolean.TRUE.equals(data.get(key))) {
+                log.info("got data for "+key);
+                return;
+            }
+            data.wait(Duration.ONE_SECOND.toMilliseconds());
+        }
+        Assert.fail("did not get data for '"+key+"' in time");
+    }
+
+    private <T> Task<T> waitForSemaphore(final Duration time, final boolean requireSemaphore, final T result) {
+        return Tasks.<T>builder().body(new Callable<T>() {
+            public T call() { 
+                try {
+                    started.release();
+                    log.info("waiting up to "+time+" to acquire before returning "+result);
+                    if (!waitInTask.tryAcquire(time.toMilliseconds(), TimeUnit.MILLISECONDS)) {
+                        log.info("did not get semaphore");
+                        if (requireSemaphore) Assert.fail("task did not get semaphore");
+                    } else {
+                        log.info("got semaphore");
+                    }
+                } catch (Exception e) {
+                    log.info("cancelled before returning "+result);
+                    cancelledWhileSleeping.release();
+                    throw Exceptions.propagate(e);
+                }
+                log.info("task returning "+result);
+                return result; 
+            }
+        }).build();
+    }
+
+    @Test
+    public void testCancelAfterStartTriggersListenableFuture() throws Exception {
+        doTestCancelTriggersListenableFuture(Duration.millis(50));
+    }
+    @Test
+    public void testCancelImmediateTriggersListenableFuture() throws Exception {
+        // if cancel fires after submit but before it passes to the executor,
+        // that needs handling separately; this doesn't guarantee this code path,
+        // but it happens sometimes (and it should be handled)
+        doTestCancelTriggersListenableFuture(Duration.ZERO);
+    }
+    public void doTestCancelTriggersListenableFuture(Duration delay) throws Exception {
+        Task<String> t = waitForSemaphore(Duration.TEN_SECONDS, true, "x");
+        addFutureListener(t, "before");
+
+        Stopwatch watch = Stopwatch.createStarted();
+        ec.submit(t);
+        
+        addFutureListener(t, "during");
+
+        log.info("test cancelling "+t+" ("+t.getClass()+") after "+delay);
+        // NB: two different code paths (callers to this method) for notifying futures 
+        // depending whether task is started 
+        Time.sleep(delay);
+
+        synchronized (data) {
+            t.cancel(true);
+            
+            assertSoonGetsData("before");
+            assertSoonGetsData("during");
+
+            addFutureListener(t, "after");
+            Assert.assertNull(data.get("after"));
+            assertSoonGetsData("after");
+        }
+        
+        Assert.assertTrue(t.isDone());
+        Assert.assertTrue(t.isCancelled());
+        try {
+            t.get();
+            Assert.fail("should have thrown CancellationException");
+        } catch (CancellationException e) { /* expected */ }
+        
+        Assert.assertTrue(watch.elapsed(TimeUnit.MILLISECONDS) < Duration.FIVE_SECONDS.toMilliseconds(), 
+            Time.makeTimeStringRounded(watch.elapsed(TimeUnit.MILLISECONDS))+" is too long; should have cancelled very quickly");
+
+        if (started.tryAcquire())
+            // if the task is begun, this should get released
+            Assert.assertTrue(cancelledWhileSleeping.tryAcquire(5, TimeUnit.SECONDS));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/CompoundTaskExecutionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/CompoundTaskExecutionTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/CompoundTaskExecutionTest.java
new file mode 100644
index 0000000..89bde95
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/CompoundTaskExecutionTest.java
@@ -0,0 +1,258 @@
+/*
+ * 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.util.task;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Semaphore;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.apache.brooklyn.core.util.task.CompoundTask;
+import org.apache.brooklyn.core.util.task.ParallelTask;
+import org.apache.brooklyn.core.util.task.SequentialTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.collections.Lists;
+
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Test the operation of the {@link CompoundTask} class.
+ */
+public class CompoundTaskExecutionTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CompoundTaskExecutionTest.class);
+
+    BasicExecutionManager em;
+    BasicExecutionContext ec;
+
+    @BeforeClass
+    public void setup() {
+        em = new BasicExecutionManager("mycontext");
+        ec = new BasicExecutionContext(em);
+    }
+
+    @AfterClass
+    public void teardown() {
+        if (em != null) em.shutdownNow();
+        em = null;
+    }
+
+    private BasicTask<String> taskReturning(final String val) {
+        return new BasicTask<String>(new Callable<String>() {
+                @Override public String call() {
+                    return val;
+                }
+            });
+    }
+
+    private BasicTask<String> slowTaskReturning(final String val, final Duration pauseTime) {
+        return new BasicTask<String>(new Callable<String>() {
+                @Override public String call() {
+                    Time.sleep(pauseTime);
+                    return val;
+                }
+            });
+    }
+
+
+    @Test
+    public void runSequenceTask() throws Exception {
+        BasicTask<String> t1 = taskReturning("a");
+        BasicTask<String> t2 = taskReturning("b");
+        BasicTask<String> t3 = taskReturning("c");
+        BasicTask<String> t4 = taskReturning("d");
+        Task<List<String>> tSequence = ec.submit(new SequentialTask<String>(t1, t2, t3, t4));
+        assertEquals(tSequence.get(), ImmutableList.of("a", "b", "c", "d"));
+    }
+
+    @Test
+    public void testSequentialTaskFailsWhenIntermediateTaskThrowsException() throws Exception {
+        BasicTask<String> t1 = taskReturning("a");
+        BasicTask<String> t2 = new BasicTask<String>(new Callable<String>() {
+                @Override public String call() throws Exception {
+                    throw new IllegalArgumentException("forced exception");
+                }
+            });
+        BasicTask<String> t3 = taskReturning("c");
+        SequentialTask<String> task = new SequentialTask<String>(t1, t2, t3);
+        Task<List<String>> tSequence = ec.submit(task);
+
+        try {
+            tSequence.get();
+            fail("t2 should have thrown an exception");
+        } catch (Exception e) {}
+
+        assertTrue(task.isDone());
+        assertTrue(task.isError());
+        assertTrue(t1.isDone());
+        assertFalse(t1.isError());
+        assertTrue(t2.isDone());
+        assertTrue(t2.isError());
+        // t3 not run because of t2 exception
+        assertFalse(t3.isDone());
+        assertFalse(t3.isBegun());
+    }
+
+    @Test
+    public void testParallelTaskFailsWhenIntermediateTaskThrowsException() throws Exception {
+        // differs from test above of SequentialTask in that expect t3 to be executed,
+        // despite t2 failing.
+        // TODO Do we expect tSequence.get() to block for everything to either fail or complete,
+        // and then to throw exception? Currently it does *not* do that so test was previously failing.
+
+        BasicTask<String> t1 = taskReturning("a");
+        BasicTask<String> t2 = new BasicTask<String>(new Callable<String>() {
+                @Override public String call() throws Exception {
+                    throw new IllegalArgumentException("forced exception");
+                }
+            });
+        BasicTask<String> t3 = slowTaskReturning("c", Duration.millis(100));
+        ParallelTask<String> task = new ParallelTask<String>(t1, t2, t3);
+        Task<List<String>> tSequence = ec.submit(task);
+
+        try {
+            tSequence.get();
+            fail("t2 should have thrown an exception");
+        } catch (Exception e) {}
+
+        assertTrue(task.isDone());
+        assertTrue(task.isError());
+        assertTrue(t1.isDone());
+        assertFalse(t1.isError());
+        assertTrue(t2.isDone());
+        assertTrue(t2.isError());
+        assertTrue(t3.isBegun());
+        assertTrue(t3.isDone());
+        assertFalse(t3.isError());
+    }
+
+    @Test
+    public void runParallelTask() throws Exception {
+        BasicTask<String> t1 = taskReturning("a");
+        BasicTask<String> t2 = taskReturning("b");
+        BasicTask<String> t3 = taskReturning("c");
+        BasicTask<String> t4 = taskReturning("d");
+        Task<List<String>> tSequence = ec.submit(new ParallelTask<String>(t4, t2, t1, t3));
+        assertEquals(new HashSet<String>(tSequence.get()), ImmutableSet.of("a", "b", "c", "d"));
+    }
+
+    @Test
+    public void runParallelTaskWithDelay() throws Exception {
+        final Semaphore locker = new Semaphore(0);
+        BasicTask<String> t1 = new BasicTask<String>(new Callable<String>() {
+                @Override public String call() {
+                    try {
+                        locker.acquire();
+                    } catch (InterruptedException e) {
+                        throw Throwables.propagate(e);
+                    }
+                    return "a";
+                }
+            });
+        BasicTask<String> t2 = taskReturning("b");
+        BasicTask<String> t3 = taskReturning("c");
+        BasicTask<String> t4 = taskReturning("d");
+        final Task<List<String>> tSequence = ec.submit(new ParallelTask<String>(t4, t2, t1, t3));
+
+        assertEquals(ImmutableSet.of(t2.get(), t3.get(), t4.get()), ImmutableSet.of("b", "c", "d"));
+        assertFalse(t1.isDone());
+        assertFalse(tSequence.isDone());
+
+        // get blocks until tasks have completed
+        Thread t = new Thread() {
+            @Override public void run() {
+                try {
+                    tSequence.get();
+                } catch (Exception e) {
+                    throw Throwables.propagate(e);
+                }
+                locker.release();
+            }
+        };
+        t.start();
+        Thread.sleep(30);
+        assertTrue(t.isAlive());
+
+        locker.release();
+
+        assertEquals(new HashSet<String>(tSequence.get()), ImmutableSet.of("a", "b", "c", "d"));
+        assertTrue(t1.isDone());
+        assertTrue(tSequence.isDone());
+
+        locker.acquire();
+    }
+
+    @Test
+    public void testComplexOrdering() throws Exception {
+        List<String> data = new CopyOnWriteArrayList<String>();
+        SequentialTask<String> taskA = new SequentialTask<String>(
+                appendAfterDelay(data, "a1"), appendAfterDelay(data, "a2"), appendAfterDelay(data, "a3"), appendAfterDelay(data, "a4"));
+        SequentialTask<String> taskB = new SequentialTask<String>(
+                appendAfterDelay(data, "b1"), appendAfterDelay(data, "b2"), appendAfterDelay(data, "b3"), appendAfterDelay(data, "b4"));
+        Task<List<String>> t = ec.submit(new ParallelTask<String>(taskA, taskB));
+        t.get();
+
+        LOG.debug("Tasks happened in order: {}", data);
+        assertEquals(data.size(), 8);
+        assertEquals(new HashSet<String>(data), ImmutableSet.of("a1", "a2", "a3", "a4", "b1", "b2", "b3", "b4"));
+
+        // a1, ..., a4 should be in order
+        List<String> as = Lists.newArrayList(), bs = Lists.newArrayList();
+        for (String value : data) {
+            ((value.charAt(0) == 'a') ? as : bs).add(value);
+        }
+        assertEquals(as, ImmutableList.of("a1", "a2", "a3", "a4"));
+        assertEquals(bs, ImmutableList.of("b1", "b2", "b3", "b4"));
+    }
+
+    private BasicTask<String> appendAfterDelay(final List<String> list, final String value) {
+        return new BasicTask<String>(new Callable<String>() {
+                @Override public String call() {
+                    try {
+                        Thread.sleep((int) (100 * Math.random()));
+                    } catch (InterruptedException e) {
+                        throw Throwables.propagate(e);
+                    }
+                    LOG.debug("running {}", value);
+                    list.add(value);
+                    return value;
+                }
+            });
+    }
+
+}


[36/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/file/ArchiveTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/file/ArchiveTasks.java b/core/src/main/java/brooklyn/util/file/ArchiveTasks.java
deleted file mode 100644
index b183f62..0000000
--- a/core/src/main/java/brooklyn/util/file/ArchiveTasks.java
+++ /dev/null
@@ -1,58 +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 brooklyn.util.file;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.management.TaskAdaptable;
-import org.apache.brooklyn.api.management.TaskFactory;
-
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.net.Urls;
-import brooklyn.util.task.Tasks;
-
-public class ArchiveTasks {
-
-    /** as {@link #deploy(ResourceUtils, Map, String, SshMachineLocation, String, String, String)} with the most common parameters */
-    public static TaskFactory<?> deploy(final ResourceUtils optionalResolver, final String archiveUrl, final SshMachineLocation machine, final String destDir) {
-        return deploy(optionalResolver, null, archiveUrl, machine, destDir, false, null, null);
-    }
-    
-    /** returns a task which installs and unpacks the given archive, as per {@link ArchiveUtils#deploy(ResourceUtils, Map, String, SshMachineLocation, String, String, String)};
-     * if allowNonarchivesOrKeepArchiveAfterDeploy is false, this task will fail if the item is not an archive;
-     * in cases where the download type is not clear in the URL but is known by the caller, supply a optionalDestFile including the appropriate file extension */
-    public static TaskFactory<?> deploy(final ResourceUtils resolver, final Map<String, ?> props, final String archiveUrl, final SshMachineLocation machine, final String destDir, final boolean allowNonarchivesOrKeepArchiveAfterDeploy, final String optionalTmpDir, final String optionalDestFile) {
-        return new TaskFactory<TaskAdaptable<?>>() {
-            @Override
-            public TaskAdaptable<?> newTask() {
-                return Tasks.<Void>builder().name("deploying "+Urls.getBasename(archiveUrl)).description("installing "+archiveUrl+" and unpacking to "+destDir).body(new Runnable() {
-                    @Override
-                    public void run() {
-                        boolean unpacked = ArchiveUtils.deploy(resolver, props, archiveUrl, machine, destDir, allowNonarchivesOrKeepArchiveAfterDeploy, optionalTmpDir, optionalDestFile);
-                        if (!unpacked && !allowNonarchivesOrKeepArchiveAfterDeploy) {
-                            throw new IllegalStateException("Unable to unpack archive from "+archiveUrl+"; not able to infer archive type");
-                        }
-                    }
-                }).build();
-            }
-        };
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/file/ArchiveUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/file/ArchiveUtils.java b/core/src/main/java/brooklyn/util/file/ArchiveUtils.java
deleted file mode 100644
index d072b70..0000000
--- a/core/src/main/java/brooklyn/util/file/ArchiveUtils.java
+++ /dev/null
@@ -1,351 +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 brooklyn.util.file;
-
-import static java.lang.String.format;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.EnumSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.javalang.StackTraceSimplifier;
-import brooklyn.util.net.Urls;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Preconditions;
-import com.google.common.io.Files;
-
-public class ArchiveUtils {
-
-    private static final Logger log = LoggerFactory.getLogger(ArchiveUtils.class);
-
-    // TODO Make this a ConfigKey on the machine location
-    /** Number of attempts when copying a file to a remote server. */
-    public static final int NUM_RETRIES_FOR_COPYING = 5;
-
-    /**
-     * The types of archive that are supported by Brooklyn.
-     */
-    public static enum ArchiveType {
-        TAR,
-        TGZ,
-        TBZ,
-        ZIP,
-        JAR,
-        WAR,
-        EAR,
-        UNKNOWN;
-
-        /**
-         * Zip format archives used by Java.
-         */
-        public static Set<ArchiveType> ZIP_ARCHIVES = EnumSet.of(ArchiveType.ZIP, ArchiveType.JAR, ArchiveType.WAR, ArchiveType.EAR);
-
-        public static ArchiveUtils.ArchiveType of(String filename) {
-            if (filename == null) return null;
-            String ext = Files.getFileExtension(filename);
-            try {
-                return valueOf(ext.toUpperCase());
-            } catch (IllegalArgumentException iae) {
-                if (filename.toLowerCase().endsWith(".tar.gz")) {
-                    return TGZ;
-                } else if (filename.toLowerCase().endsWith(".tar.bz") ||
-                        filename.toLowerCase().endsWith(".tar.bz2") ||
-                        filename.toLowerCase().endsWith(".tar.xz")) {
-                    return TBZ;
-                } else {
-                    return UNKNOWN;
-                }
-            }
-        }
-
-        @Override
-        public String toString() {
-            if (UNKNOWN.equals(this)) {
-                return "";
-            } else {
-                return name().toLowerCase();
-            }
-        }
-    }
-
-    /**
-     * Returns the list of commands used to install support for an archive with the given name.
-     */
-    public static List<String> installCommands(String fileName) {
-        List<String> commands = new LinkedList<String>();
-        switch (ArchiveType.of(fileName)) {
-            case TAR:
-            case TGZ:
-            case TBZ:
-                commands.add(BashCommands.INSTALL_TAR);
-                break;
-            case ZIP:
-                commands.add(BashCommands.INSTALL_UNZIP);
-                break;
-            case JAR:
-            case WAR:
-            case EAR:
-            case UNKNOWN:
-                break;
-        }
-        return commands;
-    }
-
-    /**
-     * Returns the list of commands used to extract the contents of the archive with the given name.
-     * <p>
-     * Optionally, Java archives of type
-     *
-     * @see #extractCommands(String, String)
-     */
-    public static List<String> extractCommands(String fileName, String sourceDir, String targetDir, boolean extractJar) {
-        return extractCommands(fileName, sourceDir, targetDir, extractJar, true);
-    }
-    
-    /** as {@link #extractCommands(String, String, String, boolean)}, but also with option to keep the original */
-    public static List<String> extractCommands(String fileName, String sourceDir, String targetDir, boolean extractJar, boolean keepOriginal) {
-        List<String> commands = new LinkedList<String>();
-        commands.add("cd " + targetDir);
-        String sourcePath = Os.mergePathsUnix(sourceDir, fileName);
-        switch (ArchiveType.of(fileName)) {
-            case TAR:
-                commands.add("tar xvf " + sourcePath);
-                break;
-            case TGZ:
-                commands.add("tar xvfz " + sourcePath);
-                break;
-            case TBZ:
-                commands.add("tar xvfj " + sourcePath);
-                break;
-            case ZIP:
-                commands.add("unzip " + sourcePath);
-                break;
-            case JAR:
-            case WAR:
-            case EAR:
-                if (extractJar) {
-                    commands.add("jar -xvf " + sourcePath);
-                    break;
-                }
-            case UNKNOWN:
-                if (!sourcePath.equals(Urls.mergePaths(targetDir, fileName))) {
-                    commands.add("cp " + sourcePath + " " + targetDir);
-                } else {
-                    keepOriginal = true;
-                    // else we'd just end up deleting it!
-                    // this branch will often lead to errors in any case, see the allowNonarchivesOrKeepArchiveAfterDeploy parameter 
-                    // in ArchiveTasks which calls through to here and then fails in the case corresponding to this code branch
-                }
-                break;
-        }
-        if (!keepOriginal && !commands.isEmpty())
-            commands.add("rm "+sourcePath);
-        return commands;
-    }
-
-    /**
-     * Returns the list of commands used to extract the contents of the archive with the given name.
-     * <p>
-     * The archive will be extracted in its current directory unless it is a Java archive of type {@code .jar},
-     * {@code .war} or {@code .ear}, which will be left as is.
-     *
-     * @see #extractCommands(String, String, String, boolean)
-     */
-    public static List<String> extractCommands(String fileName, String sourceDir) {
-        return extractCommands(fileName, sourceDir, ".", false);
-    }
-
-    /**
-     * Deploys an archive file to a remote machine and extracts the contents.
-     */
-    public static void deploy(String archiveUrl, SshMachineLocation machine, String destDir) {
-        deploy(MutableMap.<String, Object>of(), archiveUrl, machine, destDir);
-    }
-
-    /**
-     * Deploys an archive file to a remote machine and extracts the contents.
-     * <p>
-     * Copies the archive file from the given URL to the destination directory and extracts
-     * the contents. If the URL is a local directory, the contents are packaged as a Zip archive first.
-     *
-     * @see #deploy(String, SshMachineLocation, String, String)
-     * @see #deploy(Map, String, SshMachineLocation, String, String, String)
-     */
-    public static void deploy(Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String destDir) {
-        if (Urls.isDirectory(archiveUrl)) {
-            File zipFile = ArchiveBuilder.zip().entry(".", Urls.toFile(archiveUrl)).create();
-            archiveUrl = zipFile.getAbsolutePath();
-        }
-
-        // Determine filename
-        String destFile = archiveUrl.contains("?") ? archiveUrl.substring(0, archiveUrl.indexOf('?')) : archiveUrl;
-        destFile = destFile.substring(destFile.lastIndexOf('/') + 1);
-
-        deploy(props, archiveUrl, machine, destDir, destFile);
-    }
-
-    /**
-     * Deploys an archive file to a remote machine and extracts the contents.
-     * <p>
-     * Copies the archive file from the given URL to a file in the destination directory and extracts
-     * the contents.
-     *
-     * @see #deploy(String, SshMachineLocation, String)
-     * @see #deploy(Map, String, SshMachineLocation, String, String, String)
-     */
-    public static void deploy(String archiveUrl, SshMachineLocation machine, String destDir, String destFile) {
-        deploy(MutableMap.<String, Object>of(), archiveUrl, machine, destDir, destDir, destFile);
-    }
-    public static void deploy(Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String destDir, String destFile) {
-        deploy(props, archiveUrl, machine, destDir, destDir, destFile);
-    }
-    public static void deploy(Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String tmpDir, String destDir, String destFile) {
-        deploy(null, props, archiveUrl, machine, destDir, true, tmpDir, destFile);
-    }
-    
-    /**
-     * Deploys an archive file to a remote machine and extracts the contents.
-     * <p>
-     * Copies the archive file from the given URL to a file in a temporary directory and extracts
-     * the contents in the destination directory. For Java archives of type {@code .jar},
-     * {@code .war} or {@code .ear} the file is simply copied.
-     * 
-     * @return true if the archive is downloaded AND unpacked; false if it is downloaded but not unpacked; 
-     * throws if there was an error downloading or, for known archive types, unpacking.
-     *
-     * @see #deploy(String, SshMachineLocation, String)
-     * @see #deploy(Map, String, SshMachineLocation, String, String, String)
-     * @see #install(SshMachineLocation, String, String, int)
-     */
-    public static boolean deploy(ResourceUtils resolver, Map<String, ?> props, String archiveUrl, SshMachineLocation machine, String destDir, boolean keepArchiveAfterUnpacking, String optionalTmpDir, String optionalDestFile) {
-        String destFile = optionalDestFile;
-        if (destFile==null) destFile = Urls.getBasename(Preconditions.checkNotNull(archiveUrl, "archiveUrl"));
-        if (Strings.isBlank(destFile)) 
-            throw new IllegalStateException("Not given filename and cannot infer archive type from '"+archiveUrl+"'");
-        
-        String tmpDir = optionalTmpDir;
-        if (tmpDir==null) tmpDir=Preconditions.checkNotNull(destDir, "destDir");
-        if (props==null) props = MutableMap.of();
-        String destPath = Os.mergePaths(tmpDir, destFile);
-
-        // Use the location mutex to prevent package manager locking issues
-        machine.acquireMutex("installing", "installing archive");
-        try {
-            int result = install(resolver, props, machine, archiveUrl, destPath, NUM_RETRIES_FOR_COPYING);
-            if (result != 0) {
-                throw new IllegalStateException(format("Unable to install archive %s to %s", archiveUrl, machine));
-            }
-
-            // extract, now using task if available
-            MutableList<String> commands = MutableList.copyOf(installCommands(destFile))
-                    .appendAll(extractCommands(destFile, tmpDir, destDir, false, keepArchiveAfterUnpacking));
-            if (DynamicTasks.getTaskQueuingContext()!=null) {
-                result = DynamicTasks.queue(SshTasks.newSshExecTaskFactory(machine, commands.toArray(new String[0])).summary("extracting archive").requiringExitCodeZero()).get();
-            } else {
-                result = machine.execCommands(props, "extracting content", commands);
-            }
-            if (result != 0) {
-                throw new IllegalStateException(format("Failed to expand archive %s on %s", archiveUrl, machine));
-            }
-            return ArchiveType.of(destFile)!=ArchiveType.UNKNOWN;
-        } finally {
-            machine.releaseMutex("installing");
-        }
-    }
-
-    /**
-     * Installs a URL onto a remote machine.
-     *
-     * @see #install(Map, SshMachineLocation, String, String, int)
-     */
-    public static int install(SshMachineLocation machine, String urlToInstall, String target) {
-        return install(MutableMap.<String, Object>of(), machine, urlToInstall, target, NUM_RETRIES_FOR_COPYING);
-    }
-
-    /**
-     * Installs a URL onto a remote machine.
-     *
-     * @see #install(SshMachineLocation, String, String)
-     * @see SshMachineLocation#installTo(Map, String, String)
-     */
-    public static int install(Map<String, ?> props, SshMachineLocation machine, String urlToInstall, String target, int numAttempts) {
-        return install(null, props, machine, urlToInstall, target, numAttempts);
-    }
-    
-    public static int install(ResourceUtils resolver, Map<String, ?> props, SshMachineLocation machine, String urlToInstall, String target, int numAttempts) {
-        if (resolver==null) resolver = ResourceUtils.create(machine);
-        Exception lastError = null;
-        int retriesRemaining = numAttempts;
-        int attemptNum = 0;
-        do {
-            attemptNum++;
-            try {
-                Tasks.setBlockingDetails("Installing "+urlToInstall+" at "+machine);
-                // TODO would be nice to have this in a task (and the things within it!)
-                return machine.installTo(resolver, props, urlToInstall, target);
-            } catch (Exception e) {
-                Exceptions.propagateIfFatal(e);
-                lastError = e;
-                String stack = StackTraceSimplifier.toString(e);
-                if (stack.contains("net.schmizz.sshj.sftp.RemoteFile.write")) {
-                    log.warn("Failed to transfer "+urlToInstall+" to "+machine+", retryable error, attempt "+attemptNum+"/"+numAttempts+": "+e);
-                    continue;
-                }
-                log.warn("Failed to transfer "+urlToInstall+" to "+machine+", not a retryable error so failing: "+e);
-                throw Exceptions.propagate(e);
-            } finally {
-                Tasks.resetBlockingDetails();
-            }
-        } while (retriesRemaining --> 0);
-        throw Exceptions.propagate(lastError);
-    }
-
-    /**
-     * Copies the entire contents of a file to a String.
-     *
-     * @see com.google.common.io.Files#toString(File, java.nio.charset.Charset)
-     */
-    public static String readFullyString(File sourceFile) {
-        try {
-            return Files.toString(sourceFile, Charsets.UTF_8);
-        } catch (IOException ioe) {
-            throw Exceptions.propagate(ioe);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/flags/ClassCoercionException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/flags/ClassCoercionException.java b/core/src/main/java/brooklyn/util/flags/ClassCoercionException.java
deleted file mode 100644
index 17385ac..0000000
--- a/core/src/main/java/brooklyn/util/flags/ClassCoercionException.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 brooklyn.util.flags;
-
-/**
- * Thrown to indicate that {@link TypeCoercions} could not cast an object from one
- * class to another.
- */
-public class ClassCoercionException extends ClassCastException {
-    public ClassCoercionException() {
-        super();
-    }
-
-    /**
-     * Constructs a <code>ClassCoercionException</code> with the specified
-     * detail message.
-     *
-     * @param s the detail message.
-     */
-    public ClassCoercionException(String s) {
-        super(s);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/flags/FlagUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/flags/FlagUtils.java b/core/src/main/java/brooklyn/util/flags/FlagUtils.java
deleted file mode 100644
index 0e596ac..0000000
--- a/core/src/main/java/brooklyn/util/flags/FlagUtils.java
+++ /dev/null
@@ -1,587 +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 brooklyn.util.flags;
-
-import static brooklyn.util.GroovyJavaMethods.elvis;
-import static brooklyn.util.GroovyJavaMethods.truth;
-import static com.google.common.base.Preconditions.checkNotNull;
-import groovy.lang.Closure;
-import groovy.lang.GroovyObject;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-import org.apache.brooklyn.api.entity.trait.Configurable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.config.ConfigKey.HasConfigKey;
-import brooklyn.util.GroovyJavaMethods;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.guava.Maybe;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.base.Throwables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-
-
-/** class to help transfer values passed as named arguments to other well-known variables/fields/objects;
- * see the test case for example usage */
-public class FlagUtils {
-
-    public static final Logger log = LoggerFactory.getLogger(FlagUtils.class);
-    
-    private FlagUtils() {}
-    
-    /** see {@link #setFieldsFromFlags(Object o, ConfigBag)} */
-    public static Map<?, ?> setPublicFieldsFromFlags(Map<?, ?> flags, Object o) {
-        return setFieldsFromFlagsInternal(o, Arrays.asList(o.getClass().getFields()), flags, null, true);
-    }
-
-    /** see {@link #setFieldsFromFlags(Object, ConfigBag)} */
-    public static Map<?, ?> setFieldsFromFlags(Map<?, ?> flags, Object o) {
-        return setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), flags, null, true);
-    }
-    
-    /** sets all fields (including private and static, local and inherited) annotated {@link SetFromFlag} on the given object, 
-     * from the given flags map, returning just those flag-value pairs passed in which do not correspond to SetFromFlags fields 
-     * annotated ConfigKey and HasConfigKey fields are _configured_ (and we assume the object in that case is {@link Configurable});
-     * keys should be ConfigKey, HasConfigKey, or String;
-     * default values are also applied unless that is specified false on one of the variants of this method which takes such an argument
-     */
-    public static void setFieldsFromFlags(Object o, ConfigBag configBag) {
-        setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), configBag.getAllConfig(), configBag, true);
-    }
-
-    /** as {@link #setFieldsFromFlags(Object, ConfigBag)}, but allowing control over whether default values should be set */
-    public static void setFieldsFromFlags(Object o, ConfigBag configBag, boolean setDefaultVals) {
-        setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), configBag.getAllConfig(), configBag, setDefaultVals);
-    }
-
-    /** as {@link #setFieldsFromFlags(Object, ConfigBag)}, but specifying a subset of flags to use */
-    public static void setFieldsFromFlagsWithBag(Object o, Map<?,?> flags, ConfigBag configBag, boolean setDefaultVals) {
-        setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), flags, configBag, setDefaultVals);
-    }
-
-    /**
-     * Sets the field with the given flag (if it exists) to the given value.
-     * Will attempt to coerce the value to the required type.
-     * Will respect "nullable" on the SetFromFlag annotation.
-     * 
-     * @throws IllegalArgumentException If fieldVal is null and the SetFromFlag annotation set nullable=false
-     */
-    public static boolean setFieldFromFlag(Object o, String flagName, Object fieldVal) {
-        return setFieldFromFlagInternal(checkNotNull(flagName, "flagName"), fieldVal, o, getAllFields(o.getClass()));
-    }
-    
-    /** get all fields (including private and static) on the given object and all supertypes, 
-     * that are annotated with SetFromFlags. 
-     */
-    public static Map<String, ?> getFieldsWithFlags(Object o) {
-        return getFieldsWithFlagsInternal(o, getAllFields(o.getClass()));
-    }
-    
-    /**
-     * Finds the {@link Field} on the given object annotated with the given name flag.
-     */
-    public static Field findFieldForFlag(String flagName, Object o) {
-        return findFieldForFlagInternal(flagName, o, getAllFields(o.getClass()));
-    }
-
-    /** get all fields (including private and static) and their values on the given object and all supertypes, 
-     * where the field is annotated with SetFromFlags. 
-     */
-    public static Map<String, Object> getFieldsWithFlagsExcludingModifiers(Object o, int excludingModifiers) {
-        List<Field> filteredFields = Lists.newArrayList();
-        for (Field contender : getAllFields(o.getClass())) {
-            if ((contender.getModifiers() & excludingModifiers) == 0) {
-                filteredFields.add(contender);
-            }
-        }
-        return getFieldsWithFlagsInternal(o, filteredFields);
-    }
-    
-    /** get all fields with the given modifiers, and their values on the given object and all supertypes, 
-     * where the field is annotated with SetFromFlags. 
-     */
-    public static Map<String, Object> getFieldsWithFlagsWithModifiers(Object o, int requiredModifiers) {
-        List<Field> filteredFields = Lists.newArrayList();
-        for (Field contender : getAllFields(o.getClass())) {
-            if ((contender.getModifiers() & requiredModifiers) == requiredModifiers) {
-                filteredFields.add(contender);
-            }
-        }
-        return getFieldsWithFlagsInternal(o, filteredFields);
-    }
-    
-    /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, 
-     * using the indicated flags/config-bag 
-     * @deprecated since 0.7.0 use {@link #setAllConfigKeys(Map, Configurable, boolean)} */
-    public static Map<String, ?> setAllConfigKeys(Map<String, ?> flagsOrConfig, Configurable instance) {
-        return setAllConfigKeys(flagsOrConfig, instance, false);
-    }
-    /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, 
-     * using the indicated flags/config-bag */
-    public static Map<String, ?> setAllConfigKeys(Map<String, ?> flagsOrConfig, Configurable instance, boolean includeFlags) {
-        ConfigBag bag = new ConfigBag().putAll(flagsOrConfig);
-        setAllConfigKeys(instance, bag, includeFlags);
-        return bag.getUnusedConfigMutable();
-    }
-    
-    /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, 
-     * using the indicated flags/config-bag 
-    * @deprecated since 0.7.0 use {@link #setAllConfigKeys(Configurable, ConfigBag, boolean)} */
-    public static void setAllConfigKeys(Configurable o, ConfigBag bag) {
-        setAllConfigKeys(o, bag, false);
-    }
-    /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, 
-     * using the indicated flags/config-bag */
-    public static void setAllConfigKeys(Configurable o, ConfigBag bag, boolean includeFlags) {
-        for (Field f: getAllFields(o.getClass())) {
-            ConfigKey<?> key = getFieldAsConfigKey(o, f);
-            if (key!=null) {
-                FlagConfigKeyAndValueRecord record = getFlagConfigKeyRecord(f, key, bag);
-                if ((includeFlags && record.isValuePresent()) || record.getConfigKeyMaybeValue().isPresent()) {
-                    setField(o, f, record.getValueOrNullPreferringConfigKey(), null);
-                }
-            }
-        }
-    }
-    
-    public static class FlagConfigKeyAndValueRecord {
-        private String flagName = null;
-        private ConfigKey<?> configKey = null;
-        private Maybe<Object> flagValue = Maybe.absent();
-        private Maybe<Object> configKeyValue = Maybe.absent();
-        
-        public String getFlagName() {
-            return flagName;
-        }
-        public ConfigKey<?> getConfigKey() {
-            return configKey;
-        }
-        public Maybe<Object> getFlagMaybeValue() {
-            return flagValue;
-        }
-        public Maybe<Object> getConfigKeyMaybeValue() {
-            return configKeyValue;
-        }
-        public Object getValueOrNullPreferringConfigKey() {
-            return getConfigKeyMaybeValue().or(getFlagMaybeValue()).orNull();
-        }
-        public Object getValueOrNullPreferringFlag() {
-            return getFlagMaybeValue().or(getConfigKeyMaybeValue()).orNull();
-        }
-        /** true if value is present for either flag or config key */
-        public boolean isValuePresent() {
-            return flagValue.isPresent() || configKeyValue.isPresent();
-        }
-        
-        @Override
-        public String toString() {
-            return Objects.toStringHelper(this).omitNullValues()
-                .add("flag", flagName)
-                .add("configKey", configKey)
-                .add("flagValue", flagValue.orNull())
-                .add("configKeyValue", configKeyValue.orNull())
-                .toString();
-        }
-    }
-    
-    /** gets all the flags/keys in the given config bag which are applicable to the given type's config keys and flags */
-    public static <T> List<FlagConfigKeyAndValueRecord> findAllFlagsAndConfigKeys(T optionalInstance, Class<? extends T> type, ConfigBag input) {
-        List<FlagConfigKeyAndValueRecord> output = new ArrayList<FlagUtils.FlagConfigKeyAndValueRecord>();
-        for (Field f: getAllFields(type)) {
-            ConfigKey<?> key = getFieldAsConfigKey(optionalInstance, f);
-            FlagConfigKeyAndValueRecord record = getFlagConfigKeyRecord(f, key, input);
-            if (record.isValuePresent())
-                output.add(record);
-        }
-        return output;
-    }
-
-    /** returns the flag/config-key record for the given input */
-    private static FlagConfigKeyAndValueRecord getFlagConfigKeyRecord(Field f, ConfigKey<?> key, ConfigBag input) {
-        FlagConfigKeyAndValueRecord result = new FlagConfigKeyAndValueRecord(); 
-        result.configKey = key;
-        if (key!=null && input.containsKey(key))
-            result.configKeyValue = Maybe.<Object>of(input.getStringKey(key.getName()));
-        SetFromFlag flag = f.getAnnotation(SetFromFlag.class);
-        if (flag!=null) {
-            result.flagName = flag.value();
-            if (input.containsKey(flag.value()))
-                result.flagValue = Maybe.of(input.getStringKey(flag.value()));
-        }
-        return result;
-    }
-
-    /** returns all fields on the given class, superclasses, and interfaces thereof, in that order of preference,
-     * (excluding fields on Object) */
-    public static List<Field> getAllFields(Class<?> base, Closure<Boolean> filter) {
-        return getAllFields(base, GroovyJavaMethods.<Field>predicateFromClosure(filter));
-    }
-    public static List<Field> getAllFields(Class<?> base) {
-        return getAllFields(base, Predicates.<Field>alwaysTrue());
-    }
-    public static List<Field> getAllFields(Class<?> base, Predicate<Field> filter) {
-        return getLocalFields(getAllAssignableTypes(base), filter);
-    }
-    /** returns all fields explicitly declared on the given classes */
-    public static List<Field> getLocalFields(List<Class<?>> classes) {
-        return getLocalFields(classes, Predicates.<Field>alwaysTrue());
-    }
-    public static List<Field> getLocalFields(List<Class<?>> classes, Closure<Boolean> filter) {
-        return getLocalFields(classes, GroovyJavaMethods.<Field>predicateFromClosure(filter));
-    }
-    public static List<Field> getLocalFields(List<Class<?>> classes, Predicate<Field> filter) {
-        List<Field> fields = Lists.newArrayList();
-        for (Class<?> c : classes) {
-            for (Field f : c.getDeclaredFields()) {
-                if (filter.apply(f)) fields.add(f);
-            }
-        }
-        return fields;
-    }
-    
-    /** returns base, superclasses, then interfaces */
-    public static List<Class<?>> getAllAssignableTypes(Class<?> base) {
-        return getAllAssignableTypes(base, new Predicate<Class<?>>() {
-            @Override public boolean apply(Class<?> it) {
-                return (it != Object.class) && (it != GroovyObject.class);
-            }
-        });
-    }
-    public static List<Class<?>> getAllAssignableTypes(Class<?> base, Closure<Boolean> filter) {
-        return getAllAssignableTypes(base, GroovyJavaMethods.<Class<?>>predicateFromClosure(filter));
-    }
-    public static List<Class<?>> getAllAssignableTypes(Class<?> base, Predicate<Class<?>> filter) {
-        List<Class<?>> classes = Lists.newArrayList();
-        for (Class<?> c = base; c != null; c = c.getSuperclass()) {
-            if (filter.apply(c)) classes.add(c);
-        }
-        for (int i=0; i<classes.size(); i++) {
-            for (Class<?> interf : classes.get(i).getInterfaces()) {
-                if (filter.apply(interf) && !(classes.contains(interf))) classes.add(interf);
-            }
-        }
-        return classes;
-    }
-    
-    private static Map<String, Object> getFieldsWithFlagsInternal(Object o, Collection<Field> fields) {
-        Map<String, Object> result = Maps.newLinkedHashMap();
-        for (Field f: fields) {
-            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
-            if (cf != null) {
-                String flagName = elvis(cf.value(), f.getName());
-                if (truth(flagName)) {
-                    result.put(flagName, getField(o, f));
-                } else {
-                    log.warn("Ignoring field {} of object {} as no flag name available", f, o);
-                }
-            }
-        }
-        return result;
-    }
-
-    private static Field findFieldForFlagInternal(String flagName, Object o, Collection<Field> fields) {
-        for (Field f: fields) {
-            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
-            if (cf != null) {
-                String contenderName = elvis(cf.value(), f.getName());
-                if (flagName.equals(contenderName)) {
-                    return f;
-                }
-            }
-        }
-        throw new NoSuchElementException("Field with flag "+flagName+" not found on "+o+" of type "+(o != null ? o.getClass() : null));
-    }
-
-    private static boolean setFieldFromFlagInternal(String flagName, Object fieldVal, Object o, Collection<Field> fields) {
-        for (Field f: fields) {
-            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
-            if (cf != null && flagName.equals(elvis(cf.value(), f.getName()))) {
-                setField(o, f, fieldVal, cf);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static Map<String, ?> setFieldsFromFlagsInternal(Object o, Collection<Field> fields, Map<?,?> flagsOrConfig, ConfigBag bag, boolean setDefaultVals) {
-        if (bag==null) bag = new ConfigBag().putAll(flagsOrConfig);
-        for (Field f: fields) {
-            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
-            if (cf!=null) setFieldFromConfig(o, f, bag, cf, setDefaultVals);
-        }
-        return bag.getUnusedConfigMutable();
-    }
-
-    private static void setFieldFromConfig(Object o, Field f, ConfigBag bag, SetFromFlag optionalAnnotation, boolean setDefaultVals) {
-        String flagName = optionalAnnotation==null ? null : (String)elvis(optionalAnnotation.value(), f.getName());
-        // prefer flag name, if present
-        if (truth(flagName) && bag.containsKey(flagName)) {
-            setField(o, f, bag.getStringKey(flagName), optionalAnnotation);
-            return;
-        }
-        // first check whether it is a key
-        ConfigKey<?> key = getFieldAsConfigKey(o, f);
-        if (key!=null && bag.containsKey(key)) {
-            Object uncoercedValue = bag.getStringKey(key.getName());
-            setField(o, f, uncoercedValue, optionalAnnotation);
-            return;
-        }
-        if (setDefaultVals && optionalAnnotation!=null && truth(optionalAnnotation.defaultVal())) {
-            Object oldValue;
-            try {
-                f.setAccessible(true);
-                oldValue = f.get(o);
-                if (oldValue==null || oldValue.equals(getDefaultValueForType(f.getType()))) {
-                    setField(o, f, optionalAnnotation.defaultVal(), optionalAnnotation);
-                }
-            } catch (Exception e) {
-                Exceptions.propagate(e);
-            }
-            return;
-        }
-    }
-
-    /** returns the given field as a config key, if it is an accessible config key, otherwise null */
-    private static ConfigKey<?> getFieldAsConfigKey(Object optionalInstance, Field f) {
-        if (optionalInstance==null) {
-            if ((f.getModifiers() & Modifier.STATIC)==0)
-                // non-static field on null instance, can't be set
-                return null;
-        }
-        if (ConfigKey.class.isAssignableFrom(f.getType())) {
-            return (ConfigKey<?>) getField(optionalInstance, f);
-        } else if (HasConfigKey.class.isAssignableFrom(f.getType())) {
-            return ((HasConfigKey<?>)getField(optionalInstance, f)).getConfigKey();
-        }
-        return null;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static void setConfig(Object objectOfField, ConfigKey<?> key, Object value, SetFromFlag optionalAnnotation) {
-        if (objectOfField instanceof Configurable) {
-            ((Configurable)objectOfField).setConfig((ConfigKey)key, value);
-            return;
-        } else {
-            if (optionalAnnotation==null) {
-                log.warn("Cannot set key "+key.getName()+" on "+objectOfField+": containing class is not Configurable");
-            } else if (!key.getName().equals(optionalAnnotation.value())) {
-                log.warn("Cannot set key "+key.getName()+" on "+objectOfField+" from flag "+optionalAnnotation.value()+": containing class is not Configurable");
-            } else {
-                // if key and flag are the same, then it will probably happen automatically
-                if (log.isDebugEnabled())
-                    log.debug("Cannot set key "+key.getName()+" on "+objectOfField+" from flag "+optionalAnnotation.value()+": containing class is not Configurable");
-            }
-            return;
-        }
-    }
-    
-    /** sets the field to the value, after checking whether the given value can be set 
-     * respecting the constraints of the annotation 
-     */
-    public static void setField(Object objectOfField, Field f, Object value, SetFromFlag optionalAnnotation) {
-        try {
-            ConfigKey<?> key = getFieldAsConfigKey(objectOfField, f);
-            if (key!=null) {
-                setConfig(objectOfField, key, value, optionalAnnotation);
-                return;
-            }
-            
-            if (!f.isAccessible()) f.setAccessible(true);
-            if (optionalAnnotation!=null && optionalAnnotation.immutable()) {
-                Object oldValue = f.get(objectOfField);
-                if (!Objects.equal(oldValue, getDefaultValueForType(f.getType())) && oldValue != value) {
-                    throw new IllegalStateException("Forbidden modification to immutable field "+
-                        f+" in "+objectOfField+": attempting to change to "+value+" when was already "+oldValue);
-                }
-            }
-            if (optionalAnnotation!=null && !optionalAnnotation.nullable() && value==null) {
-                throw new IllegalArgumentException("Forbidden null assignment to non-nullable field "+
-                        f+" in "+objectOfField);
-            }
-            if (optionalAnnotation!=null && (f.getModifiers() & Modifier.STATIC)==Modifier.STATIC)
-                log.warn("Setting static field "+f+" in "+objectOfField+" from flag "+optionalAnnotation.value()+": discouraged");
-
-            Object newValue;
-            try {
-                newValue = TypeCoercions.coerce(value, f.getType());
-            } catch (Exception e) {
-                throw new IllegalArgumentException("Cannot set "+f+" in "+objectOfField+" from type "+value.getClass()+" ("+value+"): "+e, e);
-            }
-            f.set(objectOfField, newValue);
-            if (log.isTraceEnabled()) log.trace("FlagUtils for "+objectOfField+", setting field="+f.getName()+"; val="+value+"; newVal="+newValue+"; key="+key);
-
-        } catch (IllegalAccessException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-
-    /** gets the value of the field. 
-     */
-    public static Object getField(Object objectOfField, Field f) {
-        try {
-            if (!f.isAccessible()) f.setAccessible(true);
-            return f.get(objectOfField);
-        } catch (IllegalAccessException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-    
-    /** returns the default/inital value that is assigned to fields of the givien type;
-     * if the type is not primitive this value is null;
-     * for primitive types it is obvious but not AFAIK programmatically visible
-     * (e.g. 0 for int, false for boolean)  
-     */
-    public static Object getDefaultValueForType(Class<?> t) {
-        if (!t.isPrimitive()) return null;
-        if (t==Integer.TYPE) return (int)0;
-        if (t==Long.TYPE) return (long)0;
-        if (t==Double.TYPE) return (double)0;
-        if (t==Float.TYPE) return (float)0;
-        if (t==Byte.TYPE) return (byte)0;
-        if (t==Short.TYPE) return (short)0;
-        if (t==Character.TYPE) return (char)0;
-        if (t==Boolean.TYPE) return false;
-        //should never happen
-        throw new IllegalStateException("Class "+t+" is an unknown primitive.");
-    }
-
-    /** returns a map of all fields which are annotated 'SetFromFlag', along with the annotation */
-    public static Map<Field,SetFromFlag> getAnnotatedFields(Class<?> type) {
-        Map<Field, SetFromFlag> result = Maps.newLinkedHashMap();
-        for (Field f: getAllFields(type)) {
-            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
-            if (truth(cf)) result.put(f, cf);
-        }
-        return result;
-    }
-
-    /** returns a map of all {@link ConfigKey} fields which are annotated 'SetFromFlag', along with the annotation */
-    public static Map<ConfigKey<?>,SetFromFlag> getAnnotatedConfigKeys(Class<?> type) {
-        Map<ConfigKey<?>, SetFromFlag> result = Maps.newLinkedHashMap();
-        List<Field> fields = getAllFields(type, new Predicate<Field>() {
-            @Override public boolean apply(Field f) {
-                return (f != null) && ConfigKey.class.isAssignableFrom(f.getType()) && ((f.getModifiers() & Modifier.STATIC)!=0);
-            }});
-        for (Field f: fields) {
-            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
-            if (cf != null) {
-                ConfigKey<?> key = getFieldAsConfigKey(null, f);
-                if (key != null) {
-                    result.put(key, cf);
-                }
-            }
-        }
-        return result;
-    }
-
-    /** returns a map of all fields which are annotated 'SetFromFlag' with their current values;
-     * useful if you want to clone settings from one object
-     */
-    public static Map<String,Object> getFieldsWithValues(Object o) {
-        try {
-            Map<String, Object> result = Maps.newLinkedHashMap();
-            for (Map.Entry<Field, SetFromFlag> entry : getAnnotatedFields(o.getClass()).entrySet()) {
-                Field f = entry.getKey();
-                SetFromFlag cf = entry.getValue();
-                String flagName = elvis(cf.value(), f.getName());
-                if (truth(flagName)) {
-                    if (!f.isAccessible()) f.setAccessible(true);
-                    result.put(flagName, f.get(o));
-                }
-            }
-            return result;
-        } catch (IllegalAccessException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-        
-    /**
-     * @throws an IllegalStateException if there are fields required (nullable=false) which are unset 
-     * @throws wrapped IllegalAccessException
-     */
-    public static void checkRequiredFields(Object o) {
-        try {
-            Set<String> unsetFields = Sets.newLinkedHashSet();
-            for (Map.Entry<Field, SetFromFlag> entry : getAnnotatedFields(o.getClass()).entrySet()) {
-                Field f = entry.getKey();
-                SetFromFlag cf = entry.getValue();
-                if (!cf.nullable()) {
-                    String flagName = elvis(cf.value(), f.getName());
-                    if (!f.isAccessible()) f.setAccessible(true);
-                    Object v = f.get(o);
-                    if (v==null) unsetFields.add(flagName);
-                }
-            }
-            if (truth(unsetFields)) {
-                throw new IllegalStateException("Missing required "+(unsetFields.size()>1 ? "fields" : "field")+": "+unsetFields);
-            }
-        } catch (IllegalAccessException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-
-//    /** sets all fields in target annotated with @SetFromFlag using the configuration in the given config bag */
-//    public static void setFieldsFromConfigFlags(Object target, ConfigBag configBag) {
-//        setFieldsFromConfigFlags(target, configBag.getAllConfig(), configBag);
-//    }
-//
-//    
-//    /** sets all fields in target annotated with @SetFromFlag using the configuration in the given configToUse,
-//     * marking used in the given configBag */
-//    public static void setFieldsFromConfigFlags(Object target, Map<?,?> configToUse, ConfigBag configBag) {
-//        for (Map.Entry<?,?> entry: configToUse.entrySet()) {
-//            setFieldFromConfigFlag(target, entry.getKey(), entry.getValue(), configBag);
-//        }
-//    }
-//
-//    public static void setFieldFromConfigFlag(Object target, Object key, Object value, ConfigBag optionalConfigBag) {
-//        String name = null;
-//        if (key instanceof String) name = (String)key;
-//        else if (key instanceof ConfigKey<?>) name = ((ConfigKey<?>)key).getName();
-//        else if (key instanceof HasConfigKey<?>) name = ((HasConfigKey<?>)key).getConfigKey().getName();
-//        else {
-//            if (key!=null) {
-//                log.warn("Invalid config type "+key.getClass().getCanonicalName()+" ("+key+") when configuring "+target+"; ignoring");
-//            }
-//            return;
-//        }
-//        if (setFieldFromFlag(name, value, target)) {
-//            if (optionalConfigBag!=null)
-//                optionalConfigBag.markUsed(name);
-//        }
-//    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/flags/MethodCoercions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/flags/MethodCoercions.java b/core/src/main/java/brooklyn/util/flags/MethodCoercions.java
deleted file mode 100644
index c9f00fe..0000000
--- a/core/src/main/java/brooklyn/util/flags/MethodCoercions.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 brooklyn.util.flags;
-
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.guava.Maybe;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import com.google.common.reflect.TypeToken;
-
-import javax.annotation.Nullable;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Type;
-import java.util.Arrays;
-import java.util.List;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-/**
- * A way of binding a loosely-specified method call into a strongly-typed Java method call.
- */
-public class MethodCoercions {
-
-    /**
-     * Returns a predicate that matches a method with the given name, and a single parameter that
-     * {@link brooklyn.util.flags.TypeCoercions#tryCoerce(Object, com.google.common.reflect.TypeToken)} can process
-     * from the given argument.
-     *
-     * @param methodName name of the method
-     * @param argument argument that is intended to be given
-     * @return a predicate that will match a compatible method
-     */
-    public static Predicate<Method> matchSingleParameterMethod(final String methodName, final Object argument) {
-        checkNotNull(methodName, "methodName");
-        checkNotNull(argument, "argument");
-
-        return new Predicate<Method>() {
-            @Override
-            public boolean apply(@Nullable Method input) {
-                if (input == null) return false;
-                if (!input.getName().equals(methodName)) return false;
-                Type[] parameterTypes = input.getGenericParameterTypes();
-                return parameterTypes.length == 1
-                        && TypeCoercions.tryCoerce(argument, TypeToken.of(parameterTypes[0])).isPresentAndNonNull();
-
-            }
-        };
-    }
-
-    /**
-     * Tries to find a single-parameter method with a parameter compatible with (can be coerced to) the argument, and
-     * invokes it.
-     *
-     * @param instance the object to invoke the method on
-     * @param methodName the name of the method to invoke
-     * @param argument the argument to the method's parameter.
-     * @return the result of the method call, or {@link brooklyn.util.guava.Maybe#absent()} if method could not be matched.
-     */
-    public static Maybe<?> tryFindAndInvokeSingleParameterMethod(final Object instance, final String methodName, final Object argument) {
-        Class<?> clazz = instance.getClass();
-        Iterable<Method> methods = Arrays.asList(clazz.getMethods());
-        Optional<Method> matchingMethod = Iterables.tryFind(methods, matchSingleParameterMethod(methodName, argument));
-        if (matchingMethod.isPresent()) {
-            Method method = matchingMethod.get();
-            try {
-                Type paramType = method.getGenericParameterTypes()[0];
-                Object coercedArgument = TypeCoercions.coerce(argument, TypeToken.of(paramType));
-                return Maybe.of(method.invoke(instance, coercedArgument));
-            } catch (IllegalAccessException | InvocationTargetException e) {
-                throw Exceptions.propagate(e);
-            }
-        } else {
-            return Maybe.absent();
-        }
-    }
-
-    /**
-     * Returns a predicate that matches a method with the given name, and parameters that
-     * {@link brooklyn.util.flags.TypeCoercions#tryCoerce(Object, com.google.common.reflect.TypeToken)} can process
-     * from the given list of arguments.
-     *
-     * @param methodName name of the method
-     * @param arguments arguments that is intended to be given
-     * @return a predicate that will match a compatible method
-     */
-    public static Predicate<Method> matchMultiParameterMethod(final String methodName, final List<?> arguments) {
-        checkNotNull(methodName, "methodName");
-        checkNotNull(arguments, "arguments");
-
-        return new Predicate<Method>() {
-            @Override
-            public boolean apply(@Nullable Method input) {
-                if (input == null) return false;
-                if (!input.getName().equals(methodName)) return false;
-                int numOptionParams = arguments.size();
-                Type[] parameterTypes = input.getGenericParameterTypes();
-                if (parameterTypes.length != numOptionParams) return false;
-
-                for (int paramCount = 0; paramCount < numOptionParams; paramCount++) {
-                    if (!TypeCoercions.tryCoerce(((List) arguments).get(paramCount),
-                            TypeToken.of(parameterTypes[paramCount])).isPresentAndNonNull()) return false;
-                }
-                return true;
-            }
-        };
-    }
-
-    /**
-     * Tries to find a multiple-parameter method with each parameter compatible with (can be coerced to) the
-     * corresponding argument, and invokes it.
-     *
-     * @param instance the object to invoke the method on
-     * @param methodName the name of the method to invoke
-     * @param argument a list of the arguments to the method's parameters.
-     * @return the result of the method call, or {@link brooklyn.util.guava.Maybe#absent()} if method could not be matched.
-     */
-    public static Maybe<?> tryFindAndInvokeMultiParameterMethod(final Object instance, final String methodName, final List<?> arguments) {
-        Class<?> clazz = instance.getClass();
-        Iterable<Method> methods = Arrays.asList(clazz.getMethods());
-        Optional<Method> matchingMethod = Iterables.tryFind(methods, matchMultiParameterMethod(methodName, arguments));
-        if (matchingMethod.isPresent()) {
-            Method method = matchingMethod.get();
-            try {
-                int numOptionParams = ((List)arguments).size();
-                Object[] coercedArguments = new Object[numOptionParams];
-                for (int paramCount = 0; paramCount < numOptionParams; paramCount++) {
-                    Object argument = arguments.get(paramCount);
-                    Type paramType = method.getGenericParameterTypes()[paramCount];
-                    coercedArguments[paramCount] = TypeCoercions.coerce(argument, TypeToken.of(paramType));
-                }
-                return Maybe.of(method.invoke(instance, coercedArguments));
-            } catch (IllegalAccessException | InvocationTargetException e) {
-                throw Exceptions.propagate(e);
-            }
-        } else {
-            return Maybe.absent();
-        }
-    }
-
-    /**
-     * Tries to find a method with each parameter compatible with (can be coerced to) the corresponding argument, and invokes it.
-     *
-     * @param instance the object to invoke the method on
-     * @param methodName the name of the method to invoke
-     * @param argument a list of the arguments to the method's parameters, or a single argument for a single-parameter method.
-     * @return the result of the method call, or {@link brooklyn.util.guava.Maybe#absent()} if method could not be matched.
-     */
-    public static Maybe<?> tryFindAndInvokeBestMatchingMethod(final Object instance, final String methodName, final Object argument) {
-        if (argument instanceof List) {
-            List<?> arguments = (List<?>) argument;
-
-            // ambiguous case: we can't tell if the user is using the multi-parameter syntax, or the single-parameter
-            // syntax for a method which takes a List parameter. So we try one, then fall back to the other.
-
-            Maybe<?> maybe = tryFindAndInvokeMultiParameterMethod(instance, methodName, arguments);
-            if (maybe.isAbsent())
-                maybe = tryFindAndInvokeSingleParameterMethod(instance, methodName, argument);
-
-            return maybe;
-        } else {
-            return tryFindAndInvokeSingleParameterMethod(instance, methodName, argument);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/flags/SetFromFlag.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/flags/SetFromFlag.java b/core/src/main/java/brooklyn/util/flags/SetFromFlag.java
deleted file mode 100644
index c7d588e..0000000
--- a/core/src/main/java/brooklyn/util/flags/SetFromFlag.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 brooklyn.util.flags;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Annotation to indicate that a variable may be set through the use of a named argument,
- * looking for the name specified here or inferred from the annotated field/argument/object.
- * <p>
- * This is used to automate the processing where named arguments are passed in constructors
- * and other methods, and the values of those named arguments should be transferred to
- * other known fields/arguments/objects at runtime.
- * <p>
- * Fields on a class are typically set from values in a map with a call to
- * {@link FlagUtils#setFieldsFromFlags(java.util.Map, Object)}.
- * That method (and related, in the same class) will attend to the arguments here.
- */
-@Retention(RetentionPolicy.RUNTIME)
-public @interface SetFromFlag {
-
-    /** the flag (key) which should be used to find the value; if empty defaults to field/argument/object name */
-    String value() default "";
-    
-    /** whether the object should not be changed once set; defaults to false
-     * <p>
-     * this is partially tested for in many routines, but not all;
-     * when nullable=false the testing (when done) is guaranteed.
-     * however if nullable is allowed we do not distinguish between null and unset
-     * so explicitly setting null then setting to a value is not detected as an illegal mutating.
-     */
-    boolean immutable() default false;
-    
-    /** whether the object is required & should not be set to null; defaults to true.
-     * (there is no 'required' parameter, but setting nullable false then invoking 
-     * e.g. {@link FlagUtils#checkRequiredFields(Object)} has the effect of requiring a value)
-     * <p>
-     * code should call that method explicitly to enforce nullable false;
-     * errors are not done during a call to setFieldsFromFlags 
-     * because fields may be initialised in multiple passes.) 
-     * <p>
-     * this is partially tested for in many routines, but not all
-     */
-    boolean nullable() default true;
-
-    /** The default value, if it is not explicitly set.
-     * <p>
-     * The value will be coerced from String where required, for types supported by {@link TypeCoercions}.
-     * <p>
-     * The field will be initialised with its default value on the first call to setFieldsFromFlags
-     * (or related).  (The field will not be initialised if that method is not called.) 
-     */
-    String defaultVal() default "";
-}


[31/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicTask.java b/core/src/main/java/brooklyn/util/task/BasicTask.java
deleted file mode 100644
index 57b2bb2..0000000
--- a/core/src/main/java/brooklyn/util/task/BasicTask.java
+++ /dev/null
@@ -1,892 +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 brooklyn.util.task;
-
-import static brooklyn.util.JavaGroovyEquivalents.asString;
-import static brooklyn.util.JavaGroovyEquivalents.elvisString;
-import groovy.lang.Closure;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.management.LockInfo;
-import java.lang.management.ManagementFactory;
-import java.lang.management.ThreadInfo;
-import java.util.Collections;
-import java.util.ConcurrentModificationException;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.apache.brooklyn.api.management.HasTaskChildren;
-import org.apache.brooklyn.api.management.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.GroovyJavaMethods;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.base.Objects;
-import com.google.common.base.Throwables;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.Callables;
-import com.google.common.util.concurrent.ExecutionList;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * The basic concrete implementation of a {@link Task} to be executed.
- *
- * A {@link Task} is a wrapper for an executable unit, such as a {@link Closure} or a {@link Runnable} or
- * {@link Callable} and will run in its own {@link Thread}.
- * <p>
- * The task can be given an optional displayName and description in its constructor (as named
- * arguments in the first {@link Map} parameter). It is guaranteed to have {@link Object#notify()} called
- * once whenever the task starts running and once again when the task is about to complete. Due to
- * the way executors work it is ugly to guarantee notification <em>after</em> completion, so instead we
- * notify just before then expect the user to call {@link #get()} - which will throw errors if the underlying job
- * did so - or {@link #blockUntilEnded()} which will not throw errors.
- */
-public class BasicTask<T> implements TaskInternal<T> {
-    private static final Logger log = LoggerFactory.getLogger(BasicTask.class);
-
-    private String id = Identifiers.makeRandomId(8);
-    protected Callable<T> job;
-    public final String displayName;
-    public final String description;
-
-    protected final Set<Object> tags = Sets.newConcurrentHashSet();
-    // for debugging, to record where tasks were created
-//    { tags.add(new Throwable("Creation stack trace")); }
-    
-    protected Task<?> proxyTargetTask = null;
-
-    protected String blockingDetails = null;
-    protected Task<?> blockingTask = null;
-    Object extraStatusText = null;
-
-    /** listeners attached at task level; these are stored here, but run on the underlying ListenableFuture */
-    protected final ExecutionList listeners = new ExecutionList();
-    
-    /**
-     * Constructor needed to prevent confusion in groovy stubs when looking for default constructor,
-     *
-     * The generics on {@link Closure} break it if that is first constructor.
-     */
-    protected BasicTask() { this(Collections.emptyMap()); }
-    protected BasicTask(Map<?,?> flags) { this(flags, (Callable<T>) null); }
-
-    public BasicTask(Callable<T> job) { this(Collections.emptyMap(), job); }
-    
-    public BasicTask(Map<?,?> flags, Callable<T> job) {
-        this.job = job;
-
-        if (flags.containsKey("tag")) tags.add(flags.remove("tag"));
-        Object ftags = flags.remove("tags");
-        if (ftags!=null) {
-            if (ftags instanceof Iterable) Iterables.addAll(tags, (Iterable<?>)ftags);
-            else {
-                log.info("deprecated use of non-collection argument for 'tags' ("+ftags+") in "+this, new Throwable("trace of discouraged use of non-colleciton tags argument"));
-                tags.add(ftags);
-            }
-        }
-
-        description = elvisString(flags.remove("description"), "");
-        String d = asString(flags.remove("displayName"));
-        displayName = (d==null ? "" : d);
-    }
-
-    public BasicTask(Runnable job) { this(GroovyJavaMethods.<T>callableFromRunnable(job)); }
-    public BasicTask(Map<?,?> flags, Runnable job) { this(flags, GroovyJavaMethods.<T>callableFromRunnable(job)); }
-    public BasicTask(Closure<T> job) { this(GroovyJavaMethods.callableFromClosure(job)); }
-    public BasicTask(Map<?,?> flags, Closure<T> job) { this(flags, GroovyJavaMethods.callableFromClosure(job)); }
-
-    @Override
-    public String getId() {
-        return id;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof Task)
-            return ((Task<?>)obj).getId().equals(getId());
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        // give display name plus id, or job and tags plus id; some jobs have been extended to include nice tostrings 
-        return "Task["+
-            (Strings.isNonEmpty(displayName) ? 
-                displayName : 
-                (job + (tags!=null && !tags.isEmpty() ? ";"+tags : "")) ) +
-            ":"+getId()+"]";
-    }
-
-    @Override
-    public Task<T> asTask() {
-        return this;
-    }
-    
-    // housekeeping --------------------
-
-    /*
-     * These flags are set by BasicExecutionManager.submit.
-     *
-     * Order is guaranteed to be as shown below, in order of #. Within each # line it is currently in the order specified by commas but this is not guaranteed.
-     * (The spaces between the # section indicate longer delays / logical separation ... it should be clear!)
-     *
-     * # submitter, submit time set, tags and other submit-time fields set
-     *
-     * # thread set, ThreadLocal getCurrentTask set
-     * # start time set, isBegun is true
-     * # task end callback run, if supplied
-     *
-     * # task runs
-     *
-     * # task end callback run, if supplied
-     * # end time set
-     * # thread cleared, ThreadLocal getCurrentTask set
-     * # Task.notifyAll()
-     * # Task.get() (result.get()) available, Task.isDone is true
-     *
-     * Few _consumers_ should care, but internally we rely on this so that, for example, status is displayed correctly.
-     * Tests should catch most things, but be careful if you change any of the above semantics.
-     */
-
-    protected long queuedTimeUtc = -1;
-    protected long submitTimeUtc = -1;
-    protected long startTimeUtc = -1;
-    protected long endTimeUtc = -1;
-    protected Maybe<Task<?>> submittedByTask;
-
-    protected volatile Thread thread = null;
-    private volatile boolean cancelled = false;
-    /** normally a {@link ListenableFuture}, except for scheduled tasks when it may be a {@link ScheduledFuture} */
-    protected volatile Future<T> internalFuture = null;
-    
-    @Override
-    public synchronized void initInternalFuture(ListenableFuture<T> result) {
-        if (this.internalFuture != null) 
-            throw new IllegalStateException("task "+this+" is being given a result twice");
-        this.internalFuture = result;
-        notifyAll();
-    }
-
-    // metadata accessors ------------
-
-    @Override
-    public Set<Object> getTags() { return Collections.unmodifiableSet(new LinkedHashSet<Object>(tags)); }
-    
-    /** if the job is queued for submission (e.g. by another task) it can indicate that fact (and time) here;
-     * note tasks can (and often are) submitted without any queueing, in which case this value may be -1 */
-    @Override
-    public long getQueuedTimeUtc() { return queuedTimeUtc; }
-    
-    @Override
-    public long getSubmitTimeUtc() { return submitTimeUtc; }
-    
-    @Override
-    public long getStartTimeUtc() { return startTimeUtc; }
-    
-    @Override
-    public long getEndTimeUtc() { return endTimeUtc; }
-
-    @Override
-    public Future<T> getInternalFuture() { return internalFuture; }
-    
-    @Override
-    public Task<?> getSubmittedByTask() { 
-        if (submittedByTask==null) return null;
-        return submittedByTask.orNull(); 
-    }
-
-    /** the thread where the task is running, if it is running */
-    @Override
-    public Thread getThread() { return thread; }
-
-    // basic fields --------------------
-
-    @Override
-    public boolean isQueued() {
-        return (queuedTimeUtc >= 0);
-    }
-
-    @Override
-    public boolean isQueuedOrSubmitted() {
-        return isQueued() || isSubmitted();
-    }
-
-    @Override
-    public boolean isQueuedAndNotSubmitted() {
-        return isQueued() && (!isSubmitted());
-    }
-
-    @Override
-    public boolean isSubmitted() {
-        return submitTimeUtc >= 0;
-    }
-
-    @Override
-    public boolean isBegun() {
-        return startTimeUtc >= 0;
-    }
-
-    /** marks the task as queued for execution */
-    @Override
-    public void markQueued() {
-        if (queuedTimeUtc<0)
-            queuedTimeUtc = System.currentTimeMillis();
-    }
-
-    @Override
-    public final synchronized boolean cancel() { return cancel(true); }
-
-    /** doesn't resume it, just means if something was cancelled but not submitted it could now be submitted;
-     * probably going to be removed and perhaps some mechanism for running again made available
-     * @since 0.7.0  */
-    @Beta
-    public synchronized boolean uncancel() {
-        boolean wasCancelled = cancelled;
-        cancelled = false; 
-        return wasCancelled;
-    }
-    
-    @Override
-    public synchronized boolean cancel(boolean mayInterruptIfRunning) {
-        if (isDone()) return false;
-        boolean cancel = true;
-        cancelled = true;
-        if (internalFuture!=null) { 
-            cancel = internalFuture.cancel(mayInterruptIfRunning);
-        }
-        notifyAll();
-        return cancel;
-    }
-
-    @Override
-    public boolean isCancelled() {
-        return cancelled || (internalFuture!=null && internalFuture.isCancelled());
-    }
-
-    @Override
-    public boolean isDone() {
-        // if endTime is set, result might not be completed yet, but it will be set very soon 
-        // (the two values are set close in time, result right after the endTime;
-        // but callback hooks might not see the result yet)
-        return cancelled || (internalFuture!=null && internalFuture.isDone()) || endTimeUtc>0;
-    }
-
-    /**
-     * Returns true if the task has had an error.
-     *
-     * Only true if calling {@link #get()} will throw an exception when it completes (including cancel).
-     * Implementations may set this true before completion if they have that insight, or
-     * (the default) they may compute it lazily after completion (returning false before completion).
-     */
-    @Override
-    public boolean isError() {
-        if (!isDone()) return false;
-        if (isCancelled()) return true;
-        try {
-            get();
-            return false;
-        } catch (Throwable t) {
-            return true;
-        }
-    }
-
-    // future value --------------------
-
-    @Override
-    public T get() throws InterruptedException, ExecutionException {
-        try {
-            if (!isDone())
-                Tasks.setBlockingTask(this);
-            blockUntilStarted();
-            return internalFuture.get();
-        } finally {
-            Tasks.resetBlockingTask();
-        }
-    }
-
-    @Override
-    public T getUnchecked() {
-        try {
-            return get();
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    
-    @Override
-    public synchronized void blockUntilStarted() {
-        blockUntilStarted(null);
-    }
-    
-    @Override
-    public synchronized boolean blockUntilStarted(Duration timeout) {
-        Long endTime = timeout==null ? null : System.currentTimeMillis() + timeout.toMillisecondsRoundingUp();
-        while (true) {
-            if (cancelled) throw new CancellationException();
-            if (internalFuture==null)
-                try {
-                    if (timeout==null) {
-                        wait();
-                    } else {
-                        long remaining = endTime - System.currentTimeMillis();
-                        if (remaining>0)
-                            wait(remaining);
-                        else
-                            return false;
-                    }
-                } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
-                    Throwables.propagate(e);
-                }
-            if (internalFuture!=null) return true;
-        }
-    }
-
-    @Override
-    public void blockUntilEnded() {
-        blockUntilEnded(null);
-    }
-    
-    @Override
-    public boolean blockUntilEnded(Duration timeout) {
-        Long endTime = timeout==null ? null : System.currentTimeMillis() + timeout.toMillisecondsRoundingUp();
-        try { 
-            boolean started = blockUntilStarted(timeout);
-            if (!started) return false;
-            if (timeout==null) {
-                internalFuture.get();
-            } else {
-                long remaining = endTime - System.currentTimeMillis();
-                if (remaining>0)
-                    internalFuture.get(remaining, TimeUnit.MILLISECONDS);
-            }
-            return isDone();
-        } catch (Throwable t) {
-            Exceptions.propagateIfFatal(t);
-            if (!(t instanceof TimeoutException) && log.isDebugEnabled())
-                log.debug("call from "+Thread.currentThread()+", blocking until '"+this+"' finishes, ended with error: "+t);
-            return isDone(); 
-        }
-    }
-
-    @Override
-    public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
-        return get(new Duration(timeout, unit));
-    }
-    
-    @Override
-    public T get(Duration duration) throws InterruptedException, ExecutionException, TimeoutException {
-        long start = System.currentTimeMillis();
-        Long end  = duration==null ? null : start + duration.toMillisecondsRoundingUp();
-        while (end==null || end > System.currentTimeMillis()) {
-            if (cancelled) throw new CancellationException();
-            if (internalFuture == null) {
-                synchronized (this) {
-                    long remaining = end - System.currentTimeMillis();
-                    if (internalFuture==null && remaining>0)
-                        wait(remaining);
-                }
-            }
-            if (internalFuture != null) break;
-        }
-        Long remaining = end==null ? null : end -  System.currentTimeMillis();
-        if (isDone()) {
-            return internalFuture.get(1, TimeUnit.MILLISECONDS);
-        } else if (remaining == null) {
-            return internalFuture.get();
-        } else if (remaining > 0) {
-            return internalFuture.get(remaining, TimeUnit.MILLISECONDS);
-        } else {
-            throw new TimeoutException();
-        }
-    }
-
-    @Override
-    public T getUnchecked(Duration duration) {
-        try {
-            return get(duration);
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    
-    // ------------------ status ---------------------------
-    
-    /**
-     * Returns a brief status string
-     *
-     * Plain-text format. Reported status if there is one, otherwise state which will be one of:
-     * <ul>
-     * <li>Not submitted
-     * <li>Submitted for execution
-     * <li>Ended by error
-     * <li>Ended by cancellation
-     * <li>Ended normally
-     * <li>Running
-     * <li>Waiting
-     * </ul>
-     */
-    @Override
-    public String getStatusSummary() {
-        return getStatusString(0);
-    }
-
-    /**
-     * Returns detailed status, suitable for a hover
-     *
-     * Plain-text format, with new-lines (and sometimes extra info) if multiline enabled.
-     */
-    @Override
-    public String getStatusDetail(boolean multiline) {
-        return getStatusString(multiline?2:1);
-    }
-
-    /**
-     * This method is useful for callers to see the status of a task.
-     *
-     * Also for developers to see best practices for examining status fields etc
-     *
-     * @param verbosity 0 = brief, 1 = one-line with some detail, 2 = lots of detail
-     */
-    protected String getStatusString(int verbosity) {
-//        Thread t = getThread();
-        String rv;
-        if (submitTimeUtc <= 0) rv = "Not submitted";
-        else if (!isCancelled() && startTimeUtc <= 0) {
-            rv = "Submitted for execution";
-            if (verbosity>0) {
-                long elapsed = System.currentTimeMillis() - submitTimeUtc;
-                rv += " "+Time.makeTimeStringRoundedSince(elapsed)+" ago";
-            }
-            if (verbosity >= 2 && getExtraStatusText()!=null) {
-                rv += "\n\n"+getExtraStatusText();
-            }
-        } else if (isDone()) {
-            long elapsed = endTimeUtc - submitTimeUtc;
-            String duration = Time.makeTimeStringRounded(elapsed);
-            if (isCancelled()) {
-                rv = "Cancelled";
-                if (verbosity >= 1) rv+=" after "+duration;
-                
-                if (verbosity >= 2 && getExtraStatusText()!=null) {
-                    rv += "\n\n"+getExtraStatusText();
-                }
-            } else if (isError()) {
-                rv = "Failed";
-                if (verbosity >= 1) {
-                    rv += " after "+duration;
-                    Throwable error = Tasks.getError(this);
-
-                    if (verbosity >= 2 && getExtraStatusText()!=null) {
-                        rv += "\n\n"+getExtraStatusText();
-                    }
-                    
-                    //remove outer ExecException which is reported by the get(), we want the exception the task threw
-                    while (error instanceof ExecutionException) error = error.getCause();
-                    String errorMessage = Exceptions.collapseText(error);
-
-                    if (verbosity == 1) rv += ": "+abbreviate(errorMessage);
-                    if (verbosity >= 2) {
-                        rv += ": "+errorMessage;
-                        StringWriter sw = new StringWriter();
-                        ((Throwable)error).printStackTrace(new PrintWriter(sw));
-                        rv += "\n\n"+sw.getBuffer();
-                    }
-                }
-            } else {
-                rv = "Completed";
-                if (verbosity>=1) {
-                    if (verbosity==1) {
-                        try {
-                            Object v = get();
-                            rv += ", " +(v==null ? "no return value (null)" : "result: "+abbreviate(v.toString()));
-                        } catch (Exception e) {
-                            rv += ", but error accessing result ["+e+"]"; //shouldn't happen
-                        }
-                    } else {
-                        rv += " after "+duration;
-                        try {
-                            Object v = get();
-                            rv += "\n\n" + (v==null ? "No return value (null)" : "Result: "+v);
-                        } catch (Exception e) {
-                            rv += " at first\n" +
-                                    "Error accessing result ["+e+"]"; //shouldn't happen
-                        }
-                        if (verbosity >= 2 && getExtraStatusText()!=null) {
-                            rv += "\n\n"+getExtraStatusText();
-                        }
-                    }
-                }
-            }
-        } else {
-            rv = getActiveTaskStatusString(verbosity);
-        }
-        return rv;
-    }
-    
-    private static String abbreviate(String s) {
-        s = Strings.getFirstLine(s);
-        if (s.length()>255) s = s.substring(0, 252)+ "...";
-        return s;
-    }
-
-    protected String getActiveTaskStatusString(int verbosity) {
-        String rv = "";
-        Thread t = getThread();
-    
-        // Normally, it's not possible for thread==null as we were started and not ended
-        
-        // However, there is a race where the task starts sand completes between the calls to getThread()
-        // at the start of the method and this call to getThread(), so both return null even though
-        // the intermediate checks returned started==true isDone()==false.
-        if (t == null) {
-            if (isDone()) {
-                return getStatusString(verbosity);
-            } else {
-                //should only happen for repeating task which is not active
-                return "Sleeping";
-            }
-        }
-
-        ThreadInfo ti = ManagementFactory.getThreadMXBean().getThreadInfo(t.getId(), (verbosity<=0 ? 0 : verbosity==1 ? 1 : Integer.MAX_VALUE));
-        if (getThread()==null)
-            //thread might have moved on to a new task; if so, recompute (it should now say "done")
-            return getStatusString(verbosity);
-        
-        if (verbosity >= 1 && Strings.isNonBlank(blockingDetails)) {
-            if (verbosity==1)
-                // short status string will just show blocking details
-                return blockingDetails;
-            //otherwise show the blocking details, then a new line, then additional information
-            rv = blockingDetails + "\n\n";
-        }
-        
-        if (verbosity >= 1 && blockingTask!=null) {
-            if (verbosity==1)
-                // short status string will just show blocking details
-                return "Waiting on "+blockingTask;
-            //otherwise show the blocking details, then a new line, then additional information
-            rv = "Waiting on "+blockingTask + "\n\n";
-        }
-
-        if (verbosity>=2) {
-            if (getExtraStatusText()!=null) {
-                rv += getExtraStatusText()+"\n\n";
-            }
-            
-            rv += ""+toString()+"\n";
-            if (submittedByTask!=null) {
-                rv += "Submitted by "+submittedByTask+"\n";
-            }
-
-            if (this instanceof HasTaskChildren) {
-                // list children tasks for compound tasks
-                try {
-                    Iterable<Task<?>> childrenTasks = ((HasTaskChildren)this).getChildren();
-                    if (childrenTasks.iterator().hasNext()) {
-                        rv += "Children:\n";
-                        for (Task<?> child: childrenTasks) {
-                            rv += "  "+child+": "+child.getStatusDetail(false)+"\n";
-                        }
-                    }
-                } catch (ConcurrentModificationException exc) {
-                    rv += "  (children not available - currently being modified)\n";
-                }
-            }
-            rv += "\n";
-        }
-        
-        LockInfo lock = ti.getLockInfo();
-        rv += "In progress";
-        if (verbosity>=1) {
-            if (lock==null && ti.getThreadState()==Thread.State.RUNNABLE) {
-                //not blocked
-                if (ti.isSuspended()) {
-                    // when does this happen?
-                    rv += ", thread suspended";
-                } else {
-                    if (verbosity >= 2) rv += " ("+ti.getThreadState()+")";
-                }
-            } else {
-                rv +=", thread waiting ";
-                if (ti.getThreadState() == Thread.State.BLOCKED) {
-                    rv += "(mutex) on "+lookup(lock);
-                    //TODO could say who holds it
-                } else if (ti.getThreadState() == Thread.State.WAITING) {
-                    rv += "(notify) on "+lookup(lock);
-                } else if (ti.getThreadState() == Thread.State.TIMED_WAITING) {
-                    rv += "(timed) on "+lookup(lock);
-                } else {
-                    rv = "("+ti.getThreadState()+") on "+lookup(lock);
-                }
-            }
-        }
-        if (verbosity>=2) {
-            StackTraceElement[] st = ti.getStackTrace();
-            st = brooklyn.util.javalang.StackTraceSimplifier.cleanStackTrace(st);
-            if (st!=null && st.length>0)
-                rv += "\n" +"At: "+st[0];
-            for (int ii=1; ii<st.length; ii++) {
-                rv += "\n" +"    "+st[ii];
-            }
-        }
-        return rv;
-    }
-    
-    protected String lookup(LockInfo info) {
-        return info!=null ? ""+info : "unknown (sleep)";
-    }
-
-    @Override
-    public String getDisplayName() {
-        return displayName;
-    }
-
-    @Override
-    public String getDescription() {
-        return description;
-    }
-
-    
-    /** allows a task user to specify why a task is blocked; for use immediately before a blocking/wait,
-     * and typically cleared immediately afterwards; referenced by management api to inspect a task
-     * which is blocking
-     */
-    @Override
-    public String setBlockingDetails(String blockingDetails) {
-        String old = this.blockingDetails;
-        this.blockingDetails = blockingDetails;
-        return old;
-    }
-    
-    @Override
-    public Task<?> setBlockingTask(Task<?> blockingTask) {
-        Task<?> old = this.blockingTask;
-        this.blockingTask = blockingTask;
-        return old;
-    }
-    
-    @Override
-    public void resetBlockingDetails() {
-        this.blockingDetails = null;
-    }
-    
-    @Override
-    public void resetBlockingTask() {
-        this.blockingTask = null;
-    }
-
-    /** returns a textual message giving details while the task is blocked */
-    @Override
-    public String getBlockingDetails() {
-        return blockingDetails;
-    }
-    
-    /** returns a task that this task is blocked on */
-    @Override
-    public Task<?> getBlockingTask() {
-        return blockingTask;
-    }
-    
-    @Override
-    public void setExtraStatusText(Object extraStatus) {
-        this.extraStatusText = extraStatus;
-    }
-    
-    @Override
-    public Object getExtraStatusText() {
-        return extraStatusText;
-    }
-
-    // ---- add a way to warn if task is not run
-    
-    public interface TaskFinalizer {
-        public void onTaskFinalization(Task<?> t);
-    }
-
-    public static final TaskFinalizer WARN_IF_NOT_RUN = new TaskFinalizer() {
-        @Override
-        public void onTaskFinalization(Task<?> t) {
-            if (!Tasks.isAncestorCancelled(t) && !t.isSubmitted()) {
-                log.warn(t+" was never submitted; did the code create it and forget to run it? ('cancel' the task to suppress this message)");
-                log.debug("Detail of unsubmitted task "+t+":\n"+t.getStatusDetail(true));
-                return;
-            }
-            if (!t.isDone()) {
-                // shouldn't happen
-                // TODO But does happen if management context was terminated (e.g. running test suite).
-                //      Should check if Execution Manager is running, and only log if it was not terminated?
-                log.warn("Task "+t+" is being finalized before completion");
-                return;
-            }
-        }
-    };
-
-    public static final TaskFinalizer NO_OP = new TaskFinalizer() {
-        @Override
-        public void onTaskFinalization(Task<?> t) {
-        }
-    };
-    
-    public void ignoreIfNotRun() {
-        setFinalizer(NO_OP);
-    }
-    
-    public void setFinalizer(TaskFinalizer f) {
-        TaskFinalizer finalizer = Tasks.tag(this, TaskFinalizer.class, false);
-        if (finalizer!=null && finalizer!=f)
-            throw new IllegalStateException("Cannot apply multiple finalizers");
-        if (isDone())
-            throw new IllegalStateException("Finalizer cannot be set on task "+this+" after it is finished");
-        tags.add(f);
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        TaskFinalizer finalizer = Tasks.tag(this, TaskFinalizer.class, false);
-        if (finalizer==null) finalizer = WARN_IF_NOT_RUN;
-        finalizer.onTaskFinalization(this);
-    }
-    
-    public static class SubmissionErrorCatchingExecutor implements Executor {
-        final Executor target;
-        public SubmissionErrorCatchingExecutor(Executor target) {
-            this.target = target;
-        }
-        @Override
-        public void execute(Runnable command) {
-            if (isShutdown()) {
-                log.debug("Skipping execution of task callback hook "+command+" because executor is shutdown.");
-                return;
-            }
-            try {
-                target.execute(command);
-            } catch (Exception e) {
-                if (isShutdown()) {
-                    log.debug("Ignoring failed execution of task callback hook "+command+" because executor is shutdown.");
-                } else {
-                    log.warn("Execution of task callback hook "+command+" failed: "+e, e);
-                }
-            }
-        }
-        protected boolean isShutdown() {
-            return target instanceof ExecutorService && ((ExecutorService)target).isShutdown();
-        }
-    }
-    
-    @Override
-    public void addListener(Runnable listener, Executor executor) {
-        listeners.add(listener, new SubmissionErrorCatchingExecutor(executor));
-    }
-    
-    @Override
-    public void runListeners() {
-        listeners.execute();
-    }
-    
-    @Override
-    public void setEndTimeUtc(long val) {
-        endTimeUtc = val;
-    }
-    
-    @Override
-    public void setThread(Thread thread) {
-        this.thread = thread;
-    }
-    
-    @Override
-    public Callable<T> getJob() {
-        return job;
-    }
-    
-    @Override
-    public void setJob(Callable<T> job) {
-        this.job = job;
-    }
-    
-    @Override
-    public ExecutionList getListeners() {
-        return listeners;
-    }
-    
-    @Override
-    public void setSubmitTimeUtc(long val) {
-        submitTimeUtc = val;
-    }
-    
-    private static <T> Task<T> newGoneTaskFor(Task<?> task) {
-        Task<T> t = Tasks.<T>builder().dynamic(false).name(task.getDisplayName())
-            .description("Details of the original task "+task+" have been forgotten.")
-            .body(Callables.returning((T)null)).build();
-        ((BasicTask<T>)t).ignoreIfNotRun();
-        return t;
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    public void setSubmittedByTask(Task<?> task) {
-        submittedByTask = (Maybe)Maybe.softThen((Task)task, (Maybe)Maybe.of(BasicTask.newGoneTaskFor(task)));
-    }
-    
-    @Override
-    public Set<Object> getMutableTags() {
-        return tags;
-    }
-    
-    @Override
-    public void setStartTimeUtc(long val) {
-        startTimeUtc = val;
-    }
-
-    @Override
-    public void applyTagModifier(Function<Set<Object>,Void> modifier) {
-        modifier.apply(tags);
-    }
-
-    @Override
-    public Task<?> getProxyTarget() {
-        return proxyTargetTask;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/CanSetName.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/CanSetName.java b/core/src/main/java/brooklyn/util/task/CanSetName.java
deleted file mode 100644
index 760c99e..0000000
--- a/core/src/main/java/brooklyn/util/task/CanSetName.java
+++ /dev/null
@@ -1,25 +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 brooklyn.util.task;
-
-public interface CanSetName {
-
-    void setName(String name);
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/CompoundTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/CompoundTask.java b/core/src/main/java/brooklyn/util/task/CompoundTask.java
deleted file mode 100644
index e33120c..0000000
--- a/core/src/main/java/brooklyn/util/task/CompoundTask.java
+++ /dev/null
@@ -1,131 +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 brooklyn.util.task;
-
-import groovy.lang.Closure;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-
-import org.apache.brooklyn.api.management.HasTaskChildren;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskAdaptable;
-import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.BrooklynTaskTags;
-import brooklyn.util.collections.MutableMap;
-
-
-/**
- * A {@link Task} that is comprised of other units of work: possibly a heterogeneous mix of {@link Task},
- * {@link Runnable}, {@link Callable} and {@link Closure} instances.
- * 
- * This class holds the collection of child tasks, but subclasses have the responsibility of executing them in a
- * sensible manner by implementing the abstract {@link #runJobs} method.
- */
-public abstract class CompoundTask<T> extends BasicTask<List<T>> implements HasTaskChildren {
-
-    @SuppressWarnings("unused")
-    private static final Logger log = LoggerFactory.getLogger(CompoundTask.class);
-                
-    protected final List<Task<? extends T>> children;
-    protected final List<Object> result;
-    
-    /**
-     * Constructs a new compound task containing the specified units of work.
-     * 
-     * @param jobs  A potentially heterogeneous mixture of {@link Runnable}, {@link Callable}, {@link Closure} and {@link Task} can be provided. 
-     * @throws IllegalArgumentException if any of the passed child jobs is not one of the above types 
-     */
-    public CompoundTask(Object... jobs) {
-        this( Arrays.asList(jobs) );
-    }
-    
-    /**
-     * Constructs a new compound task containing the specified units of work.
-     * 
-     * @param jobs  A potentially heterogeneous mixture of {@link Runnable}, {@link Callable}, {@link Closure} and {@link Task} can be provided. 
-     * @throws IllegalArgumentException if any of the passed child jobs is not one of the above types 
-     */
-    public CompoundTask(Collection<?> jobs) {
-        this(MutableMap.of("tag", "compound"), jobs);
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public CompoundTask(Map<String,?> flags, Collection<?> jobs) {
-        super(flags);
-        super.job = new Callable<List<T>>() {
-            @Override public List<T> call() throws Exception {
-                return runJobs();
-            }
-        };
-        
-        this.result = new ArrayList<Object>(jobs.size());
-        this.children = new ArrayList<Task<? extends T>>(jobs.size());
-        for (Object job : jobs) {
-            Task subtask;
-            if (job instanceof TaskAdaptable) { subtask = ((TaskAdaptable)job).asTask(); }
-            else if (job instanceof Closure)  { subtask = new BasicTask<T>((Closure) job); }
-            else if (job instanceof Callable) { subtask = new BasicTask<T>((Callable) job); }
-            else if (job instanceof Runnable) { subtask = new BasicTask<T>((Runnable) job); }
-            
-            else throw new IllegalArgumentException("Invalid child "+(job == null ? null : job.getClass() + " ("+job+")")+
-                " passed to compound task; must be Runnable, Callable, Closure or Task");
-            
-            BrooklynTaskTags.addTagDynamically(subtask, ManagementContextInternal.SUB_TASK_TAG);
-            children.add(subtask);
-        }
-        
-        for (Task<?> t: getChildren()) {
-            ((TaskInternal<?>)t).markQueued();
-        }
-    }
-
-    /** return value needs to be specified by subclass; subclass should also setBlockingDetails 
-     * @throws ExecutionException 
-     * @throws InterruptedException */    
-    protected abstract List<T> runJobs() throws InterruptedException, ExecutionException;
-    
-    protected void submitIfNecessary(TaskAdaptable<?> task) {
-        if (!task.asTask().isSubmitted()) {
-            if (BasicExecutionContext.getCurrentExecutionContext() == null) {
-                throw new IllegalStateException("Compound task ("+task+") launched from "+this+" missing required execution context");
-            } else {
-                BasicExecutionContext.getCurrentExecutionContext().submit(task);
-            }
-        }
-    }
-    
-    public List<Task<? extends T>> getChildrenTyped() {
-        return children;
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public List<Task<?>> getChildren() {
-        return (List) getChildrenTyped();
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/DeferredSupplier.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/DeferredSupplier.java b/core/src/main/java/brooklyn/util/task/DeferredSupplier.java
deleted file mode 100644
index d82b3fb..0000000
--- a/core/src/main/java/brooklyn/util/task/DeferredSupplier.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 brooklyn.util.task;
-
-import com.google.common.base.Supplier;
-
-/**
- * A class that supplies objects of a single type. When used as a ConfigKey value,
- * the evaluation is deferred until getConfig() is called. The returned value will then
- * be coerced to the correct type. 
- * 
- * Subsequent calls to getConfig will result in further calls to deferredProvider.get(), 
- * rather than reusing the result. If you want to reuse the result, consider instead 
- * using a Future.
- * 
- * Note that this functionality replaces the ues of Closure in brooklyn 0.4.0, which 
- * served the same purpose.
- */
-public interface DeferredSupplier<T> extends Supplier<T> {
-    @Override
-    T get();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java b/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
deleted file mode 100644
index 455a889..0000000
--- a/core/src/main/java/brooklyn/util/task/DynamicSequentialTask.java
+++ /dev/null
@@ -1,480 +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 brooklyn.util.task;
-
-import groovy.lang.Closure;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import org.apache.brooklyn.api.management.HasTaskChildren;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskQueueingContext;
-import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.BrooklynTaskTags;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.time.CountdownTimer;
-import brooklyn.util.time.Duration;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ImmutableList;
-
-/** Represents a task whose run() method can create other tasks
- * which are run sequentially, but that sequence runs in parallel to this task
- * <p>
- * There is an optional primary job run with this task, along with multiple secondary children.
- * If any secondary task fails (assuming it isn't {@link Tasks#markInessential()} then by default
- * subsequent tasks are not submitted and the primary task fails (but no tasks are cancelled or interrupted).
- * You can change the behavior of this task with fields in {@link FailureHandlingConfig},
- * or the convenience {@link TaskQueueingContext#swallowChildrenFailures()}
- * (and {@link DynamicTasks#swallowChildrenFailures()} if you are inside the task).
- * <p>
- * This synchronizes on secondary tasks when submitting them, in case they may be manually submitted
- * and the submitter wishes to ensure it is only submitted once.
- * <p>
- * Improvements which would be nice to have:
- * <li> unqueued tasks not visible in api; would like that
- * <li> uses an extra thread (submitted as background task) to monitor the secondary jobs; would be nice to remove this,
- *      and rely on {@link BasicExecutionManager} to run the jobs sequentially (combined with fix to item above)
- * <li> would be nice to have cancel, resume, and possibly skipQueue available as operations (ideally in the REST API and GUI)   
- **/
-public class DynamicSequentialTask<T> extends BasicTask<T> implements HasTaskChildren, TaskQueueingContext {
-
-    private static final Logger log = LoggerFactory.getLogger(CompoundTask.class);
-                
-    protected final Queue<Task<?>> secondaryJobsAll = new ConcurrentLinkedQueue<Task<?>>();
-    protected final Queue<Task<?>> secondaryJobsRemaining = new ConcurrentLinkedQueue<Task<?>>();
-    protected final Object jobTransitionLock = new Object();
-    protected volatile boolean primaryStarted = false;
-    protected volatile boolean primaryFinished = false;
-    protected volatile boolean secondaryQueueAborted = false;
-    protected Thread primaryThread;
-    protected DstJob dstJob;
-    protected FailureHandlingConfig failureHandlingConfig = FailureHandlingConfig.DEFAULT;
-
-    // default values for how to handle the various failures
-    @Beta
-    public static class FailureHandlingConfig {
-        /** secondary queue runs independently of primary task (submitting and blocking on each secondary task in order), 
-         * but can set it up not to submit any more tasks if the primary fails */
-        public final boolean abortSecondaryQueueOnPrimaryFailure;
-        /** as {@link #abortSecondaryQueueOnPrimaryFailure} but controls cancelling of secondary queue*/
-        public final boolean cancelSecondariesOnPrimaryFailure;
-        /** secondary queue can continue submitting+blocking tasks even if a secondary task fails (unusual;
-         * typically handled by {@link TaskTags#markInessential(Task)} on the secondary tasks, in which case
-         * the secondary queue is never aborted */
-        public final boolean abortSecondaryQueueOnSecondaryFailure;
-        /** unsubmitted secondary tasks (ie those further in the queue) can be cancelled if a secondary task fails */
-        public final boolean cancelSecondariesOnSecondaryFailure;
-        /** whether to issue cancel against primary task if a secondary task fails */
-        public final boolean cancelPrimaryOnSecondaryFailure;
-        /** whether to fail this task if a secondary task fails */
-        public final boolean failParentOnSecondaryFailure;
-        
-        @Beta
-        public FailureHandlingConfig(
-                boolean abortSecondaryQueueOnPrimaryFailure, boolean cancelSecondariesOnPrimaryFailure,
-                boolean abortSecondaryQueueOnSecondaryFailure, boolean cancelSecondariesOnSecondaryFailure,
-                boolean cancelPrimaryOnSecondaryFailure, boolean failParentOnSecondaryFailure) {
-            this.abortSecondaryQueueOnPrimaryFailure = abortSecondaryQueueOnPrimaryFailure;
-            this.cancelSecondariesOnPrimaryFailure = cancelSecondariesOnPrimaryFailure;
-            this.abortSecondaryQueueOnSecondaryFailure = abortSecondaryQueueOnSecondaryFailure;
-            this.cancelSecondariesOnSecondaryFailure = cancelSecondariesOnSecondaryFailure;
-            this.cancelPrimaryOnSecondaryFailure = cancelPrimaryOnSecondaryFailure;
-            this.failParentOnSecondaryFailure = failParentOnSecondaryFailure;
-        }
-        
-        public static final FailureHandlingConfig DEFAULT = new FailureHandlingConfig(false, false, true, false, false, true);
-        public static final FailureHandlingConfig SWALLOWING_CHILDREN_FAILURES = new FailureHandlingConfig(false, false, false, false, false, false);
-    }
-    
-    public static class QueueAbortedException extends IllegalStateException {
-        private static final long serialVersionUID = -7569362887826818524L;
-        
-        public QueueAbortedException(String msg) {
-            super(msg);
-        }
-        public QueueAbortedException(String msg, Throwable cause) {
-            super(msg, cause);
-        }
-    }
-
-    /**
-     * Constructs a new compound task containing the specified units of work.
-     * 
-     * @param jobs  A potentially heterogeneous mixture of {@link Runnable}, {@link Callable}, {@link Closure} and {@link Task} can be provided. 
-     * @throws IllegalArgumentException if any of the passed child jobs is not one of the above types 
-     */
-    public DynamicSequentialTask() {
-        this(null);
-    }
-    
-    public DynamicSequentialTask(Callable<T> mainJob) {
-        this(MutableMap.of("tag", "compound"), mainJob);
-    }
-    
-    public DynamicSequentialTask(Map<?,?> flags, Callable<T> mainJob) {
-        super(flags);
-        this.job = dstJob = new DstJob(mainJob);
-    }
-    
-    @Override
-    public void queue(Task<?> t) {
-        synchronized (jobTransitionLock) {
-            if (primaryFinished)
-                throw new IllegalStateException("Cannot add a task to "+this+" which is already finished (trying to add "+t+")");
-            if (secondaryQueueAborted)
-                throw new QueueAbortedException("Cannot add a task to "+this+" whose queue has been aborted (trying to add "+t+")");
-            secondaryJobsAll.add(t);
-            secondaryJobsRemaining.add(t);
-            BrooklynTaskTags.addTagsDynamically(t, ManagementContextInternal.SUB_TASK_TAG);
-            ((TaskInternal<?>)t).markQueued();
-            jobTransitionLock.notifyAll();
-        }
-    }
-
-    @Override
-    public boolean cancel(boolean mayInterruptIfRunning) {
-        return cancel(mayInterruptIfRunning, mayInterruptIfRunning, true);
-    }
-    public boolean cancel(boolean mayInterruptTask, boolean interruptPrimaryThread, boolean alsoCancelChildren) {
-        if (isDone()) return false;
-        if (log.isTraceEnabled()) log.trace("cancelling {}", this);
-        boolean cancel = super.cancel(mayInterruptTask);
-        if (alsoCancelChildren) {
-            for (Task<?> t: secondaryJobsAll)
-                cancel |= t.cancel(mayInterruptTask);
-        }
-        synchronized (jobTransitionLock) {
-            if (primaryThread!=null) {
-                if (interruptPrimaryThread) {
-                    if (log.isTraceEnabled()) log.trace("cancelling {} - interrupting", this);
-                    primaryThread.interrupt();
-                }
-                cancel = true;
-            }
-        }
-        return cancel;
-    }
-    
-    @Override
-    public synchronized boolean uncancel() {
-        secondaryQueueAborted = false;
-        return super.uncancel();
-    }
-
-    @Override
-    public Iterable<Task<?>> getChildren() {
-        return Collections.unmodifiableCollection(secondaryJobsAll);
-    }
-    
-    /** submits the indicated task for execution in the current execution context, and returns immediately */
-    protected void submitBackgroundInheritingContext(Task<?> task) {
-        BasicExecutionContext ec = BasicExecutionContext.getCurrentExecutionContext();
-        if (log.isTraceEnabled()) {
-            log.trace("task {} - submitting background task {} ({})", new Object[] { Tasks.current(), task, ec });
-        }
-        if (ec==null) {
-            String message = Tasks.current()!=null ?
-                    // user forgot ExecContext:
-                        "Task "+this+" submitting background task requires an ExecutionContext (an ExecutionManager is not enough): submitting "+task+" in "+Tasks.current()
-                    : // should not happen:
-                        "Cannot submit tasks inside DST when not in a task : submitting "+task+" in "+this;
-            log.warn(message+" (rethrowing)");
-            throw new IllegalStateException(message);
-        }
-        synchronized (task) {
-            if (task.isSubmitted()) {
-                if (log.isTraceEnabled()) {
-                    log.trace("DST "+this+" skipping submission of child "+task+" because it is already submitted");
-                }
-            } else {
-                try {
-                    ec.submit(task);
-                } catch (Exception e) {
-                    Exceptions.propagateIfFatal(e);
-                    // Give some context when the submit fails (happens when the target is already unmanaged)
-                    throw new IllegalStateException("Failure submitting task "+task+" in "+this+": "+e.getMessage(), e);
-                }
-            }
-        }
-    }
-
-    public void setFailureHandlingConfig(FailureHandlingConfig failureHandlingConfig) {
-        this.failureHandlingConfig = failureHandlingConfig;
-    }
-    @Override
-    public void swallowChildrenFailures() {
-        setFailureHandlingConfig(FailureHandlingConfig.SWALLOWING_CHILDREN_FAILURES);
-    }
-    
-    protected class DstJob implements Callable<T> {
-        protected Callable<T> primaryJob;
-        /** currently executing (or just completed) secondary task, or null if none;
-         * with jobTransitionLock notified on change and completion */
-        protected volatile Task<?> currentSecondary = null;
-        protected volatile boolean finishedSecondaries = false;
-        
-        public DstJob(Callable<T> mainJob) {
-            this.primaryJob = mainJob;
-        }
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public T call() throws Exception {
-
-            synchronized (jobTransitionLock) {
-                primaryStarted = true;
-                primaryThread = Thread.currentThread();
-                for (Task<?> t: secondaryJobsAll)
-                    ((TaskInternal<?>)t).markQueued();
-            }
-            // TODO overkill having a thread/task for this, but it works
-            // optimisation would either use newTaskEndCallback property on task to submit
-            // or use some kind of single threaded executor for the queued tasks
-            Task<List<Object>> secondaryJobMaster = Tasks.<List<Object>>builder().dynamic(false)
-                    .name("DST manager (internal)")
-                    // TODO marking it transient helps it be GC'd sooner, 
-                    // but ideally we wouldn't have this,
-                    // or else it would be a child
-                    .tag(BrooklynTaskTags.TRANSIENT_TASK_TAG)
-                    .body(new Callable<List<Object>>() {
-
-                @Override
-                public List<Object> call() throws Exception {
-                    List<Object> result = new ArrayList<Object>();
-                    try { 
-                        while (!secondaryQueueAborted && (!primaryFinished || !secondaryJobsRemaining.isEmpty())) {
-                            synchronized (jobTransitionLock) {
-                                if (!primaryFinished && secondaryJobsRemaining.isEmpty()) {
-                                    currentSecondary = null;
-                                    jobTransitionLock.wait(1000);
-                                }
-                            }
-                            @SuppressWarnings("rawtypes")
-                            Task secondaryJob = secondaryJobsRemaining.poll();
-                            if (secondaryJob != null) {
-                                synchronized (jobTransitionLock) {
-                                    currentSecondary = secondaryJob;
-                                    submitBackgroundInheritingContext(secondaryJob);
-                                    jobTransitionLock.notifyAll();
-                                }
-                                try {
-                                    result.add(secondaryJob.get());
-                                } catch (Exception e) {
-                                    if (TaskTags.isInessential(secondaryJob)) {
-                                        result.add(Tasks.getError(secondaryJob));
-                                        if (log.isDebugEnabled())
-                                            log.debug("Secondary job queue for "+DynamicSequentialTask.this+" ignoring error in inessential task "+secondaryJob+": "+e);
-                                    } else {
-                                        if (failureHandlingConfig.cancelSecondariesOnSecondaryFailure) {
-                                            if (log.isDebugEnabled())
-                                                log.debug("Secondary job queue for "+DynamicSequentialTask.this+" cancelling "+secondaryJobsRemaining.size()+" remaining, due to error in task "+secondaryJob+": "+e);
-                                            synchronized (jobTransitionLock) {
-                                                for (Task<?> t: secondaryJobsRemaining)
-                                                    t.cancel(true);
-                                                jobTransitionLock.notifyAll();
-                                            }
-                                        }
-                                        
-                                        if (failureHandlingConfig.abortSecondaryQueueOnSecondaryFailure) {
-                                            if (log.isDebugEnabled())
-                                                log.debug("Aborting secondary job queue for "+DynamicSequentialTask.this+" due to error in child task "+secondaryJob+" ("+e+", being rethrown)");
-                                            secondaryQueueAborted = true;
-                                            throw e;
-                                        }
-
-                                        if (!primaryFinished && failureHandlingConfig.cancelPrimaryOnSecondaryFailure) {
-                                            cancel(true, false, false);
-                                        }
-                                        
-                                        result.add(Tasks.getError(secondaryJob));
-                                        if (log.isDebugEnabled())
-                                            log.debug("Secondary job queue for "+DynamicSequentialTask.this+" continuing in presence of error in child task "+secondaryJob+" ("+e+", being remembered)");
-                                    }
-                                }
-                            }
-                        }
-                    } finally {
-                        synchronized (jobTransitionLock) {
-                            currentSecondary = null;
-                            finishedSecondaries = true;
-                            jobTransitionLock.notifyAll();
-                        }
-                    }
-                    return result;
-                }
-            }).build();
-            ((BasicTask<?>)secondaryJobMaster).proxyTargetTask = DynamicSequentialTask.this;
-            
-            submitBackgroundInheritingContext(secondaryJobMaster);
-            
-            T result = null;
-            Throwable error = null;
-            Throwable uninterestingSelfError = null;
-            boolean errorIsFromChild = false;
-            try {
-                if (log.isTraceEnabled()) log.trace("calling primary job for {}", this);
-                if (primaryJob!=null) result = primaryJob.call();
-            } catch (Throwable selfException) {
-                Exceptions.propagateIfFatal(selfException);
-                if (Exceptions.getFirstThrowableOfType(selfException, QueueAbortedException.class) != null) {
-                    // Error was caused by the task already having failed, and this thread calling queue() to try
-                    // to queue more work. The underlying cause will be much more interesting.
-                    // Without this special catch, we record error = "Cannot add a task to ... whose queue has been aborted",
-                    // which gets propagated instead of the more interesting child exception.
-                    uninterestingSelfError = selfException;
-                } else {
-                    error = selfException;
-                    errorIsFromChild = false;
-                }
-                if (failureHandlingConfig.abortSecondaryQueueOnPrimaryFailure) {
-                    if (log.isDebugEnabled())
-                        log.debug("Secondary job queue for "+DynamicSequentialTask.this+" aborting with "+secondaryJobsRemaining.size()+" remaining, due to error in primary task: "+selfException);
-                    secondaryQueueAborted = true;
-                }
-                if (failureHandlingConfig.cancelSecondariesOnPrimaryFailure) {
-                    if (log.isDebugEnabled())
-                        log.debug(DynamicSequentialTask.this+" cancelling "+secondaryJobsRemaining.size()+" remaining, due to error in primary task: "+selfException);
-                    synchronized (jobTransitionLock) {
-                        for (Task<?> t: secondaryJobsRemaining)
-                            t.cancel(true);
-                        // do this early to prevent additions; and note we notify very soon below, so not notify is help off until below
-                        primaryThread = null;
-                        primaryFinished = true;
-                    }
-                }
-            } finally {
-                try {
-                    if (log.isTraceEnabled()) log.trace("cleaning up for {}", this);
-                    synchronized (jobTransitionLock) {
-                        // semaphore might be nicer here (aled notes as it is this is a little hard to read)
-                        primaryThread = null;
-                        primaryFinished = true;
-                        jobTransitionLock.notifyAll();
-                    }
-                    if (!isCancelled() && !Thread.currentThread().isInterrupted()) {
-                        if (log.isTraceEnabled()) log.trace("waiting for secondaries for {}", this);
-                        // wait on tasks sequentially so that blocking information is more interesting
-                        DynamicTasks.waitForLast();
-                        List<Object> result2 = secondaryJobMaster.get();
-                        try {
-                            if (primaryJob==null) result = (T)result2;
-                        } catch (ClassCastException e) { /* ignore class cast exception; leave the result as null */ }
-                    }
-                } catch (Throwable childException) {
-                    Exceptions.propagateIfFatal(childException);
-                    if (error==null) {
-                        error = childException;
-                        errorIsFromChild = true;
-                    } else {
-                        if (log.isDebugEnabled()) log.debug("Parent task "+this+" ignoring child error ("+childException+") in presence of our own error ("+error+")");
-                    }
-                }
-            }
-            if (error!=null) {
-                handleException(error, errorIsFromChild);
-            }
-            if (uninterestingSelfError != null) {
-                handleException(uninterestingSelfError, false);
-            }
-            return result;
-        }
-        
-        @Override
-        public String toString() {
-            return "DstJob:"+DynamicSequentialTask.this.getId();
-        }
-
-        /** waits for this job to complete, or the given time to elapse */
-        public void join(boolean includePrimary, Duration optionalTimeout) throws InterruptedException {
-            CountdownTimer timeLeft = optionalTimeout!=null ? CountdownTimer.newInstanceStarted(optionalTimeout) : null;
-            while (true) {
-                Task<?> cs;
-                Duration remaining;
-                synchronized (jobTransitionLock) {
-                    cs = currentSecondary;
-                    if (finishedSecondaries) return;
-                    remaining = timeLeft==null ? Duration.ONE_SECOND : timeLeft.getDurationRemaining();
-                    if (!remaining.isPositive()) return;
-                    if (cs==null) {
-                        if (!includePrimary && secondaryJobsRemaining.isEmpty()) return;
-                        // parent still running, no children though
-                        Tasks.setBlockingTask(DynamicSequentialTask.this);
-                        jobTransitionLock.wait(remaining.toMilliseconds());
-                        Tasks.resetBlockingDetails();
-                    }
-                }
-                if (cs!=null) {
-                    Tasks.setBlockingTask(cs);
-                    cs.blockUntilEnded(remaining);
-                    Tasks.resetBlockingDetails();
-                }
-            }
-        }
-    }
-
-    @Override
-    public List<Task<?>> getQueue() {
-        return ImmutableList.copyOf(secondaryJobsAll);
-    }
-
-    public void handleException(Throwable throwable, boolean fromChild) throws Exception {
-        Exceptions.propagateIfFatal(throwable);
-        if (fromChild && !failureHandlingConfig.failParentOnSecondaryFailure) {
-            log.debug("Parent task "+this+" swallowing child error: "+throwable);
-            return;
-        }
-        handleException(throwable);
-    }
-    public void handleException(Throwable throwable) throws Exception { 
-        Exceptions.propagateIfFatal(throwable);
-        if (throwable instanceof Exception) {
-            // allow checked exceptions to be passed through
-            throw (Exception)throwable;
-        }
-        throw Exceptions.propagate(throwable);
-    }
-
-    @Override
-    public void drain(Duration optionalTimeout, boolean includePrimary, boolean throwFirstError) {
-        try {
-            dstJob.join(includePrimary, optionalTimeout);
-        } catch (InterruptedException e) {
-            throw Exceptions.propagate(e);
-        }
-        if (throwFirstError) {
-            if (isError()) 
-                getUnchecked();
-            for (Task<?> t: getQueue())
-                if (t.isError() && !TaskTags.isInessential(t))
-                    t.getUnchecked();
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/DynamicTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/DynamicTasks.java b/core/src/main/java/brooklyn/util/task/DynamicTasks.java
deleted file mode 100644
index 9d552c6..0000000
--- a/core/src/main/java/brooklyn/util/task/DynamicTasks.java
+++ /dev/null
@@ -1,337 +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 brooklyn.util.task;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.management.ExecutionContext;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskAdaptable;
-import org.apache.brooklyn.api.management.TaskFactory;
-import org.apache.brooklyn.api.management.TaskQueueingContext;
-import org.apache.brooklyn.api.management.TaskWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.EntityInternal;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.time.Duration;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterables;
-
-/** 
- * Contains static methods which detect and use the current {@link TaskQueueingContext} to execute tasks.
- * 
- * @since 0.6.0
- */
-@Beta
-public class DynamicTasks {
-
-    private static final Logger log = LoggerFactory.getLogger(DynamicTasks.class);
-    private static final ThreadLocal<TaskQueueingContext> taskQueueingContext = new ThreadLocal<TaskQueueingContext>();
-    
-    public static void setTaskQueueingContext(TaskQueueingContext newTaskQC) {
-        taskQueueingContext.set(newTaskQC);
-    }
-    
-    public static TaskQueueingContext getThreadTaskQueuingContext() {
-        return taskQueueingContext.get();
-    }
-    
-    public static TaskQueueingContext getTaskQueuingContext() {
-        TaskQueueingContext adder = getThreadTaskQueuingContext();
-        if (adder!=null) return adder;
-        Task<?> t = Tasks.current();
-        if (t instanceof TaskQueueingContext) return (TaskQueueingContext) t;
-        return null;
-    }
-
-    
-    public static void removeTaskQueueingContext() {
-        taskQueueingContext.remove();
-    }
-
-    public static class TaskQueueingResult<T> implements TaskWrapper<T> {
-        private final Task<T> task;
-        private final boolean wasQueued;
-        private ExecutionContext execContext = null;
-        
-        private TaskQueueingResult(TaskAdaptable<T> task, boolean wasQueued) {
-            this.task = task.asTask();
-            this.wasQueued = wasQueued;
-        }
-        @Override
-        public Task<T> asTask() {
-            return task;
-        }
-        @Override
-        public Task<T> getTask() {
-            return task;
-        }
-        /** returns true if the task was queued */
-        public boolean wasQueued() {
-            return wasQueued;
-        }
-        /** returns true if the task either is currently queued or has been submitted */
-        public boolean isQueuedOrSubmitted() {
-            return wasQueued || Tasks.isQueuedOrSubmitted(task);
-        }
-        /** specifies an execContext to use if the task has to be explicitly submitted;
-         * if omitted it will attempt to find one based on the current thread's context */
-        public TaskQueueingResult<T> executionContext(ExecutionContext execContext) {
-            this.execContext = execContext;
-            return this;
-        }
-        /** as {@link #executionContext(ExecutionContext)} but inferring from the entity */
-        public TaskQueueingResult<T> executionContext(Entity entity) {
-            this.execContext = ((EntityInternal)entity).getManagementSupport().getExecutionContext();
-            return this;
-        }
-        private boolean orSubmitInternal() {
-            if (!wasQueued()) {
-                if (isQueuedOrSubmitted()) {
-                    log.warn("Redundant call to execute "+getTask()+"; skipping");
-                    return false;
-                } else {
-                    ExecutionContext ec = execContext;
-                    if (ec==null)
-                        ec = BasicExecutionContext.getCurrentExecutionContext();
-                    if (ec==null)
-                        throw new IllegalStateException("Cannot execute "+getTask()+" without an execution context; ensure caller is in an ExecutionContext");
-                    ec.submit(getTask());
-                    return true;
-                }
-            } else {
-                return false;
-            }
-        }
-        /** causes the task to be submitted (asynchronously) if it hasn't already been,
-         * requiring an entity execution context (will try to find a default if not set) */
-        public TaskQueueingResult<T> orSubmitAsync() {
-            orSubmitInternal();
-            return this;
-        }
-        /** convenience for setting {@link #executionContext(ExecutionContext)} then submitting async */
-        public TaskQueueingResult<T> orSubmitAsync(Entity entity) {
-            executionContext(entity);
-            return orSubmitAsync();
-        }
-        /** causes the task to be submitted *synchronously* if it hasn't already been submitted;
-         * useful in contexts such as libraries where callers may be either on a legacy call path 
-         * (which assumes all commands complete immediately);
-         * requiring an entity execution context (will try to find a default if not set) */
-        public TaskQueueingResult<T> orSubmitAndBlock() {
-            if (orSubmitInternal()) task.getUnchecked();
-            return this;
-        }
-        /** convenience for setting {@link #executionContext(ExecutionContext)} then submitting blocking */
-        public TaskQueueingResult<T> orSubmitAndBlock(Entity entity) {
-            executionContext(entity);
-            return orSubmitAndBlock();
-        }
-        /** blocks for the task to be completed
-         * <p>
-         * needed in any context where subsequent commands assume the task has completed.
-         * not needed in a context where the task is simply being built up and queued.
-         * <p>
-         * throws if there are any errors
-         */
-        public T andWaitForSuccess() {
-            return task.getUnchecked();
-        }
-        public void orCancel() {
-            if (!wasQueued()) {
-                task.cancel(false);
-            }
-        }
-    }
-    
-    /**
-     * Tries to add the task to the current addition context if there is one, otherwise does nothing.
-     * <p/>
-     * Call {@link TaskQueueingResult#orSubmitAsync() orSubmitAsync()} on the returned
-     * {@link TaskQueueingResult TaskQueueingResult} to handle execution of tasks in a
-     * {@link BasicExecutionContext}.
-     */
-    public static <T> TaskQueueingResult<T> queueIfPossible(TaskAdaptable<T> task) {
-        TaskQueueingContext adder = getTaskQueuingContext();
-        boolean result = false;
-        if (adder!=null)
-            result = Tasks.tryQueueing(adder, task);
-        return new TaskQueueingResult<T>(task, result);
-    }
-
-    /** @see #queueIfPossible(TaskAdaptable) */
-    public static <T> TaskQueueingResult<T> queueIfPossible(TaskFactory<? extends TaskAdaptable<T>> task) {
-        return queueIfPossible(task.newTask());
-    }
-
-    /** adds the given task to the nearest task addition context,
-     * either set as a thread-local, or in the current task, or the submitter of the task, etc
-     * <p>
-     * throws if it cannot add */
-    public static <T> Task<T> queueInTaskHierarchy(Task<T> task) {
-        Preconditions.checkNotNull(task, "Task to queue cannot be null");
-        Preconditions.checkState(!Tasks.isQueuedOrSubmitted(task), "Task to queue must not yet be submitted: {}", task);
-        
-        TaskQueueingContext adder = getTaskQueuingContext();
-        if (adder!=null) { 
-            if (Tasks.tryQueueing(adder, task)) {
-                log.debug("Queued task {} at context {} (no hierarchy)", task, adder);
-                return task;
-            }
-        }
-        
-        Task<?> t = Tasks.current();
-        Preconditions.checkState(t!=null || adder!=null, "No task addition context available for queueing task "+task);
-        
-        while (t!=null) {
-            if (t instanceof TaskQueueingContext) {
-                if (Tasks.tryQueueing((TaskQueueingContext)t, task)) {
-                    log.debug("Queued task {} at hierarchical context {}", task, t);
-                    return task;
-                }
-            }
-            t = t.getSubmittedByTask();
-        }
-        
-        throw new IllegalStateException("No task addition context available in current task hierarchy for adding task "+task);
-    }
-
-    /**
-     * Queues the given task.
-     * <p/>
-     * This method is only valid within a dynamic task. Use {@link #queueIfPossible(TaskAdaptable)}
-     * and {@link TaskQueueingResult#orSubmitAsync()} if the calling context is a basic task.
-     *
-     * @param task The task to queue
-     * @throws IllegalStateException if no task queueing context is available
-     * @return The queued task
-     */
-    public static <V extends TaskAdaptable<?>> V queue(V task) {
-        try {
-            Preconditions.checkNotNull(task, "Task to queue cannot be null");
-            Preconditions.checkState(!Tasks.isQueued(task), "Task to queue must not yet be queued: %s", task);
-            TaskQueueingContext adder = getTaskQueuingContext();
-            if (adder==null) {
-                throw new IllegalStateException("Task "+task+" cannot be queued here; no queueing context available");
-            }
-            adder.queue(task.asTask());
-            return task;
-        } catch (Throwable e) {
-            log.warn("Error queueing "+task+" (rethrowing): "+e);
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    /** @see #queue(org.apache.brooklyn.api.management.TaskAdaptable)  */
-    public static void queue(TaskAdaptable<?> task1, TaskAdaptable<?> task2, TaskAdaptable<?> ...tasks) {
-        queue(task1);
-        queue(task2);
-        for (TaskAdaptable<?> task: tasks) queue(task);
-    }
-
-    /** @see #queue(org.apache.brooklyn.api.management.TaskAdaptable)  */
-    public static <T extends TaskAdaptable<?>> T queue(TaskFactory<T> taskFactory) {
-        return queue(taskFactory.newTask());
-    }
-
-    /** @see #queue(org.apache.brooklyn.api.management.TaskAdaptable)  */
-    public static void queue(TaskFactory<?> task1, TaskFactory<?> task2, TaskFactory<?> ...tasks) {
-        queue(task1.newTask());
-        queue(task2.newTask());
-        for (TaskFactory<?> task: tasks) queue(task.newTask());
-    }
-
-    /** @see #queue(org.apache.brooklyn.api.management.TaskAdaptable)  */
-    public static <T> Task<T> queue(String name, Callable<T> job) {
-        return DynamicTasks.queue(Tasks.<T>builder().name(name).body(job).build());
-    }
-
-    /** @see #queue(org.apache.brooklyn.api.management.TaskAdaptable)  */
-    public static <T> Task<T> queue(String name, Runnable job) {
-        return DynamicTasks.queue(Tasks.<T>builder().name(name).body(job).build());
-    }
-
-    /** queues the task if needed, i.e. if it is not yet submitted (so it will run), 
-     * or if it is submitted but not queued and we are in a queueing context (so it is available for informational purposes) */
-    public static <T extends TaskAdaptable<?>> T queueIfNeeded(T task) {
-        if (!Tasks.isQueued(task)) {
-            if (Tasks.isSubmitted(task) && getTaskQueuingContext()==null) {
-                // already submitted and not in a queueing context, don't try to queue
-            } else {
-                // needs submitting, put it in the queue
-                // (will throw an error if we are not a queueing context)
-                queue(task);
-            }
-        }
-        return task;
-    }
-    
-    /** submits/queues the given task if needed, and gets the result (unchecked) 
-     * only permitted in a queueing context (ie a DST main job) if the task is not yet submitted */
-    // things get really confusing if you try to queueInTaskHierarchy -- easy to cause deadlocks!
-    public static <T> T get(TaskAdaptable<T> t) {
-        return queueIfNeeded(t).asTask().getUnchecked();
-    }
-
-    /** As {@link #drain(Duration, boolean)} waiting forever and throwing the first error 
-     * (excluding errors in inessential tasks),
-     * then returning the last task in the queue (which is guaranteed to have finished without error,
-     * if this method returns without throwing) */
-    public static Task<?> waitForLast() {
-        drain(null, true);
-        // this call to last is safe, as the above guarantees everything will have run
-        // (on errors the above will throw so we won't come here)
-        List<Task<?>> q = DynamicTasks.getTaskQueuingContext().getQueue();
-        return q.isEmpty() ? null : Iterables.getLast(q);
-    }
-    
-    /** Calls {@link TaskQueueingContext#drain(Duration, boolean, boolean)} on the current task context */
-    public static TaskQueueingContext drain(Duration optionalTimeout, boolean throwFirstError) {
-        TaskQueueingContext qc = DynamicTasks.getTaskQueuingContext();
-        Preconditions.checkNotNull(qc, "Cannot drain when there is no queueing context");
-        qc.drain(optionalTimeout, false, throwFirstError);
-        return qc;
-    }
-
-    /** as {@link Tasks#swallowChildrenFailures()} but requiring a {@link TaskQueueingContext}. */
-    @Beta
-    public static void swallowChildrenFailures() {
-        Preconditions.checkNotNull(DynamicTasks.getTaskQueuingContext(), "Task queueing context required here");
-        Tasks.swallowChildrenFailures();
-    }
-
-    /** same as {@link Tasks#markInessential()}
-     * (but included here for convenience as it is often used in conjunction with {@link DynamicTasks}) */
-    public static void markInessential() {
-        Tasks.markInessential();
-    }
-
-    /** queues the task if possible, otherwise submits it asynchronously; returns the task for callers to 
-     * {@link Task#getUnchecked()} or {@link Task#blockUntilEnded()} */
-    public static <T> Task<T> submit(TaskAdaptable<T> task, Entity entity) {
-        return queueIfPossible(task).orSubmitAsync(entity).asTask();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ExecutionListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ExecutionListener.java b/core/src/main/java/brooklyn/util/task/ExecutionListener.java
deleted file mode 100644
index 7753588..0000000
--- a/core/src/main/java/brooklyn/util/task/ExecutionListener.java
+++ /dev/null
@@ -1,31 +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 brooklyn.util.task;
-
-import org.apache.brooklyn.api.management.Task;
-
-public interface ExecutionListener {
-
-    /** invoked when a task completes: 
-     * {@link Task#getEndTimeUtc()} and {@link Task#isDone()} are guaranteed to be set,
-     * and {@link Task#get()} should return immediately for most Task implementations
-     * (care has been taken to avoid potential deadlocks here, waiting for a result!)  */
-    public void onTaskDone(Task<?> task);
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ExecutionUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ExecutionUtils.java b/core/src/main/java/brooklyn/util/task/ExecutionUtils.java
deleted file mode 100644
index 37c19d2..0000000
--- a/core/src/main/java/brooklyn/util/task/ExecutionUtils.java
+++ /dev/null
@@ -1,49 +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 brooklyn.util.task;
-
-import groovy.lang.Closure;
-
-import java.util.concurrent.Callable;
-
-import com.google.common.base.Function;
-import com.google.common.base.Throwables;
-
-public class ExecutionUtils {
-    /**
-     * Attempts to run/call the given object, with the given arguments if possible, preserving the return value if there is one (null otherwise);
-     * throws exception if the callable is a non-null object which cannot be invoked (not a callable or runnable)
-     * @deprecated since 0.7.0 ; this super-loose typing should be avoided; if it is needed, let's move it to one of the Groovy compatibility classes
-     */
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public static Object invoke(Object callable, Object ...args) {
-        if (callable instanceof Closure) return ((Closure<?>)callable).call(args);
-        if (callable instanceof Callable) {
-            try {
-                return ((Callable<?>)callable).call();
-            } catch (Throwable t) {
-                throw Throwables.propagate(t);
-            }
-        }
-        if (callable instanceof Runnable) { ((Runnable)callable).run(); return null; }
-        if (callable instanceof Function && args.length == 1) { return ((Function)callable).apply(args[0]); }
-        if (callable==null) return null;
-        throw new IllegalArgumentException("Cannot invoke unexpected object "+callable+" of type "+callable.getClass()+", with "+args.length+" args");
-    }
-}


[29/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ValueResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ValueResolver.java b/core/src/main/java/brooklyn/util/task/ValueResolver.java
deleted file mode 100644
index 37f4269..0000000
--- a/core/src/main/java/brooklyn/util/task/ValueResolver.java
+++ /dev/null
@@ -1,426 +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 brooklyn.util.task;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Future;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.management.ExecutionContext;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskAdaptable;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.BrooklynTaskTags;
-import brooklyn.entity.basic.EntityInternal;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.javalang.JavaClassNames;
-import brooklyn.util.repeat.Repeater;
-import brooklyn.util.time.CountdownTimer;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Durations;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.common.reflect.TypeToken;
-
-/** 
- * Resolves a given object, as follows:
- * <li> If it is a {@link Tasks} or a {@link DeferredSupplier} then get its contents
- * <li> If it's a map and {@link #deep(boolean)} is requested, it applies resolution to contents
- * <li> It applies coercion
- * <p>
- * Fluent-style API exposes a number of other options.
- */
-public class ValueResolver<T> implements DeferredSupplier<T> {
-
-    /** 
-     * Period to wait if we're expected to return real quick 
-     * but we want fast things to have time to finish.
-     * <p>
-     * Timings are always somewhat arbitrary but this at least
-     * allows some intention to be captured in code rather than arbitrary values. */
-    public static Duration REAL_QUICK_WAIT = Duration.millis(50);
-    /** 
-     * Period to wait if we're expected to return quickly 
-     * but we want to be a bit more generous for things to finish,
-     * without letting a caller get annoyed. 
-     * <p>
-     * See {@link #REAL_QUICK_WAIT}. */
-    public static Duration PRETTY_QUICK_WAIT = Duration.millis(200);
-    
-    /** Period to wait when we have to poll but want to give the illusion of no wait.
-     * See {@link Repeater#DEFAULT_REAL_QUICK_PERIOD} */ 
-    public static Duration REAL_QUICK_PERIOD = Repeater.DEFAULT_REAL_QUICK_PERIOD;
-    
-    private static final Logger log = LoggerFactory.getLogger(ValueResolver.class);
-    
-    final Object value;
-    final Class<T> type;
-    ExecutionContext exec;
-    String description;
-    boolean forceDeep;
-    /** null means do it if you can; true means always, false means never */
-    Boolean embedResolutionInTask;
-    /** timeout on execution, if possible, or if embedResolutionInTask is true */
-    Duration timeout;
-    boolean isTransientTask = true;
-    
-    T defaultValue = null;
-    boolean returnDefaultOnGet = false;
-    boolean swallowExceptions = false;
-    
-    // internal fields
-    final Object parentOriginalValue;
-    final CountdownTimer parentTimer;
-    AtomicBoolean started = new AtomicBoolean(false);
-    boolean expired;
-    
-    ValueResolver(Object v, Class<T> type) {
-        this.value = v;
-        this.type = type;
-        checkTypeNotNull();
-        parentOriginalValue = null;
-        parentTimer = null;
-    }
-    
-    ValueResolver(Object v, Class<T> type, ValueResolver<?> parent) {
-        this.value = v;
-        this.type = type;
-        checkTypeNotNull();
-        
-        exec = parent.exec;
-        description = parent.description;
-        forceDeep = parent.forceDeep;
-        embedResolutionInTask = parent.embedResolutionInTask;
-
-        parentOriginalValue = parent.getOriginalValue();
-
-        timeout = parent.timeout;
-        parentTimer = parent.parentTimer;
-        if (parentTimer!=null && parentTimer.isExpired())
-            expired = true;
-        
-        // default value and swallow exceptions do not need to be nested
-    }
-
-    public static class ResolverBuilderPretype {
-        final Object v;
-        public ResolverBuilderPretype(Object v) {
-            this.v = v;
-        }
-        public <T> ValueResolver<T> as(Class<T> type) {
-            return new ValueResolver<T>(v, type);
-        }
-    }
-
-    /** returns a copy of this resolver which can be queried, even if the original (single-use instance) has already been copied */
-    public ValueResolver<T> clone() {
-        ValueResolver<T> result = new ValueResolver<T>(value, type)
-            .context(exec).description(description)
-            .embedResolutionInTask(embedResolutionInTask)
-            .deep(forceDeep)
-            .timeout(timeout);
-        if (returnDefaultOnGet) result.defaultValue(defaultValue);
-        if (swallowExceptions) result.swallowExceptions();
-        return result;
-    }
-    
-    /** execution context to use when resolving; required if resolving unsubmitted tasks or running with a time limit */
-    public ValueResolver<T> context(ExecutionContext exec) {
-        this.exec = exec;
-        return this;
-    }
-    /** as {@link #context(ExecutionContext)} for use from an entity */
-    public ValueResolver<T> context(Entity entity) {
-        return context(entity!=null ? ((EntityInternal)entity).getExecutionContext() : null);
-    }
-    
-    /** sets a message which will be displayed in status reports while it waits (e.g. the name of the config key being looked up) */
-    public ValueResolver<T> description(String description) {
-        this.description = description;
-        return this;
-    }
-    
-    /** sets a default value which will be returned on a call to {@link #get()} if the task does not complete
-     * or completes with an error
-     * <p>
-     * note that {@link #getMaybe()} returns an absent object even in the presence of
-     * a default, so that any error can still be accessed */
-    public ValueResolver<T> defaultValue(T defaultValue) {
-        this.defaultValue = defaultValue;
-        this.returnDefaultOnGet = true;
-        return this;
-    }
-
-    /** indicates that no default value should be returned on a call to {@link #get()}, and instead it should throw
-     * (this is the default; this method is provided to undo a call to {@link #defaultValue(Object)}) */
-    public ValueResolver<T> noDefaultValue() {
-        this.returnDefaultOnGet = false;
-        this.defaultValue = null;
-        return this;
-    }
-    
-    /** indicates that exceptions in resolution should not be thrown on a call to {@link #getMaybe()}, 
-     * but rather used as part of the {@link Maybe#get()} if it's absent, 
-     * and swallowed altogether on a call to {@link #get()} in the presence of a {@link #defaultValue(Object)} */
-    public ValueResolver<T> swallowExceptions() {
-        this.swallowExceptions = true;
-        return this;
-    }
-    
-    /** whether the task should be marked as transient; defaults true */
-    public ValueResolver<T> transientTask(boolean isTransientTask) {
-        this.isTransientTask = isTransientTask;
-        return this;
-    }
-    
-    public Maybe<T> getDefault() {
-        if (returnDefaultOnGet) return Maybe.of(defaultValue);
-        else return Maybe.absent("No default value set");
-    }
-    
-    /** causes nested structures (maps, lists) to be descended and nested unresolved values resolved */
-    public ValueResolver<T> deep(boolean forceDeep) {
-        this.forceDeep = forceDeep;
-        return this;
-    }
-
-    /** if true, forces execution of a deferred supplier to be run in a task;
-     * if false, it prevents it (meaning time limits may not be applied);
-     * if null, the default, it runs in a task if a time limit is applied.
-     * <p>
-     * running inside a task is required for some {@link DeferredSupplier}
-     * instances which look up a task {@link ExecutionContext}. */
-    public ValueResolver<T> embedResolutionInTask(Boolean embedResolutionInTask) {
-        this.embedResolutionInTask = embedResolutionInTask;
-        return this;
-    }
-    
-    /** sets a time limit on executions
-     * <p>
-     * used for {@link Task} and {@link DeferredSupplier} instances.
-     * may require an execution context at runtime. */
-    public ValueResolver<T> timeout(Duration timeout) {
-        this.timeout = timeout;
-        return this;
-    }
-    
-    protected void checkTypeNotNull() {
-        if (type==null) 
-            throw new NullPointerException("type must be set to resolve, for '"+value+"'"+(description!=null ? ", "+description : ""));
-    }
-
-    public T get() {
-        Maybe<T> m = getMaybe();
-        if (m.isPresent()) return m.get();
-        if (returnDefaultOnGet) return defaultValue;
-        return m.get();
-    }
-    
-    public Maybe<T> getMaybe() {
-        Maybe<T> result = getMaybeInternal();
-        if (log.isTraceEnabled()) {
-            log.trace(this+" evaluated as "+result);
-        }
-        return result;
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    protected Maybe<T> getMaybeInternal() {
-        if (started.getAndSet(true))
-            throw new IllegalStateException("ValueResolver can only be used once");
-        
-        if (expired) return Maybe.absent("Nested resolution of "+getOriginalValue()+" did not complete within "+timeout);
-        
-        ExecutionContext exec = this.exec;
-        if (exec==null) {
-            // if execution context not specified, take it from the current task if present
-            exec = BasicExecutionContext.getCurrentExecutionContext();
-        }
-        
-        CountdownTimer timerU = parentTimer;
-        if (timerU==null && timeout!=null)
-            timerU = timeout.countdownTimer();
-        final CountdownTimer timer = timerU;
-        if (timer!=null && !timer.isRunning())
-            timer.start();
-        
-        checkTypeNotNull();
-        Object v = this.value;
-        
-        //if the expected type is a closure or map and that's what we have, we're done (or if it's null);
-        //but not allowed to return a future or DeferredSupplier as the resolved value
-        if (v==null || (!forceDeep && type.isInstance(v) && !Future.class.isInstance(v) && !DeferredSupplier.class.isInstance(v)))
-            return Maybe.of((T) v);
-        
-        try {
-            //if it's a task or a future, we wait for the task to complete
-            if (v instanceof TaskAdaptable<?>) {
-                //if it's a task, we make sure it is submitted
-                if (!((TaskAdaptable<?>) v).asTask().isSubmitted() ) {
-                    if (exec==null)
-                        return Maybe.absent("Value for unsubmitted task '"+getDescription()+"' requested but no execution context available");
-                    exec.submit(((TaskAdaptable<?>) v).asTask());
-                }
-            }
-
-            if (v instanceof Future) {
-                final Future<?> vfuture = (Future<?>) v;
-
-                //including tasks, above
-                if (!vfuture.isDone()) {
-                    Callable<Maybe> callable = new Callable<Maybe>() {
-                        public Maybe call() throws Exception {
-                            return Durations.get(vfuture, timer);
-                        } };
-
-                    String description = getDescription();
-                    Maybe vm = Tasks.withBlockingDetails("Waiting for "+description, callable);
-                    if (vm.isAbsent()) return vm;
-                    v = vm.get();
-
-                } else {
-                    v = vfuture.get();
-                    
-                }
-
-            } else if (v instanceof DeferredSupplier<?>) {
-                final Object vf = v;
-
-                if ((!Boolean.FALSE.equals(embedResolutionInTask) && (exec!=null || timeout!=null)) || Boolean.TRUE.equals(embedResolutionInTask)) {
-                    if (exec==null)
-                        return Maybe.absent("Embedding in task needed for '"+getDescription()+"' but no execution context available");
-                        
-                    Callable<Object> callable = new Callable<Object>() {
-                        public Object call() throws Exception {
-                            try {
-                                Tasks.setBlockingDetails("Retrieving "+vf);
-                                return ((DeferredSupplier<?>) vf).get();
-                            } finally {
-                                Tasks.resetBlockingDetails();
-                            }
-                        } };
-                    String description = getDescription();
-                    TaskBuilder<Object> vb = Tasks.<Object>builder().body(callable).name("Resolving dependent value").description(description);
-                    if (isTransientTask) vb.tag(BrooklynTaskTags.TRANSIENT_TASK_TAG);
-                    Task<Object> vt = exec.submit(vb.build());
-                    // TODO to handle immediate resolution, it would be nice to be able to submit 
-                    // so it executes in the current thread,
-                    // or put a marker in the target thread or task while it is running that the task 
-                    // should never wait on anything other than another value being resolved 
-                    // (though either could recurse infinitely) 
-                    Maybe<Object> vm = Durations.get(vt, timer);
-                    vt.cancel(true);
-                    if (vm.isAbsent()) return (Maybe<T>)vm;
-                    v = vm.get();
-                    
-                } else {
-                    try {
-                        Tasks.setBlockingDetails("Retrieving (non-task) "+vf);
-                        v = ((DeferredSupplier<?>) vf).get();
-                    } finally {
-                        Tasks.resetBlockingDetails();
-                    }
-                }
-
-            } else if (v instanceof Map) {
-                //and if a map or list we look inside
-                Map result = Maps.newLinkedHashMap();
-                for (Map.Entry<?,?> entry : ((Map<?,?>)v).entrySet()) {
-                    Maybe<?> kk = new ValueResolver(entry.getKey(), type, this)
-                        .description( (description!=null ? description+", " : "") + "map key "+entry.getKey() )
-                        .getMaybe();
-                    if (kk.isAbsent()) return (Maybe<T>)kk;
-                    Maybe<?> vv = new ValueResolver(entry.getValue(), type, this)
-                        .description( (description!=null ? description+", " : "") + "map value for key "+kk.get() )
-                        .getMaybe();
-                    if (vv.isAbsent()) return (Maybe<T>)vv;
-                    result.put(kk.get(), vv.get());
-                }
-                return Maybe.of((T) result);
-
-            } else if (v instanceof Set) {
-                Set result = Sets.newLinkedHashSet();
-                int count = 0;
-                for (Object it : (Set)v) {
-                    Maybe<?> vv = new ValueResolver(it, type, this)
-                        .description( (description!=null ? description+", " : "") + "entry "+count )
-                        .getMaybe();
-                    if (vv.isAbsent()) return (Maybe<T>)vv;
-                    result.add(vv.get());
-                    count++;
-                }
-                return Maybe.of((T) result);
-
-            } else if (v instanceof Iterable) {
-                List result = Lists.newArrayList();
-                int count = 0;
-                for (Object it : (Iterable)v) {
-                    Maybe<?> vv = new ValueResolver(it, type, this)
-                        .description( (description!=null ? description+", " : "") + "entry "+count )
-                        .getMaybe();
-                    if (vv.isAbsent()) return (Maybe<T>)vv;
-                    result.add(vv.get());
-                    count++;
-                }
-                return Maybe.of((T) result);
-
-            } else {
-                return TypeCoercions.tryCoerce(v, TypeToken.of(type));
-            }
-
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            
-            IllegalArgumentException problem = new IllegalArgumentException("Error resolving "+(description!=null ? description+", " : "")+v+", in "+exec+": "+e, e);
-            if (swallowExceptions) {
-                if (log.isDebugEnabled())
-                    log.debug("Resolution of "+this+" failed, swallowing and returning: "+e);
-                return Maybe.absent(problem);
-            }
-            if (log.isDebugEnabled())
-                log.debug("Resolution of "+this+" failed, throwing: "+e);
-            throw problem;
-        }
-        
-        return new ValueResolver(v, type, this).getMaybe();
-    }
-
-    protected String getDescription() {
-        return description!=null ? description : ""+value;
-    }
-    protected Object getOriginalValue() {
-        if (parentOriginalValue!=null) return parentOriginalValue;
-        return value;
-    }
-    
-    @Override
-    public String toString() {
-        return JavaClassNames.cleanSimpleClassName(this)+"["+JavaClassNames.cleanSimpleClassName(type)+" "+value+"]";
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskFactory.java b/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskFactory.java
deleted file mode 100644
index bd9e96e..0000000
--- a/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskFactory.java
+++ /dev/null
@@ -1,89 +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 brooklyn.util.task.ssh;
-
-import org.apache.brooklyn.api.management.TaskFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.config.ConfigBag;
-
-// cannot be (cleanly) instantiated due to nested generic self-referential type; however trivial subclasses do allow it 
-public class SshFetchTaskFactory implements TaskFactory<SshFetchTaskWrapper> {
-    
-    private static final Logger log = LoggerFactory.getLogger(SshFetchTaskFactory.class);
-    
-    private boolean dirty = false;
-    
-    protected SshMachineLocation machine;
-    protected String remoteFile;
-    protected final ConfigBag config = ConfigBag.newInstance();
-
-    /** constructor where machine will be added later */
-    public SshFetchTaskFactory(String remoteFile) {
-        remoteFile(remoteFile);
-    }
-
-    /** convenience constructor to supply machine immediately */
-    public SshFetchTaskFactory(SshMachineLocation machine, String remoteFile) {
-        machine(machine);
-        remoteFile(remoteFile);
-    }
-
-    protected SshFetchTaskFactory self() { return this; }
-
-    protected void markDirty() {
-        dirty = true;
-    }
-    
-    public SshFetchTaskFactory machine(SshMachineLocation machine) {
-        markDirty();
-        this.machine = machine;
-        return self();
-    }
-        
-    public SshMachineLocation getMachine() {
-        return machine;
-    }
-    
-    public SshFetchTaskFactory remoteFile(String remoteFile) {
-        this.remoteFile = remoteFile;
-        return self();
-    }
-
-    public ConfigBag getConfig() {
-        return config;
-    }
-    
-    @Override
-    public SshFetchTaskWrapper newTask() {
-        dirty = false;
-        return new SshFetchTaskWrapper(this);
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        // help let people know of API usage error
-        if (dirty)
-            log.warn("Task "+this+" was modified but modification was never used");
-        super.finalize();
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskWrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskWrapper.java b/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskWrapper.java
deleted file mode 100644
index 9553b4f..0000000
--- a/core/src/main/java/brooklyn/util/task/ssh/SshFetchTaskWrapper.java
+++ /dev/null
@@ -1,135 +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 brooklyn.util.task.ssh;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskWrapper;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.FilenameUtils;
-
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.os.Os;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-
-/**
- * As {@link ProcessTaskWrapper}, but putting a file on the remote machine
- * 
- * @since 0.6.0
- */
-@Beta
-public class SshFetchTaskWrapper implements TaskWrapper<String> {
-
-    private final Task<String> task;
-
-    private final String remoteFile;
-    private final SshMachineLocation machine;
-    private File backingFile;
-    private final ConfigBag config;
-    
-    
-    // package private as only AbstractSshTaskFactory should invoke
-    SshFetchTaskWrapper(SshFetchTaskFactory factory) {
-        this.remoteFile = Preconditions.checkNotNull(factory.remoteFile, "remoteFile");
-        this.machine = Preconditions.checkNotNull(factory.machine, "machine");
-        TaskBuilder<String> tb = TaskBuilder.<String>builder().dynamic(false).name("ssh fetch "+factory.remoteFile);
-        task = tb.body(new SshFetchJob()).build();
-        config = factory.getConfig();
-    }
-    
-    @Override
-    public Task<String> asTask() {
-        return getTask();
-    }
-    
-    @Override
-    public Task<String> getTask() {
-        return task;
-    }
-    
-    public String getRemoteFile() {
-        return remoteFile;
-    }
-    
-    public SshMachineLocation getMachine() {
-        return machine;
-    }
-        
-    private class SshFetchJob implements Callable<String> {
-        @Override
-        public String call() throws Exception {
-            int result = -1;
-            try {
-                Preconditions.checkNotNull(getMachine(), "machine");
-                backingFile = Os.newTempFile("brooklyn-ssh-fetch-", FilenameUtils.getName(remoteFile));
-                backingFile.deleteOnExit();
-                
-                result = getMachine().copyFrom(config.getAllConfig(), remoteFile, backingFile.getPath());
-            } catch (Exception e) {
-                throw new IllegalStateException("SSH fetch "+getRemoteFile()+" from "+getMachine()+" returned threw exception, in "+Tasks.current()+": "+e, e);
-            }
-            if (result!=0) {
-                throw new IllegalStateException("SSH fetch "+getRemoteFile()+" from "+getMachine()+" returned non-zero exit code  "+result+", in "+Tasks.current());
-            }
-            return FileUtils.readFileToString(backingFile);
-        }
-    }
-    
-    @Override
-    public String toString() {
-        return super.toString()+"["+task+"]";
-    }
-
-    /** blocks, returns the fetched file as a string, throwing if there was an exception */
-    public String get() {
-        return getTask().getUnchecked();
-    }
-    
-    /** blocks, returns the fetched file as bytes, throwing if there was an exception */
-    public byte[] getBytes() {
-        block();
-        try {
-            return FileUtils.readFileToByteArray(backingFile);
-        } catch (IOException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    
-    /** blocks until the task completes; does not throw */
-    public SshFetchTaskWrapper block() {
-        getTask().blockUntilEnded();
-        return this;
-    }
- 
-    /** true iff the ssh job has completed (with or without failure) */
-    public boolean isDone() {
-        return getTask().isDone();
-    }   
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskFactory.java b/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskFactory.java
deleted file mode 100644
index e2c5502..0000000
--- a/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskFactory.java
+++ /dev/null
@@ -1,123 +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 brooklyn.util.task.ssh;
-
-import java.io.InputStream;
-import java.io.Reader;
-
-import org.apache.brooklyn.api.management.TaskFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.stream.KnownSizeInputStream;
-import brooklyn.util.stream.ReaderInputStream;
-
-import com.google.common.base.Suppliers;
-
-// cannot be (cleanly) instantiated due to nested generic self-referential type; however trivial subclasses do allow it 
-public class SshPutTaskFactory extends SshPutTaskStub implements TaskFactory<SshPutTaskWrapper> {
-    
-    private static final Logger log = LoggerFactory.getLogger(SshPutTaskFactory.class);
-    
-    private boolean dirty = false;
-
-    /** constructor where machine will be added later */
-    public SshPutTaskFactory(String remoteFile) {
-        remoteFile(remoteFile);
-    }
-
-    /** convenience constructor to supply machine immediately */
-    public SshPutTaskFactory(SshMachineLocation machine, String remoteFile) {
-        machine(machine);
-        remoteFile(remoteFile);
-    }
-
-    protected SshPutTaskFactory self() { return this; }
-
-    protected void markDirty() {
-        dirty = true;
-    }
-    
-    public SshPutTaskFactory machine(SshMachineLocation machine) {
-        markDirty();
-        this.machine = machine;
-        return self();
-    }
-        
-    public SshPutTaskFactory remoteFile(String remoteFile) {
-        this.remoteFile = remoteFile;
-        return self();
-    }
-
-    public SshPutTaskFactory summary(String summary) {
-        markDirty();
-        this.summary = summary;
-        return self();
-    }
-
-    public SshPutTaskFactory contents(String contents) {
-        markDirty();
-        this.contents = Suppliers.ofInstance(KnownSizeInputStream.of(contents));  
-        return self();
-    }
-
-    public SshPutTaskFactory contents(byte[] contents) {
-        markDirty();
-        this.contents = Suppliers.ofInstance(KnownSizeInputStream.of(contents));  
-        return self();
-    }
-
-    public SshPutTaskFactory contents(InputStream stream) {
-        markDirty();
-        this.contents = Suppliers.ofInstance(stream);  
-        return self();
-    }
-
-    public SshPutTaskFactory contents(Reader reader) {
-        markDirty();
-        this.contents = Suppliers.ofInstance(new ReaderInputStream(reader));  
-        return self();
-    }
-
-    public SshPutTaskFactory allowFailure() {
-        markDirty();
-        allowFailure = true;
-        return self();
-    }
-    
-    public SshPutTaskFactory createDirectory() {
-        markDirty();
-        createDirectory = true;
-        return self();
-    }
-    
-    public SshPutTaskWrapper newTask() {
-        dirty = false;
-        return new SshPutTaskWrapper(this);
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        // help let people know of API usage error
-        if (dirty)
-            log.warn("Task "+this+" was modified but modification was never used");
-        super.finalize();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskStub.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskStub.java b/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskStub.java
deleted file mode 100644
index 185e819..0000000
--- a/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskStub.java
+++ /dev/null
@@ -1,69 +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 brooklyn.util.task.ssh;
-
-import java.io.InputStream;
-
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.config.ConfigBag;
-
-import com.google.common.base.Supplier;
-
-public class SshPutTaskStub {
-
-    protected String remoteFile;
-    protected SshMachineLocation machine;
-    protected Supplier<? extends InputStream> contents;
-    protected String summary;
-    protected String permissions;
-    protected boolean allowFailure = false;
-    protected boolean createDirectory = false;
-    protected final ConfigBag config = ConfigBag.newInstance();
-
-    protected SshPutTaskStub() {
-    }
-    
-    protected SshPutTaskStub(SshPutTaskStub constructor) {
-        this.remoteFile = constructor.remoteFile;
-        this.machine = constructor.machine;
-        this.contents = constructor.contents;
-        this.summary = constructor.summary;
-        this.allowFailure = constructor.allowFailure;
-        this.createDirectory = constructor.createDirectory;
-        this.permissions = constructor.permissions;
-        this.config.copy(constructor.config);
-    }
-
-    public String getRemoteFile() {
-        return remoteFile;
-    }
-    
-    public String getSummary() {
-        if (summary!=null) return summary;
-        return "scp put: "+remoteFile;
-    }
-
-    public SshMachineLocation getMachine() {
-        return machine;
-    }
-    
-    protected ConfigBag getConfig() {
-        return config;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskWrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskWrapper.java b/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskWrapper.java
deleted file mode 100644
index 4f0cd76..0000000
--- a/core/src/main/java/brooklyn/util/task/ssh/SshPutTaskWrapper.java
+++ /dev/null
@@ -1,190 +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 brooklyn.util.task.ssh;
-
-import java.util.Arrays;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
-
-/** As {@link ProcessTaskWrapper}, but putting a file on the remote machine */
-@Beta
-public class SshPutTaskWrapper extends SshPutTaskStub implements TaskWrapper<Void> {
-
-    private static final Logger log = LoggerFactory.getLogger(SshPutTaskWrapper.class);
-    
-    private final Task<Void> task;
-
-    protected Integer exitCodeOfCopy = null;
-    protected Exception exception = null;
-    protected boolean successful = false;
-    
-    // package private as only AbstractSshTaskFactory should invoke
-    SshPutTaskWrapper(SshPutTaskFactory constructor) {
-        super(constructor);
-        TaskBuilder<Void> tb = TaskBuilder.<Void>builder().dynamic(false).name(getSummary());
-        task = tb.body(new SshPutJob()).build();
-    }
-    
-    @Override
-    public Task<Void> asTask() {
-        return getTask();
-    }
-    
-    @Override
-    public Task<Void> getTask() {
-        return task;
-    }
-        
-    // TODO:
-    //   verify
-    //   copyAsRoot
-    //   owner
-    //   lastModificationDate - see {@link #PROP_LAST_MODIFICATION_DATE}; not supported by all SshTool implementations
-    //   lastAccessDate - see {@link #PROP_LAST_ACCESS_DATE}; not supported by all SshTool implementations
-
-    private class SshPutJob implements Callable<Void> {
-        @Override
-        public Void call() throws Exception {
-            try {
-                Preconditions.checkNotNull(getMachine(), "machine");
-                
-                String remoteFile = getRemoteFile();
-
-                if (createDirectory) {
-                    String remoteDir = remoteFile;
-                    int exitCodeOfCreate = -1;
-                    try {
-                        int li = remoteDir.lastIndexOf("/");
-                        if (li>=0) {
-                            remoteDir = remoteDir.substring(0, li+1);
-                            exitCodeOfCreate = getMachine().execCommands("creating directory for "+getSummary(), 
-                                    Arrays.asList("mkdir -p "+remoteDir));
-                        } else {
-                            // nothing to create
-                            exitCodeOfCreate = 0;
-                        }
-                    } catch (Exception e) {
-                        if (log.isDebugEnabled())
-                            log.debug("SSH put "+getRemoteFile()+" (create dir, in task "+getSummary()+") to "+getMachine()+" threw exception: "+e);
-                        exception = e;
-                    }
-                    if (exception!=null || !((Integer)0).equals(exitCodeOfCreate)) {
-                        if (!allowFailure) {
-                            if (exception != null) {
-                                throw new IllegalStateException(getSummary()+" (creating dir "+remoteDir+" for SSH put task) ended with exception, in "+Tasks.current()+": "+exception, exception);
-                            }
-                            if (exitCodeOfCreate!=0) {
-                                exception = new IllegalStateException(getSummary()+" (creating dir "+remoteDir+" SSH put task) ended with exit code "+exitCodeOfCreate+", in "+Tasks.current());
-                                throw exception;
-                            }
-                        }
-                        // not successful, but allowed
-                        return null;
-                    }
-                }
-                
-                ConfigBag config = ConfigBag.newInstanceCopying(getConfig());
-                if (permissions!=null) config.put(SshTool.PROP_PERMISSIONS, permissions);
-                
-                exitCodeOfCopy = getMachine().copyTo(config.getAllConfig(), contents.get(), remoteFile);
-
-                if (log.isDebugEnabled())
-                    log.debug("SSH put "+getRemoteFile()+" (task "+getSummary()+") to "+getMachine()+" completed with exit code "+exitCodeOfCopy);
-            } catch (Exception e) {
-                if (log.isDebugEnabled())
-                    log.debug("SSH put "+getRemoteFile()+" (task "+getSummary()+") to "+getMachine()+" threw exception: "+e);
-                exception = e;
-            }
-            
-            if (exception!=null || !((Integer)0).equals(exitCodeOfCopy)) {
-                if (!allowFailure) {
-                    if (exception != null) {
-                        throw new IllegalStateException(getSummary()+" (SSH put task) ended with exception, in "+Tasks.current()+": "+exception, exception);
-                    }
-                    if (exitCodeOfCopy!=0) {
-                        exception = new IllegalStateException(getSummary()+" (SSH put task) ended with exit code "+exitCodeOfCopy+", in "+Tasks.current());
-                        throw exception;
-                    }
-                }
-                // not successful, but allowed
-                return null;
-            }
-            
-            // TODO verify
-
-            successful = (exception==null && ((Integer)0).equals(exitCodeOfCopy));
-            return null;
-        }
-    }
-    
-    @Override
-    public String toString() {
-        return super.toString()+"["+task+"]";
-    }
-
-    /** blocks, throwing if there was an exception */
-    public Void get() {
-        return getTask().getUnchecked();
-    }
-    
-    /** returns the exit code from the copy, 0 on success; 
-     * null if it has not completed or threw exception
-     * (not sure if this is ever a non-zero integer or if it is meaningful)
-     * <p>
-     * most callers will want the simpler {@link #isSuccessful()} */
-    public Integer getExitCode() {
-        return exitCodeOfCopy;
-    }
-    
-    /** returns any exception encountered in the operation */
-    public Exception getException() {
-        return exception;
-    }
-    
-    /** blocks until the task completes; does not throw */
-    public SshPutTaskWrapper block() {
-        getTask().blockUntilEnded();
-        return this;
-    }
- 
-    /** true iff the ssh job has completed (with or without failure) */
-    public boolean isDone() {
-        return getTask().isDone();
-    }
-
-    /** true iff the scp has completed successfully; guaranteed to be set before {@link #isDone()} or {@link #block()} are satisfied */
-    public boolean isSuccessful() {
-        return successful;
-    }
-    
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java b/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
deleted file mode 100644
index 9f6fbb9..0000000
--- a/core/src/main/java/brooklyn/util/task/ssh/SshTasks.java
+++ /dev/null
@@ -1,236 +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 brooklyn.util.task.ssh;
-
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskAdaptable;
-import org.apache.brooklyn.api.management.TaskFactory;
-import org.apache.brooklyn.api.management.TaskQueueingContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.config.ConfigUtils;
-import brooklyn.entity.basic.BrooklynTaskTags;
-import brooklyn.entity.basic.ConfigKeys;
-
-import org.apache.brooklyn.location.basic.AbstractLocation;
-import org.apache.brooklyn.location.basic.LocationInternal;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.net.Urls;
-import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.internal.PlainSshExecTaskFactory;
-import brooklyn.util.task.system.ProcessTaskFactory;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.Strings;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-
-/**
- * Conveniences for generating {@link Task} instances to perform SSH activities on an {@link SshMachineLocation}.
- * <p>
- * To infer the {@link SshMachineLocation} and take properties from entities and global management context the
- * {@link SshEffectorTasks} should be preferred over this class.
- *  
- * @see SshEffectorTasks
- * @since 0.6.0
- */
-@Beta
-public class SshTasks {
-
-    private static final Logger log = LoggerFactory.getLogger(SshTasks.class);
-        
-    public static ProcessTaskFactory<Integer> newSshExecTaskFactory(SshMachineLocation machine, String ...commands) {
-        return newSshExecTaskFactory(machine, true, commands);
-    }
-    
-    public static ProcessTaskFactory<Integer> newSshExecTaskFactory(SshMachineLocation machine, final boolean useMachineConfig, String ...commands) {
-        return new PlainSshExecTaskFactory<Integer>(machine, commands) {
-            {
-                if (useMachineConfig)
-                    config.putIfAbsent(getSshFlags(machine));
-            }
-        };
-    }
-
-    public static SshPutTaskFactory newSshPutTaskFactory(SshMachineLocation machine, String remoteFile) {
-        return newSshPutTaskFactory(machine, true, remoteFile);
-    }
-    
-    public static SshPutTaskFactory newSshPutTaskFactory(SshMachineLocation machine, final boolean useMachineConfig, String remoteFile) {
-        return new SshPutTaskFactory(machine, remoteFile) {
-            {
-                if (useMachineConfig)
-                    config.putIfAbsent(getSshFlags(machine));
-            }
-        };
-    }
-
-    public static SshFetchTaskFactory newSshFetchTaskFactory(SshMachineLocation machine, String remoteFile) {
-        return newSshFetchTaskFactory(machine, true, remoteFile);
-    }
-    
-    public static SshFetchTaskFactory newSshFetchTaskFactory(SshMachineLocation machine, final boolean useMachineConfig, String remoteFile) {
-        return new SshFetchTaskFactory(machine, remoteFile) {
-            {
-                if (useMachineConfig)
-                    config.putIfAbsent(getSshFlags(machine));
-            }
-        };
-    }
-
-    private static Map<String, Object> getSshFlags(Location location) {
-        ConfigBag allConfig = ConfigBag.newInstance();
-        
-        if (location instanceof AbstractLocation) {
-            ManagementContext mgmt = ((AbstractLocation)location).getManagementContext();
-            if (mgmt!=null)
-                allConfig.putAll(mgmt.getConfig().getAllConfig());
-        }
-        
-        allConfig.putAll(((LocationInternal)location).config().getBag());
-        
-        Map<String, Object> result = Maps.newLinkedHashMap();
-        for (String keyS : allConfig.getAllConfig().keySet()) {
-            ConfigKey<?> key = ConfigKeys.newConfigKey(Object.class, keyS);
-            if (key.getName().startsWith(SshTool.BROOKLYN_CONFIG_KEY_PREFIX)) {
-                result.put(ConfigUtils.unprefixedKey(SshTool.BROOKLYN_CONFIG_KEY_PREFIX, key).getName(), allConfig.get(key));
-            }
-        }
-        return result;
-    }
-
-    @Beta
-    public static enum OnFailingTask { 
-        FAIL,
-        /** issues a warning, sometimes implemented as marking the task inessential and failing it if it appears
-         * we are in a dynamic {@link TaskQueueingContext};
-         * useful because this way the warning appears to the user;
-         * but note that the check is done against the calling thread so use with some care
-         * (and thus this enum is currently here rather then elsewhere) */
-        WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL,
-        /** issues a warning in the log if the task fails, otherwise swallows it */
-        WARN_IN_LOG_ONLY, 
-        /** not even a warning if the task fails (the caller is expected to handle it as appropriate) */
-        IGNORE }
-    
-    public static ProcessTaskFactory<Boolean> dontRequireTtyForSudo(SshMachineLocation machine, final boolean failIfCantSudo) {
-        return dontRequireTtyForSudo(machine, failIfCantSudo ? OnFailingTask.FAIL : OnFailingTask.WARN_IN_LOG_ONLY);
-    }
-    /** creates a task which returns modifies sudoers to ensure non-tty access is permitted;
-     * also gives nice warnings if sudo is not permitted */
-    public static ProcessTaskFactory<Boolean> dontRequireTtyForSudo(SshMachineLocation machine, OnFailingTask onFailingTaskRequested) {
-        final OnFailingTask onFailingTask;
-        if (onFailingTaskRequested==OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL) {
-            if (DynamicTasks.getTaskQueuingContext()!=null)
-                onFailingTask = onFailingTaskRequested;
-            else
-                onFailingTask = OnFailingTask.WARN_IN_LOG_ONLY;
-        } else {
-            onFailingTask = onFailingTaskRequested;
-        }
-        
-        final String id = Identifiers.makeRandomId(6);
-        return newSshExecTaskFactory(machine, 
-                BashCommands.dontRequireTtyForSudo(),
-                // strange quotes are to ensure we don't match against echoed stdin
-                BashCommands.sudo("echo \"sudo\"-is-working-"+id))
-            .summary("setting up sudo")
-            .configure(SshTool.PROP_ALLOCATE_PTY, true)
-            .allowingNonZeroExitCode()
-            .returning(new Function<ProcessTaskWrapper<?>,Boolean>() { public Boolean apply(ProcessTaskWrapper<?> task) {
-                if (task.getExitCode()==0 && task.getStdout().contains("sudo-is-working-"+id)) return true;
-                Entity entity = BrooklynTaskTags.getTargetOrContextEntity(Tasks.current());
-                
-                
-                if (onFailingTask!=OnFailingTask.IGNORE) {
-                    // TODO if in a queueing context can we mark this task inessential and throw?
-                    // that way user sees the message...
-                    String message = "Error setting up sudo for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+" "+
-                        " (exit code "+task.getExitCode()+(entity!=null ? ", entity "+entity : "")+")";
-                    DynamicTasks.queueIfPossible(Tasks.warning(message, null));
-                }
-                Streams.logStreamTail(log, "STDERR of sudo setup problem", Streams.byteArrayOfString(task.getStderr()), 1024);
-                
-                if (onFailingTask==OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL) {
-                    Tasks.markInessential();
-                }
-                if (onFailingTask==OnFailingTask.FAIL || onFailingTask==OnFailingTask.WARN_OR_IF_DYNAMIC_FAIL_MARKING_INESSENTIAL) {
-                    throw new IllegalStateException("Passwordless sudo is required for "+task.getMachine().getUser()+"@"+task.getMachine().getAddress().getHostName()+
-                            (entity!=null ? " ("+entity+")" : ""));
-                }
-                return false; 
-            } });
-    }
-
-    /** Function for use in {@link ProcessTaskFactory#returning(Function)} which logs all information, optionally requires zero exit code, 
-     * and then returns stdout */
-    public static Function<ProcessTaskWrapper<?>, String> returningStdoutLoggingInfo(final Logger logger, final boolean requireZero) {
-        return new Function<ProcessTaskWrapper<?>, String>() {
-          public String apply(@Nullable ProcessTaskWrapper<?> input) {
-            if (logger!=null) logger.info(input+" COMMANDS:\n"+Strings.join(input.getCommands(),"\n"));
-            if (logger!=null) logger.info(input+" STDOUT:\n"+input.getStdout());
-            if (logger!=null) logger.info(input+" STDERR:\n"+input.getStderr());
-            if (requireZero && input.getExitCode()!=0) 
-                throw new IllegalStateException("non-zero exit code in "+input.getSummary()+": see log for more details!");
-            return input.getStdout();
-          }
-        };
-    }
-
-    /** task to install a file given a url, where the url is resolved remotely first then locally */
-    public static TaskFactory<?> installFromUrl(final SshMachineLocation location, final String url, final String destPath) {
-        return installFromUrl(ResourceUtils.create(SshTasks.class), ImmutableMap.<String,Object>of(), location, url, destPath);
-    }
-    /** task to install a file given a url, where the url is resolved remotely first then locally */
-    public static TaskFactory<?> installFromUrl(final ResourceUtils utils, final Map<String, ?> props, final SshMachineLocation location, final String url, final String destPath) {
-        return new TaskFactory<TaskAdaptable<?>>() {
-            @Override
-            public TaskAdaptable<?> newTask() {
-                return Tasks.<Void>builder().name("installing "+Urls.getBasename(url)).description("installing "+url+" to "+destPath).body(new Runnable() {
-                    @Override
-                    public void run() {
-                        int result = location.installTo(utils, props, url, destPath);
-                        if (result!=0) 
-                            throw new IllegalStateException("Failed to install '"+url+"' to '"+destPath+"' at "+location+": exit code "+result);
-                    }
-                }).build();
-            }
-        };
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ssh/internal/AbstractSshExecTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/internal/AbstractSshExecTaskFactory.java b/core/src/main/java/brooklyn/util/task/ssh/internal/AbstractSshExecTaskFactory.java
deleted file mode 100644
index 86764f3..0000000
--- a/core/src/main/java/brooklyn/util/task/ssh/internal/AbstractSshExecTaskFactory.java
+++ /dev/null
@@ -1,58 +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 brooklyn.util.task.ssh.internal;
-
-import com.google.common.base.Preconditions;
-
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.task.system.ProcessTaskFactory;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-import brooklyn.util.task.system.internal.AbstractProcessTaskFactory;
-
-// cannot be (cleanly) instantiated due to nested generic self-referential type; however trivial subclasses do allow it 
-public abstract class AbstractSshExecTaskFactory<T extends AbstractProcessTaskFactory<T,RET>,RET> extends AbstractProcessTaskFactory<T,RET> implements ProcessTaskFactory<RET> {
-    
-    /** constructor where machine will be added later */
-    public AbstractSshExecTaskFactory(String ...commands) {
-        super(commands);
-    }
-
-    /** convenience constructor to supply machine immediately */
-    public AbstractSshExecTaskFactory(SshMachineLocation machine, String ...commands) {
-        this(commands);
-        machine(machine);
-    }
-    
-    @Override
-    public ProcessTaskWrapper<RET> newTask() {
-        dirty = false;
-        return new ProcessTaskWrapper<RET>(this) {
-            protected void run(ConfigBag config) {
-                Preconditions.checkNotNull(getMachine(), "machine");
-                if (Boolean.FALSE.equals(this.runAsScript)) {
-                    this.exitCode = getMachine().execCommands(config.getAllConfig(), getSummary(), commands, shellEnvironment);
-                } else { // runScript = null or TRUE
-                    this.exitCode = getMachine().execScript(config.getAllConfig(), getSummary(), commands, shellEnvironment);
-                }
-            }
-            protected String taskTypeShortName() { return "SSH"; }
-        };
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ssh/internal/PlainSshExecTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ssh/internal/PlainSshExecTaskFactory.java b/core/src/main/java/brooklyn/util/task/ssh/internal/PlainSshExecTaskFactory.java
deleted file mode 100644
index efc14db..0000000
--- a/core/src/main/java/brooklyn/util/task/ssh/internal/PlainSshExecTaskFactory.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 brooklyn.util.task.ssh.internal;
-
-import java.util.List;
-
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-
-import com.google.common.base.Function;
-
-/** the "Plain" class exists purely so we can massage return types for callers' convenience */
-public class PlainSshExecTaskFactory<RET> extends AbstractSshExecTaskFactory<PlainSshExecTaskFactory<RET>,RET> {
-    /** constructor where machine will be added later */
-    public PlainSshExecTaskFactory(String ...commands) {
-        super(commands);
-    }
-
-    /** convenience constructor to supply machine immediately */
-    public PlainSshExecTaskFactory(SshMachineLocation machine, String ...commands) {
-        this(commands);
-        machine(machine);
-    }
-
-    /** Constructor where machine will be added later */
-    public PlainSshExecTaskFactory(List<String> commands) {
-        this(commands.toArray(new String[commands.size()]));
-    }
-
-    /** Convenience constructor to supply machine immediately */
-    public PlainSshExecTaskFactory(SshMachineLocation machine, List<String> commands) {
-        this(machine, commands.toArray(new String[commands.size()]));
-    }
-
-    @Override
-    public <T2> PlainSshExecTaskFactory<T2> returning(ScriptReturnType type) {
-        return (PlainSshExecTaskFactory<T2>) super.<T2>returning(type);
-    }
-
-    @Override
-    public <RET2> PlainSshExecTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation) {
-        return (PlainSshExecTaskFactory<RET2>) super.returning(resultTransformation);
-    }
-    
-    @Override
-    public PlainSshExecTaskFactory<Boolean> returningIsExitCodeZero() {
-        return (PlainSshExecTaskFactory<Boolean>) super.returningIsExitCodeZero();
-    }
-    
-    @Override
-    public PlainSshExecTaskFactory<String> requiringZeroAndReturningStdout() {
-        return (PlainSshExecTaskFactory<String>) super.requiringZeroAndReturningStdout();
-    }
-    
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/system/ProcessTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/ProcessTaskFactory.java b/core/src/main/java/brooklyn/util/task/system/ProcessTaskFactory.java
deleted file mode 100644
index 407111c..0000000
--- a/core/src/main/java/brooklyn/util/task/system/ProcessTaskFactory.java
+++ /dev/null
@@ -1,65 +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 brooklyn.util.task.system;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.management.TaskFactory;
-
-import brooklyn.config.ConfigKey;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.task.system.ProcessTaskStub.ScriptReturnType;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-
-public interface ProcessTaskFactory<T> extends TaskFactory<ProcessTaskWrapper<T>> {
-    public ProcessTaskFactory<T> machine(SshMachineLocation machine);
-    public ProcessTaskFactory<T> add(String ...commandsToAdd);
-    public ProcessTaskFactory<T> add(Iterable<String> commandsToAdd);
-    public ProcessTaskFactory<T> requiringExitCodeZero();
-    public ProcessTaskFactory<T> requiringExitCodeZero(String extraErrorMessage);
-    public ProcessTaskFactory<T> allowingNonZeroExitCode();
-    public ProcessTaskFactory<String> requiringZeroAndReturningStdout();
-    public ProcessTaskFactory<Boolean> returningIsExitCodeZero();
-    public <RET2> ProcessTaskFactory<RET2> returning(ScriptReturnType type);
-    public <RET2> ProcessTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation);
-    public ProcessTaskFactory<T> runAsCommand();
-    public ProcessTaskFactory<T> runAsScript();
-    public ProcessTaskFactory<T> runAsRoot();
-    public ProcessTaskFactory<T> environmentVariable(String key, String val);
-    public ProcessTaskFactory<T> environmentVariables(Map<String,String> vars);
-    public ProcessTaskFactory<T> summary(String summary);
-    
-    /** allows setting config-key based properties for specific underlying tools */
-    @Beta
-    public <V> ProcessTaskFactory<T> configure(ConfigKey<V> key, V value);
-
-    /** allows setting config-key/flag based properties for specific underlying tools;
-     * but note that if any are prefixed with {@link SshTool#BROOKLYN_CONFIG_KEY_PREFIX}
-     * these should normally be filtered out */
-    @Beta
-    public ProcessTaskFactory<T> configure(Map<?,?> flags);
-
-    /** adds a listener which will be notified of (otherwise) successful completion,
-     * typically used to invalidate the result (ie throw exception, to promote a string in the output to an exception);
-     * invoked even if return code is zero, so a better error can be thrown */
-    public ProcessTaskFactory<T> addCompletionListener(Function<ProcessTaskWrapper<?>, Void> function);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/system/ProcessTaskStub.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/ProcessTaskStub.java b/core/src/main/java/brooklyn/util/task/system/ProcessTaskStub.java
deleted file mode 100644
index df37691..0000000
--- a/core/src/main/java/brooklyn/util/task/system/ProcessTaskStub.java
+++ /dev/null
@@ -1,101 +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 brooklyn.util.task.system;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class ProcessTaskStub {
-    
-    protected final List<String> commands = new ArrayList<String>();
-    /** null for localhost */
-    protected SshMachineLocation machine;
-    
-    // config data
-    protected String summary;
-    protected final ConfigBag config = ConfigBag.newInstance();
-    
-    public static enum ScriptReturnType { CUSTOM, EXIT_CODE, STDOUT_STRING, STDOUT_BYTES, STDERR_STRING, STDERR_BYTES }
-    protected Function<ProcessTaskWrapper<?>, ?> returnResultTransformation = null;
-    protected ScriptReturnType returnType = ScriptReturnType.EXIT_CODE;
-    
-    protected Boolean runAsScript = null;
-    protected boolean runAsRoot = false;
-    protected Boolean requireExitCodeZero = null;
-    protected String extraErrorMessage = null;
-    protected Map<String,String> shellEnvironment = new MutableMap<String, String>();
-    protected final List<Function<ProcessTaskWrapper<?>, Void>> completionListeners = new ArrayList<Function<ProcessTaskWrapper<?>,Void>>();
-
-    public ProcessTaskStub() {}
-    
-    protected ProcessTaskStub(ProcessTaskStub source) {
-        commands.addAll(source.getCommands());
-        machine = source.getMachine();
-        summary = source.getSummary();
-        config.copy(source.getConfig());
-        returnResultTransformation = source.returnResultTransformation;
-        returnType = source.returnType;
-        runAsScript = source.runAsScript;
-        runAsRoot = source.runAsRoot;
-        requireExitCodeZero = source.requireExitCodeZero;
-        extraErrorMessage = source.extraErrorMessage;
-        shellEnvironment.putAll(source.getShellEnvironment());
-        completionListeners.addAll(source.getCompletionListeners());
-    }
-
-    public String getSummary() {
-        if (summary!=null) return summary;
-        return Strings.maxlen(Strings.join(commands, " ; "), 160);
-    }
-    
-    /** null for localhost */
-    public SshMachineLocation getMachine() {
-        return machine;
-    }
-    
-    public Map<String, String> getShellEnvironment() {
-        return ImmutableMap.copyOf(shellEnvironment);
-    }
- 
-    @Override
-    public String toString() {
-        return super.toString()+"["+getSummary()+"]";
-    }
-
-    public List<String> getCommands() {
-        return ImmutableList.copyOf(commands);
-    }
- 
-    public List<Function<ProcessTaskWrapper<?>, Void>> getCompletionListeners() {
-        return completionListeners;
-    }
-
-    protected ConfigBag getConfig() { return config; }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/system/ProcessTaskWrapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/ProcessTaskWrapper.java b/core/src/main/java/brooklyn/util/task/system/ProcessTaskWrapper.java
deleted file mode 100644
index 5c18fdd..0000000
--- a/core/src/main/java/brooklyn/util/task/system/ProcessTaskWrapper.java
+++ /dev/null
@@ -1,187 +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 brooklyn.util.task.system;
-
-import java.io.ByteArrayOutputStream;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskWrapper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.BrooklynTaskTags;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.internal.ssh.ShellTool;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.system.internal.AbstractProcessTaskFactory;
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Function;
-
-/** Wraps a fully constructed process task, and allows callers to inspect status. 
- * Note that methods in here such as {@link #getStdout()} will return partially completed streams while the task is ongoing
- * (and exit code will be null). You can {@link #block()} or {@link #get()} as conveniences on the underlying {@link #getTask()}. */ 
-public abstract class ProcessTaskWrapper<RET> extends ProcessTaskStub implements TaskWrapper<RET> {
-
-    private static final Logger log = LoggerFactory.getLogger(ProcessTaskWrapper.class);
-    
-    private final Task<RET> task;
-
-    // execution details
-    protected ByteArrayOutputStream stdout = new ByteArrayOutputStream();
-    protected ByteArrayOutputStream stderr = new ByteArrayOutputStream();
-    protected Integer exitCode = null;
-    
-    @SuppressWarnings("unchecked")
-    protected ProcessTaskWrapper(AbstractProcessTaskFactory<?,RET> constructor) {
-        super(constructor);
-        TaskBuilder<Object> tb = constructor.constructCustomizedTaskBuilder();
-        if (stdout!=null) tb.tag(BrooklynTaskTags.tagForStreamSoft(BrooklynTaskTags.STREAM_STDOUT, stdout));
-        if (stderr!=null) tb.tag(BrooklynTaskTags.tagForStreamSoft(BrooklynTaskTags.STREAM_STDERR, stderr));
-        task = (Task<RET>) tb.body(new ProcessTaskInternalJob()).build();
-    }
-    
-    @Override
-    public Task<RET> asTask() {
-        return getTask();
-    }
-    
-    @Override
-    public Task<RET> getTask() {
-        return task;
-    }
-    
-    public Integer getExitCode() {
-        return exitCode;
-    }
-    
-    public byte[] getStdoutBytes() {
-        if (stdout==null) return null;
-        return stdout.toByteArray();
-    }
-    
-    public byte[] getStderrBytes() {
-        if (stderr==null) return null;
-        return stderr.toByteArray();
-    }
-    
-    public String getStdout() {
-        if (stdout==null) return null;
-        return stdout.toString();
-    }
-    
-    public String getStderr() {
-        if (stderr==null) return null;
-        return stderr.toString();
-    }
-
-    protected class ProcessTaskInternalJob implements Callable<Object> {
-        @Override
-        public Object call() throws Exception {
-            run( getConfigForRunning() );
-            
-            for (Function<ProcessTaskWrapper<?>, Void> listener: completionListeners) {
-                try {
-                    listener.apply(ProcessTaskWrapper.this);
-                } catch (Exception e) {
-                    logWithDetailsAndThrow("Error in "+taskTypeShortName()+" task "+getSummary()+": "+e, e);                    
-                }
-            }
-            
-            if (exitCode!=0 && !Boolean.FALSE.equals(requireExitCodeZero)) {
-                if (Boolean.TRUE.equals(requireExitCodeZero)) {
-                    logWithDetailsAndThrow(taskTypeShortName()+" task ended with exit code "+exitCode+" when 0 was required, in "+Tasks.current()+": "+getSummary(), null);
-                } else {
-                    // warn, but allow, on non-zero not explicitly allowed
-                    log.warn(taskTypeShortName()+" task ended with exit code "+exitCode+" when non-zero was not explicitly allowed (error may be thrown in future), in "
-                            +Tasks.current()+": "+getSummary());
-                }
-            }
-            switch (returnType) {
-            case CUSTOM: return returnResultTransformation.apply(ProcessTaskWrapper.this);
-            case STDOUT_STRING: return stdout.toString();
-            case STDOUT_BYTES: return stdout.toByteArray();
-            case STDERR_STRING: return stderr.toString();
-            case STDERR_BYTES: return stderr.toByteArray();
-            case EXIT_CODE: return exitCode;
-            }
-
-            throw new IllegalStateException("Unknown return type for "+taskTypeShortName()+" job "+getSummary()+": "+returnType);
-        }
-
-        protected void logWithDetailsAndThrow(String message, Throwable optionalCause) {
-            message = (extraErrorMessage!=null ? extraErrorMessage+": " : "") + message;
-            log.warn(message+" (throwing)");
-            logProblemDetails("STDERR", stderr, 1024);
-            logProblemDetails("STDOUT", stdout, 1024);
-            logProblemDetails("STDIN", Streams.byteArrayOfString(Strings.join(commands,"\n")), 4096);
-            if (optionalCause!=null) throw new IllegalStateException(message, optionalCause);
-            throw new IllegalStateException(message);
-        }
-        
-        protected void logProblemDetails(String streamName, ByteArrayOutputStream stream, int max) {
-            Streams.logStreamTail(log, streamName+" for problem in "+Tasks.current(), stream, max);
-        }
-
-    }
-    
-    @Override
-    public String toString() {
-        return super.toString()+"["+task+"]";
-    }
-
-    /** blocks and gets the result, throwing if there was an exception */
-    public RET get() {
-        return getTask().getUnchecked();
-    }
-    
-    /** blocks until the task completes; does not throw */
-    public ProcessTaskWrapper<RET> block() {
-        getTask().blockUntilEnded();
-        return this;
-    }
- 
-    /** true iff the process has completed (with or without failure) */
-    public boolean isDone() {
-        return getTask().isDone();
-    }
-
-    /** for overriding */
-    protected ConfigBag getConfigForRunning() {
-        ConfigBag config = ConfigBag.newInstanceCopying(ProcessTaskWrapper.this.config);
-        if (stdout!=null) config.put(ShellTool.PROP_OUT_STREAM, stdout);
-        if (stderr!=null) config.put(ShellTool.PROP_ERR_STREAM, stderr);
-        
-        if (!config.containsKey(ShellTool.PROP_NO_EXTRA_OUTPUT))
-            // by default no extra output (so things like cat, etc work as expected)
-            config.put(ShellTool.PROP_NO_EXTRA_OUTPUT, true);
-
-        if (runAsRoot)
-            config.put(ShellTool.PROP_RUN_AS_ROOT, true);
-        return config;
-    }
-
-    protected abstract void run(ConfigBag config);
-    
-    protected abstract String taskTypeShortName();
-    
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/system/SystemTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/SystemTasks.java b/core/src/main/java/brooklyn/util/task/system/SystemTasks.java
deleted file mode 100644
index 8553935..0000000
--- a/core/src/main/java/brooklyn/util/task/system/SystemTasks.java
+++ /dev/null
@@ -1,29 +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 brooklyn.util.task.system;
-
-import brooklyn.util.task.system.internal.SystemProcessTaskFactory.ConcreteSystemProcessTaskFactory;
-
-public class SystemTasks {
-
-    public static ProcessTaskFactory<Integer> exec(String ...commands) {
-        return new ConcreteSystemProcessTaskFactory<Integer>(commands);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/system/internal/AbstractProcessTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/internal/AbstractProcessTaskFactory.java b/core/src/main/java/brooklyn/util/task/system/internal/AbstractProcessTaskFactory.java
deleted file mode 100644
index e41a9a9..0000000
--- a/core/src/main/java/brooklyn/util/task/system/internal/AbstractProcessTaskFactory.java
+++ /dev/null
@@ -1,214 +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 brooklyn.util.task.system.internal;
-
-import java.util.Arrays;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.BrooklynTaskTags;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.system.ProcessTaskFactory;
-import brooklyn.util.task.system.ProcessTaskStub;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterables;
-
-public abstract class AbstractProcessTaskFactory<T extends AbstractProcessTaskFactory<T,RET>,RET> extends ProcessTaskStub implements ProcessTaskFactory<RET> {
-    
-    private static final Logger log = LoggerFactory.getLogger(AbstractProcessTaskFactory.class);
-    
-    protected boolean dirty = false;
-    
-    public AbstractProcessTaskFactory(String ...commands) {
-        this.commands.addAll(Arrays.asList(commands));
-    }
-
-    @SuppressWarnings("unchecked")
-    protected T self() { return (T)this; }
-    
-    protected void markDirty() {
-        dirty = true;
-    }
-    
-    @Override
-    public T add(String ...commandsToAdd) {
-        markDirty();
-        for (String commandToAdd: commandsToAdd) this.commands.add(commandToAdd);
-        return self();
-    }
-
-    @Override
-    public T add(Iterable<String> commandsToAdd) {
-        Iterables.addAll(this.commands, commandsToAdd);
-        return self();
-    }
-    
-    @Override
-    public T machine(SshMachineLocation machine) {
-        markDirty();
-        this.machine = machine;
-        return self();
-    }
-
-    @Override
-    public T requiringExitCodeZero() {
-        markDirty();
-        requireExitCodeZero = true;
-        return self();
-    }
-    
-    @Override
-    public T requiringExitCodeZero(String extraErrorMessage) {
-        markDirty();
-        requireExitCodeZero = true;
-        this.extraErrorMessage = extraErrorMessage;
-        return self();
-    }
-    
-    @Override
-    public T allowingNonZeroExitCode() {
-        markDirty();
-        requireExitCodeZero = false;
-        return self();
-    }
-
-    @Override
-    public ProcessTaskFactory<Boolean> returningIsExitCodeZero() {
-        if (requireExitCodeZero==null) allowingNonZeroExitCode();
-        return returning(new Function<ProcessTaskWrapper<?>,Boolean>() {
-            public Boolean apply(ProcessTaskWrapper<?> input) {
-                return input.getExitCode()==0;
-            }
-        });
-    }
-
-    @Override
-    public ProcessTaskFactory<String> requiringZeroAndReturningStdout() {
-        requiringExitCodeZero();
-        return this.<String>returning(ScriptReturnType.STDOUT_STRING);
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public <RET2> ProcessTaskFactory<RET2> returning(ScriptReturnType type) {
-        markDirty();
-        returnType = Preconditions.checkNotNull(type);
-        return (ProcessTaskFactory<RET2>) self();
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public <RET2> ProcessTaskFactory<RET2> returning(Function<ProcessTaskWrapper<?>, RET2> resultTransformation) {
-        markDirty();
-        returnType = ScriptReturnType.CUSTOM;
-        this.returnResultTransformation = resultTransformation;
-        return (ProcessTaskFactory<RET2>) self();
-    }
-    
-    @Override
-    public T runAsCommand() {
-        markDirty();
-        runAsScript = false;
-        return self();
-    }
-
-    @Override
-    public T runAsScript() {
-        markDirty();
-        runAsScript = true;
-        return self();
-    }
-
-    @Override
-    public T runAsRoot() {
-        markDirty();
-        runAsRoot = true;
-        return self();
-    }
-    
-    @Override
-    public T environmentVariable(String key, String val) {
-        markDirty();
-        shellEnvironment.put(key, val);
-        return self();
-    }
-
-    @Override
-    public T environmentVariables(Map<String,String> vars) {
-        if (vars!=null) {
-            markDirty();
-            shellEnvironment.putAll(vars);
-        }
-        return self();
-    }
-
-    /** creates the TaskBuilder which can be further customized; typically invoked by the initial {@link #newTask()} */
-    public TaskBuilder<Object> constructCustomizedTaskBuilder() {
-        TaskBuilder<Object> tb = TaskBuilder.builder().dynamic(false).name("ssh: "+getSummary());
-        
-        tb.tag(BrooklynTaskTags.tagForStream(BrooklynTaskTags.STREAM_STDIN, 
-                Streams.byteArrayOfString(Strings.join(commands, "\n"))));
-        tb.tag(BrooklynTaskTags.tagForEnvStream(BrooklynTaskTags.STREAM_ENV, shellEnvironment));
-        
-        return tb;
-    }
-    
-    @Override
-    public T summary(String summary) {
-        markDirty();
-        this.summary = summary;
-        return self();
-    }
-
-    @Override
-    public <V> T configure(ConfigKey<V> key, V value) {
-        config.configure(key, value);
-        return self();
-    }
-    
-    @Override
-    public T configure(Map<?, ?> flags) {
-        if (flags!=null)
-            config.putAll(flags);
-        return self();
-    }
- 
-    @Override
-    public T addCompletionListener(Function<ProcessTaskWrapper<?>, Void> listener) {
-        completionListeners.add(listener);
-        return self();
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        // help let people know of API usage error
-        if (dirty)
-            log.warn("Task "+this+" was modified but modification was never used");
-        super.finalize();
-    }
-}


[59/64] incubator-brooklyn git commit: brooklyn-software-database: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlClusterImpl.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlClusterImpl.java
deleted file mode 100644
index f86ad43..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlClusterImpl.java
+++ /dev/null
@@ -1,445 +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 brooklyn.entity.database.mysql;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.basic.EntityLocal;
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.api.event.SensorEvent;
-import org.apache.brooklyn.api.event.SensorEventListener;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.core.util.task.DynamicTasks;
-import org.apache.brooklyn.core.util.task.TaskBuilder;
-
-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.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.reflect.TypeToken;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.enricher.Enrichers;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.EntityInternal;
-import brooklyn.entity.basic.EntityPredicates;
-import brooklyn.entity.basic.ServiceStateLogic.ServiceNotUpLogic;
-import brooklyn.entity.group.DynamicClusterImpl;
-import brooklyn.event.basic.DependentConfiguration;
-import brooklyn.event.basic.Sensors;
-import brooklyn.event.feed.function.FunctionFeed;
-import brooklyn.event.feed.function.FunctionPollConfig;
-import brooklyn.util.collections.CollectionFunctionals;
-import brooklyn.util.guava.Functionals;
-import brooklyn.util.guava.IfFunctions;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.StringPredicates;
-import brooklyn.util.time.Duration;
-
-// https://dev.mysql.com/doc/refman/5.7/en/replication-howto.html
-
-// TODO CREATION_SCRIPT_CONTENTS executed before replication setup so it is not replicated to slaves
-// TODO Bootstrap slave from dump for the case where the binary log is purged
-// TODO Promote slave to master
-// TODO SSL connection between master and slave
-// TODO DB credentials littered all over the place in file system
-public class MySqlClusterImpl extends DynamicClusterImpl implements MySqlCluster {
-    private static final AttributeSensor<Boolean> NODE_REPLICATION_INITIALIZED = Sensors.newBooleanSensor("mysql.replication_initialized");
-
-    private static final String MASTER_CONFIG_URL = "classpath:///brooklyn/entity/database/mysql/mysql_master.conf";
-    private static final String SLAVE_CONFIG_URL = "classpath:///brooklyn/entity/database/mysql/mysql_slave.conf";
-    private static final int MASTER_SERVER_ID = 1;
-    private static final Predicate<Entity> IS_MASTER = EntityPredicates.configEqualTo(MySqlNode.MYSQL_SERVER_ID, MASTER_SERVER_ID);
-
-    @SuppressWarnings("serial")
-    private static final AttributeSensor<Supplier<Integer>> SLAVE_NEXT_SERVER_ID = Sensors.newSensor(new TypeToken<Supplier<Integer>>() {},
-            "mysql.slave.next_server_id", "Returns the ID of the next slave server");
-    @SuppressWarnings("serial")
-    private static final AttributeSensor<Map<String, String>> SLAVE_ID_ADDRESS_MAPPING = Sensors.newSensor(new TypeToken<Map<String, String>>() {},
-            "mysql.slave.id_address_mapping", "Maps slave entity IDs to SUBNET_ADDRESS, so the address is known at member remove time.");
-
-    @Override
-    public void init() {
-        super.init();
-        // Set id supplier in attribute so it is serialized
-        setAttribute(SLAVE_NEXT_SERVER_ID, new NextServerIdSupplier());
-        setAttribute(SLAVE_ID_ADDRESS_MAPPING, new ConcurrentHashMap<String, String>());
-        if (getConfig(SLAVE_PASSWORD) == null) {
-            setAttribute(SLAVE_PASSWORD, Identifiers.makeRandomId(8));
-        } else {
-            setAttribute(SLAVE_PASSWORD, getConfig(SLAVE_PASSWORD));
-        }
-        initSubscriptions();
-    }
-
-    @Override
-    public void rebind() {
-        super.rebind();
-        initSubscriptions();
-    }
-
-    private void initSubscriptions() {
-        subscribeToMembers(this, MySqlNode.SERVICE_PROCESS_IS_RUNNING, new NodeRunningListener(this));
-        subscribe(this, MEMBER_REMOVED, new MemberRemovedListener());
-    }
-
-    @Override
-    protected void initEnrichers() {
-        super.initEnrichers();
-        propagateMasterAttribute(MySqlNode.HOSTNAME);
-        propagateMasterAttribute(MySqlNode.ADDRESS);
-        propagateMasterAttribute(MySqlNode.SUBNET_HOSTNAME);
-        propagateMasterAttribute(MySqlNode.SUBNET_ADDRESS);
-        propagateMasterAttribute(MySqlNode.MYSQL_PORT);
-        propagateMasterAttribute(MySqlNode.DATASTORE_URL);
-
-        addEnricher(Enrichers.builder()
-                .aggregating(MySqlNode.DATASTORE_URL)
-                .publishing(SLAVE_DATASTORE_URL_LIST)
-                .computing(Functions.<Collection<String>>identity())
-                .entityFilter(Predicates.not(IS_MASTER))
-                .fromMembers()
-                .build());
-
-        addEnricher(Enrichers.builder()
-                .aggregating(MySqlNode.QUERIES_PER_SECOND_FROM_MYSQL)
-                .publishing(QUERIES_PER_SECOND_FROM_MYSQL_PER_NODE)
-                .fromMembers()
-                .computingAverage()
-                .defaultValueForUnreportedSensors(0d)
-                .build());
-    }
-
-    private void propagateMasterAttribute(AttributeSensor<?> att) {
-        addEnricher(Enrichers.builder()
-                .aggregating(att)
-                .publishing(att)
-                .computing(IfFunctions.ifPredicate(CollectionFunctionals.notEmpty())
-                        .apply(CollectionFunctionals.firstElement())
-                        .defaultValue(null))
-                .entityFilter(IS_MASTER)
-                .build());
-    }
-
-    @Override
-    protected EntitySpec<?> getFirstMemberSpec() {
-        final EntitySpec<?> firstMemberSpec = super.getFirstMemberSpec();
-        if (firstMemberSpec != null) {
-            return applyDefaults(firstMemberSpec, Suppliers.ofInstance(MASTER_SERVER_ID), MASTER_CONFIG_URL, false);
-        }
-
-        final EntitySpec<?> memberSpec = super.getMemberSpec();
-        if (memberSpec != null) {
-            if (!isKeyConfigured(memberSpec, MySqlNode.TEMPLATE_CONFIGURATION_URL.getConfigKey())) {
-                return EntitySpec.create(memberSpec)
-                        .configure(MySqlNode.MYSQL_SERVER_ID, MASTER_SERVER_ID)
-                        .configure(MySqlNode.TEMPLATE_CONFIGURATION_URL, MASTER_CONFIG_URL);
-            } else {
-                return memberSpec;
-            }
-        }
-
-        return EntitySpec.create(MySqlNode.class)
-                .displayName("MySql Master")
-                .configure(MySqlNode.MYSQL_SERVER_ID, MASTER_SERVER_ID)
-                .configure(MySqlNode.TEMPLATE_CONFIGURATION_URL, MASTER_CONFIG_URL);
-    }
-
-    @Override
-    protected EntitySpec<?> getMemberSpec() {
-        Supplier<Integer> serverIdSupplier = getAttribute(SLAVE_NEXT_SERVER_ID);
-
-        EntitySpec<?> spec = super.getMemberSpec();
-        if (spec != null) {
-            return applyDefaults(spec, serverIdSupplier, SLAVE_CONFIG_URL, true);
-        }
-
-        return EntitySpec.create(MySqlNode.class)
-                .displayName("MySql Slave")
-                .configure(MySqlNode.MYSQL_SERVER_ID, serverIdSupplier.get())
-                .configure(MySqlNode.TEMPLATE_CONFIGURATION_URL, SLAVE_CONFIG_URL)
-                // block inheritance, only master should execute the creation script
-                .configure(MySqlNode.CREATION_SCRIPT_URL, (String) null)
-                .configure(MySqlNode.CREATION_SCRIPT_CONTENTS, (String) null);
-    }
-
-    private EntitySpec<?> applyDefaults(EntitySpec<?> spec, Supplier<Integer> serverId, String configUrl, boolean resetCreationScript) {
-        boolean needsServerId = !isKeyConfigured(spec, MySqlNode.MYSQL_SERVER_ID);
-        boolean needsConfigUrl = !isKeyConfigured(spec, MySqlNode.TEMPLATE_CONFIGURATION_URL.getConfigKey());
-        boolean needsCreationScriptUrl = resetCreationScript && !isKeyConfigured(spec, MySqlNode.CREATION_SCRIPT_URL);
-        boolean needsCreationScriptContents = resetCreationScript && !isKeyConfigured(spec, MySqlNode.CREATION_SCRIPT_CONTENTS);
-        if (needsServerId || needsConfigUrl || needsCreationScriptUrl || needsCreationScriptContents) {
-            EntitySpec<?> clonedSpec = EntitySpec.create(spec);
-            if (needsServerId) {
-                clonedSpec.configure(MySqlNode.MYSQL_SERVER_ID, serverId.get());
-            }
-            if (needsConfigUrl) {
-                clonedSpec.configure(MySqlNode.TEMPLATE_CONFIGURATION_URL, configUrl);
-            }
-            if (needsCreationScriptUrl) {
-                clonedSpec.configure(MySqlNode.CREATION_SCRIPT_URL, (String) null);
-            }
-            if (needsCreationScriptContents) {
-                clonedSpec.configure(MySqlNode.CREATION_SCRIPT_URL, (String) null);
-            }
-            return clonedSpec;
-        } else {
-            return spec;
-        }
-    }
-
-    private boolean isKeyConfigured(EntitySpec<?> spec, ConfigKey<?> key) {
-        return spec.getConfig().containsKey(key) || spec.getFlags().containsKey(key.getName());
-    }
-
-    @Override
-    protected Entity createNode(Location loc, Map<?, ?> flags) {
-        Entity node = super.createNode(loc, flags);
-        if (!IS_MASTER.apply(node)) {
-            ServiceNotUpLogic.updateNotUpIndicator((EntityLocal)node, MySqlSlave.SLAVE_HEALTHY, "Replication not started");
-
-            addFeed(FunctionFeed.builder()
-                .entity((EntityLocal)node)
-                .period(Duration.FIVE_SECONDS)
-                .poll(FunctionPollConfig.forSensor(MySqlSlave.SLAVE_HEALTHY)
-                        .callable(new SlaveStateCallable(node))
-                        .checkSuccess(StringPredicates.isNonBlank())
-                        .onSuccess(new SlaveStateParser(node))
-                        .setOnFailure(false)
-                        .description("Polls SHOW SLAVE STATUS"))
-                .build());
-
-            node.addEnricher(Enrichers.builder().updatingMap(Attributes.SERVICE_NOT_UP_INDICATORS)
-                    .from(MySqlSlave.SLAVE_HEALTHY)
-                    .computing(Functionals.ifNotEquals(true).value("Slave replication status is not healthy") )
-                    .build());
-        }
-        return node;
-    }
-
-    public static class SlaveStateCallable implements Callable<String> {
-        private Entity slave;
-        public SlaveStateCallable(Entity slave) {
-            this.slave = slave;
-        }
-
-        @Override
-        public String call() throws Exception {
-            if (Boolean.TRUE.equals(slave.getAttribute(MySqlNode.SERVICE_PROCESS_IS_RUNNING))) {
-                return slave.invoke(MySqlNode.EXECUTE_SCRIPT, ImmutableMap.of("commands", "SHOW SLAVE STATUS \\G")).asTask().getUnchecked();
-            } else {
-                return null;
-            }
-        }
-
-    }
-
-    public static class SlaveStateParser implements Function<String, Boolean> {
-        private Entity slave;
-
-        public SlaveStateParser(Entity slave) {
-            this.slave = slave;
-        }
-
-        @Override
-        public Boolean apply(String result) {
-            Map<String, String> status = MySqlRowParser.parseSingle(result);
-            String secondsBehindMaster = status.get("Seconds_Behind_Master");
-            if (secondsBehindMaster != null && !"NULL".equals(secondsBehindMaster)) {
-                ((EntityLocal)slave).setAttribute(MySqlSlave.SLAVE_SECONDS_BEHIND_MASTER, new Integer(secondsBehindMaster));
-            }
-            return "Yes".equals(status.get("Slave_IO_Running")) && "Yes".equals(status.get("Slave_SQL_Running"));
-        }
-
-    }
-
-    private static class NextServerIdSupplier implements Supplier<Integer> {
-        private AtomicInteger nextId = new AtomicInteger(MASTER_SERVER_ID+1);
-
-        @Override
-        public Integer get() {
-            return nextId.getAndIncrement();
-        }
-    }
-
-    // ============= Member Init =============
-
-    // The task is executed in inessential context (event handler) so
-    // not visible in tasks UI. Better make it visible so the user can
-    // see failures, currently accessible only from logs.
-    private static final class InitReplicationTask implements Runnable {
-        private final MySqlCluster cluster;
-        private final MySqlNode node;
-
-        private InitReplicationTask(MySqlCluster cluster, MySqlNode node) {
-            this.cluster = cluster;
-            this.node = node;
-        }
-
-        @Override
-        public void run() {
-            Integer serverId = node.getConfig(MySqlNode.MYSQL_SERVER_ID);
-            if (serverId == MASTER_SERVER_ID) {
-                initMaster(node);
-            } else if (serverId > MASTER_SERVER_ID) {
-                initSlave(node);
-            }
-        }
-
-        private void initMaster(MySqlNode master) {
-            String binLogInfo = executeScriptOnNode(master, "FLUSH TABLES WITH READ LOCK;SHOW MASTER STATUS \\G UNLOCK TABLES;");
-            Map<String, String> status = MySqlRowParser.parseSingle(binLogInfo);
-            String file = status.get("File");
-            if (file != null) {
-                ((EntityInternal)master).setAttribute(MySqlMaster.MASTER_LOG_FILE, file);
-            }
-            String position = status.get("Position");
-            if (position != null) {
-                ((EntityInternal)master).setAttribute(MySqlMaster.MASTER_LOG_POSITION, new Integer(position));
-            }
-        }
-
-        private void initSlave(MySqlNode slave) {
-            MySqlNode master = (MySqlNode) Iterables.find(cluster.getMembers(), IS_MASTER);
-            String masterLogFile = validateSqlParam(getAttributeBlocking(master, MySqlMaster.MASTER_LOG_FILE));
-            Integer masterLogPos = getAttributeBlocking(master, MySqlMaster.MASTER_LOG_POSITION);
-            String masterAddress = validateSqlParam(master.getAttribute(MySqlNode.SUBNET_ADDRESS));
-            Integer masterPort = master.getAttribute(MySqlNode.MYSQL_PORT);
-            String slaveAddress = validateSqlParam(slave.getAttribute(MySqlNode.SUBNET_ADDRESS));
-            String username = validateSqlParam(cluster.getConfig(SLAVE_USERNAME));
-            String password = validateSqlParam(cluster.getAttribute(SLAVE_PASSWORD));
-
-            executeScriptOnNode(master, String.format(
-                    "CREATE USER '%s'@'%s' IDENTIFIED BY '%s';\n" +
-                    "GRANT REPLICATION SLAVE ON *.* TO '%s'@'%s';\n",
-                    username, slaveAddress, password, username, slaveAddress));
-
-            String slaveCmd = String.format(
-                    "CHANGE MASTER TO " +
-                        "MASTER_HOST='%s', " +
-                        "MASTER_PORT=%d, " +
-                        "MASTER_USER='%s', " +
-                        "MASTER_PASSWORD='%s', " +
-                        "MASTER_LOG_FILE='%s', " +
-                        "MASTER_LOG_POS=%d;\n" +
-                    "START SLAVE;\n",
-                    masterAddress, masterPort, username, password, masterLogFile, masterLogPos);
-            executeScriptOnNode(slave, slaveCmd);
-
-            cluster.getAttribute(SLAVE_ID_ADDRESS_MAPPING).put(slave.getId(), slave.getAttribute(MySqlNode.SUBNET_ADDRESS));
-        }
-
-        private <T> T getAttributeBlocking(Entity masterNode, AttributeSensor<T> att) {
-            return DynamicTasks.queue(DependentConfiguration.attributeWhenReady(masterNode, att)).getUnchecked();
-        }
-
-    }
-
-    private static final class NodeRunningListener implements SensorEventListener<Boolean> {
-        private MySqlCluster cluster;
-
-        public NodeRunningListener(MySqlCluster cluster) {
-            this.cluster = cluster;
-        }
-
-        @Override
-        public void onEvent(SensorEvent<Boolean> event) {
-            final MySqlNode node = (MySqlNode) event.getSource();
-            if (Boolean.TRUE.equals(event.getValue()) &&
-                    // We are interested in SERVICE_PROCESS_IS_RUNNING only while haven't come online yet.
-                    // Probably will get several updates while replication is initialized so an additional
-                    // check is needed whether we have already seen this.
-                    Boolean.FALSE.equals(node.getAttribute(MySqlNode.SERVICE_UP)) &&
-                    !Boolean.TRUE.equals(node.getAttribute(NODE_REPLICATION_INITIALIZED))) {
-
-                // Events executed sequentially so no need to synchronize here.
-                ((EntityLocal)node).setAttribute(NODE_REPLICATION_INITIALIZED, Boolean.TRUE);
-
-                DynamicTasks.queueIfPossible(TaskBuilder.builder()
-                        .name("Configure master-slave replication on node")
-                        .body(new InitReplicationTask(cluster, node))
-                        .build())
-                    .orSubmitAsync(node);
-            }
-        }
-
-    }
-
-    // ============= Member Remove =============
-
-    public class MemberRemovedListener implements SensorEventListener<Entity> {
-        @Override
-        public void onEvent(SensorEvent<Entity> event) {
-            MySqlCluster cluster = (MySqlCluster) event.getSource();
-            Entity node = event.getValue();
-            String slaveAddress = cluster.getAttribute(SLAVE_ID_ADDRESS_MAPPING).remove(node.getId());
-            if (slaveAddress != null) {
-                DynamicTasks.queueIfPossible(TaskBuilder.builder()
-                        .name("Remove slave access")
-                        .body(new RemoveSlaveConfigTask(cluster, slaveAddress))
-                        .build())
-                    .orSubmitAsync(cluster);
-            }
-        }
-    }
-
-    public class RemoveSlaveConfigTask implements Runnable {
-        private MySqlCluster cluster;
-        private String slaveAddress;
-
-        public RemoveSlaveConfigTask(MySqlCluster cluster, String slaveAddress) {
-            this.cluster = cluster;
-            this.slaveAddress = validateSqlParam(slaveAddress);
-        }
-
-        @Override
-        public void run() {
-            // Could already be gone if stopping the entire app - let it throw an exception
-            MySqlNode master = (MySqlNode) Iterables.find(cluster.getMembers(), IS_MASTER);
-            String username = validateSqlParam(cluster.getConfig(SLAVE_USERNAME));
-            executeScriptOnNode(master, String.format("DROP USER '%s'@'%s';", username, slaveAddress));
-        }
-
-    }
-
-    // Can't call node.executeScript directly, need to change execution context, so use an effector task
-    private static String executeScriptOnNode(MySqlNode node, String commands) {
-        return node.invoke(MySqlNode.EXECUTE_SCRIPT, ImmutableMap.of(MySqlNode.EXECUTE_SCRIPT_COMMANDS, commands)).getUnchecked();
-    }
-
-    private static String validateSqlParam(String config) {
-        // Don't go into escape madness, just deny any suspicious strings.
-        // Would be nice to use prepared statements, but not worth pulling in the extra dependencies.
-        if (config.contains("'") && config.contains("\\")) {
-            throw new IllegalStateException("User provided string contains illegal SQL characters: " + config);
-        }
-        return config;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlDriver.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlDriver.java
deleted file mode 100644
index 2c90142..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlDriver.java
+++ /dev/null
@@ -1,31 +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 brooklyn.entity.database.mysql;
-
-import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
-
-import brooklyn.entity.basic.SoftwareProcessDriver;
-
-/**
- * The {@link SoftwareProcessDriver} for MySQL.
- */
-public interface MySqlDriver extends SoftwareProcessDriver {
-    public String getStatusCmd();
-    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNode.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNode.java
deleted file mode 100644
index 99b53c5..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNode.java
+++ /dev/null
@@ -1,97 +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 brooklyn.entity.database.mysql;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.entity.trait.HasShortName;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.MethodEffector;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
-import brooklyn.event.basic.MapConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-
-import org.apache.brooklyn.location.basic.PortRanges;
-
-@Catalog(name="MySql Node", description="MySql is an open source relational database management system (RDBMS)", iconUrl="classpath:///mysql-logo-110x57.png")
-@ImplementedBy(MySqlNodeImpl.class)
-public interface MySqlNode extends SoftwareProcess, HasShortName, DatastoreCommon {
-
-    // NOTE MySQL changes the minor version number of their GA release frequently, check for latest version if install fails
-    @SetFromFlag("version")
-    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "5.6.26");
-
-    //http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.26-osx10.9-x86_64.tar.gz
-    //http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.26-linux-glibc2.5-x86_64.tar.gz
-    @SetFromFlag("downloadUrl")
-    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new StringAttributeSensorAndConfigKey(
-            Attributes.DOWNLOAD_URL, "http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-${version}-${driver.osTag}.tar.gz");
-
-    @SetFromFlag("port")
-    PortAttributeSensorAndConfigKey MYSQL_PORT = new PortAttributeSensorAndConfigKey("mysql.port", "MySQL port", PortRanges.fromString("3306, 13306+"));
-
-    @SetFromFlag("dataDir")
-    ConfigKey<String> DATA_DIR = ConfigKeys.newStringConfigKey(
-            "mysql.datadir", "Directory for writing data files", null);
-
-    @SetFromFlag("serverConf")
-    MapConfigKey<Object> MYSQL_SERVER_CONF = new MapConfigKey<Object>(
-            Object.class, "mysql.server.conf", "Configuration options for mysqld");
-    
-    ConfigKey<Object> MYSQL_SERVER_CONF_LOWER_CASE_TABLE_NAMES = MYSQL_SERVER_CONF.subKey("lower_case_table_names", "See MySQL guide. Set 1 to ignore case in table names (useful for OS portability)");
-    
-    @SetFromFlag("serverId")
-    ConfigKey<Integer> MYSQL_SERVER_ID = ConfigKeys.newIntegerConfigKey("mysql.server_id", "Corresponds to server_id option", 0);
-    
-    @SetFromFlag("password")
-    StringAttributeSensorAndConfigKey PASSWORD = new StringAttributeSensorAndConfigKey(
-            "mysql.password", "Database admin password (or randomly generated if not set)", null);
-
-    @SetFromFlag("socketUid")
-    StringAttributeSensorAndConfigKey SOCKET_UID = new StringAttributeSensorAndConfigKey(
-            "mysql.socketUid", "Socket uid, for use in file /tmp/mysql.sock.<uid>.3306 (or randomly generated if not set)", null);
-    
-    /** @deprecated since 0.7.0 use DATASTORE_URL */ @Deprecated
-    AttributeSensor<String> MYSQL_URL = DATASTORE_URL;
-
-    @SetFromFlag("configurationTemplateUrl")
-    BasicAttributeSensorAndConfigKey<String> TEMPLATE_CONFIGURATION_URL = new StringAttributeSensorAndConfigKey(
-            "mysql.template.configuration.url", "Template file (in freemarker format) for the mysql.conf file",
-            "classpath://brooklyn/entity/database/mysql/mysql.conf");
-
-    AttributeSensor<Double> QUERIES_PER_SECOND_FROM_MYSQL = Sensors.newDoubleSensor("mysql.queries.perSec.fromMysql");
-
-    MethodEffector<String> EXECUTE_SCRIPT = new MethodEffector<String>(MySqlNode.class, "executeScript");
-    String EXECUTE_SCRIPT_COMMANDS = "commands";
-
-    @Effector(description = "Execute SQL script on the node as the root user")
-    String executeScript(@EffectorParam(name=EXECUTE_SCRIPT_COMMANDS) String commands);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNodeImpl.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNodeImpl.java
deleted file mode 100644
index dfbcbf1..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNodeImpl.java
+++ /dev/null
@@ -1,167 +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 brooklyn.entity.database.mysql;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.core.util.config.ConfigBag;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.effector.EffectorBody;
-import brooklyn.event.feed.ssh.SshFeed;
-import brooklyn.event.feed.ssh.SshPollConfig;
-import brooklyn.event.feed.ssh.SshPollValue;
-
-import org.apache.brooklyn.location.basic.Locations;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Function;
-
-public class MySqlNodeImpl extends SoftwareProcessImpl implements MySqlNode {
-
-    private static final Logger LOG = LoggerFactory.getLogger(MySqlNodeImpl.class);
-
-    private SshFeed feed;
-
-    public MySqlNodeImpl() {
-    }
-
-    public MySqlNodeImpl(Entity parent) {
-        this(MutableMap.of(), parent);
-    }
-
-    public MySqlNodeImpl(Map<?,?> flags) {
-        super(flags, null);
-    }
-
-    public MySqlNodeImpl(Map<?,?> flags, Entity parent) {
-        super(flags, parent);
-    }
-
-    @Override
-    public Class<?> getDriverInterface() {
-        return MySqlDriver.class;
-    }
-
-    @Override
-    public MySqlDriver getDriver() {
-        return (MySqlDriver) super.getDriver();
-    }
-    
-    @Override
-    public void init() {
-        super.init();
-        getMutableEntityType().addEffector(EXECUTE_SCRIPT, new EffectorBody<String>() {
-            @Override
-            public String call(ConfigBag parameters) {
-                return executeScript((String)parameters.getStringKey("commands"));
-            }
-        });
-    }
-
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-        setAttribute(DATASTORE_URL, String.format("mysql://%s:%s/", getAttribute(HOSTNAME), getAttribute(MYSQL_PORT)));
-        
-        /*        
-         * TODO status gives us things like:
-         *   Uptime: 2427  Threads: 1  Questions: 581  Slow queries: 0  Opens: 53  Flush tables: 1  Open tables: 35  Queries per second avg: 0.239
-         * So can extract lots of sensors from that.
-         */
-        Maybe<SshMachineLocation> machine = Locations.findUniqueSshMachineLocation(getLocations());
-        boolean retrieveUsageMetrics = getConfig(RETRIEVE_USAGE_METRICS);
-
-        if (machine.isPresent()) {
-            String cmd = getDriver().getStatusCmd();
-            feed = SshFeed.builder()
-                    .entity(this)
-                    .period(Duration.FIVE_SECONDS)
-                    .machine(machine.get())
-                    .poll(new SshPollConfig<Double>(QUERIES_PER_SECOND_FROM_MYSQL)
-                            .command(cmd)
-                            .onSuccess(new Function<SshPollValue, Double>() {
-                                @Override
-                                public Double apply(SshPollValue input) {
-                                    String q = Strings.getFirstWordAfter(input.getStdout(), "Queries per second avg:");
-                                    if (q==null) return null;
-                                    return Double.parseDouble(q);
-                                }})
-                            .setOnFailureOrException(null)
-                            .enabled(retrieveUsageMetrics))
-                    .poll(new SshPollConfig<Boolean>(SERVICE_PROCESS_IS_RUNNING)
-                            .command(cmd)
-                            .setOnSuccess(true)
-                            .setOnFailureOrException(false)
-                            .suppressDuplicates(true))
-                    .build();
-        } else {
-            LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; setting serviceUp immediately", getLocations());
-            setAttribute(SERVICE_UP, true);
-        }
-    }
-    
-    @Override
-    protected void disconnectSensors() {
-        if (feed != null) feed.stop();
-        super.disconnectSensors();
-    }
-
-    public int getPort() {
-        return getAttribute(MYSQL_PORT);
-    }
-    
-    public String getSocketUid() {
-        String result = getAttribute(MySqlNode.SOCKET_UID);
-        if (Strings.isBlank(result)) {
-            result = Identifiers.makeRandomId(6);
-            setAttribute(MySqlNode.SOCKET_UID, result);
-        }
-        return result;
-    }
-
-    public String getPassword() {
-        String result = getAttribute(MySqlNode.PASSWORD);
-        if (Strings.isBlank(result)) {
-            result = Identifiers.makeRandomId(6);
-            setAttribute(MySqlNode.PASSWORD, result);
-        }
-        return result;
-    }
-    
-    @Override
-    public String getShortName() {
-        return "MySQL";
-    }
-
-    @Override
-    public String executeScript(String commands) {
-        return getDriver().executeScriptAsync(commands).block().getStdout();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlRowParser.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlRowParser.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlRowParser.java
deleted file mode 100644
index cdd5149..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlRowParser.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 brooklyn.entity.database.mysql;
-
-import java.util.Map;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.text.Strings;
-
-public class MySqlRowParser {
-    public static Map<String, String> parseSingle(String row) {
-        Map<String, String> values = MutableMap.of();
-        String[] lines = row.split("\\n");
-        for (String line : lines) {
-            if (line.startsWith("*")) continue; // row delimiter
-            String[] arr = line.split(":", 2);
-            String key = arr[0].trim();
-            String value = Strings.emptyToNull(arr[1].trim());
-            values.put(key, value);
-        }
-        return values;
-    };
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlSshDriver.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlSshDriver.java
deleted file mode 100644
index 32b530d..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlSshDriver.java
+++ /dev/null
@@ -1,279 +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 brooklyn.entity.database.mysql;
-
-import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
-import static brooklyn.util.ssh.BashCommands.commandsToDownloadUrlsAs;
-import static brooklyn.util.ssh.BashCommands.installPackage;
-import static java.lang.String.format;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.database.DatastoreMixins;
-import brooklyn.entity.software.SshEffectorTasks;
-
-import org.apache.brooklyn.api.location.OsDetails;
-import org.apache.brooklyn.core.util.task.DynamicTasks;
-import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.location.basic.BasicOsDetails.OsVersions;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.io.FileUtil;
-import brooklyn.util.net.Urls;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.text.ComparableVersion;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.CountdownTimer;
-import brooklyn.util.time.Duration;
-
-import com.google.common.collect.ImmutableMap;
-
-/**
- * The SSH implementation of the {@link MySqlDriver}.
- */
-public class MySqlSshDriver extends AbstractSoftwareProcessSshDriver implements MySqlDriver {
-
-    public static final Logger log = LoggerFactory.getLogger(MySqlSshDriver.class);
-
-    public MySqlSshDriver(MySqlNodeImpl entity, SshMachineLocation machine) {
-        super(entity, machine);
-
-        entity.setAttribute(Attributes.LOG_FILE_LOCATION, getLogFile());
-    }
-
-    public String getOsTag() {
-        // e.g. "osx10.6-x86_64"; see http://www.mysql.com/downloads/mysql/#downloads
-        OsDetails os = getLocation().getOsDetails();
-        if (os == null) return "linux-glibc2.5-x86_64";
-        if (os.isMac()) {
-            String osp1 = os.getVersion()==null ? "osx10.8" //lowest common denominator
-                : new ComparableVersion(os.getVersion()).isGreaterThanOrEqualTo(OsVersions.MAC_10_9) ? "osx10.9"
-                : "osx10.8";  //lowest common denominator
-            if (!os.is64bit()) {
-                throw new IllegalStateException("Only 64 bit MySQL build is available for OS X");
-            }
-            return osp1+"-x86_64";
-        }
-        //assume generic linux
-        String osp1 = "linux-glibc2.5";
-        String osp2 = os.is64bit() ? "x86_64" : "i686";
-        return osp1+"-"+osp2;
-    }
-
-    public String getBaseDir() { return getExpandedInstallDir(); }
-
-    public String getDataDir() {
-        String result = entity.getConfig(MySqlNode.DATA_DIR);
-        return (result == null) ? "." : result;
-    }
-
-    public String getLogFile() {
-        return Urls.mergePaths(getRunDir(), "console.log");
-    }
-
-    public String getConfigFile() {
-        return "mymysql.cnf";
-    }
-
-    public String getInstallFilename() {
-        return String.format("mysql-%s-%s.tar.gz", getVersion(), getOsTag());
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this, ImmutableMap.of("filename", getInstallFilename()));
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("mysql-%s-%s", getVersion(), getOsTag()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-
-        List<String> commands = new LinkedList<String>();
-        commands.add(BashCommands.INSTALL_TAR);
-        commands.add(BashCommands.INSTALL_CURL);
-
-        commands.add("echo installing extra packages");
-        commands.add(installPackage(ImmutableMap.of("yum", "libgcc_s.so.1"), null));
-        commands.add(installPackage(ImmutableMap.of("yum", "libaio.so.1 libncurses.so.5", "apt", "libaio1 libaio-dev"), null));
-
-        // these deps are only needed on some OS versions but others don't need them
-        commands.add(installPackage(ImmutableMap.of("yum", "libaio", "apt", "ia32-libs"), null));
-        commands.add("echo finished installing extra packages");
-        commands.addAll(commandsToDownloadUrlsAs(urls, saveAs));
-        commands.add(format("tar xfvz %s", saveAs));
-
-        newScript(INSTALLING).body.append(commands).execute();
-    }
-
-    @Override
-    public MySqlNodeImpl getEntity() { return (MySqlNodeImpl) super.getEntity(); }
-    public int getPort() { return getEntity().getPort(); }
-    public String getSocketUid() { return getEntity().getSocketUid(); }
-    public String getPassword() { return getEntity().getPassword(); }
-
-    @Override
-    public void customize() {
-        copyDatabaseConfigScript();
-
-        newScript(CUSTOMIZING)
-            .updateTaskAndFailOnNonZeroResultCode()
-            .body.append(
-                "chmod 600 "+getConfigFile(),
-                getBaseDir()+"/scripts/mysql_install_db "+
-                    "--basedir="+getBaseDir()+" --datadir="+getDataDir()+" "+
-                    "--defaults-file="+getConfigFile())
-            .execute();
-
-        // launch, then we will configure it
-        launch();
-
-        CountdownTimer timer = Duration.seconds(20).countdownTimer();
-        boolean hasCreationScript = copyDatabaseCreationScript();
-        timer.waitForExpiryUnchecked();
-
-        DynamicTasks.queue(
-            SshEffectorTasks.ssh(
-                "cd "+getRunDir(),
-                getBaseDir()+"/bin/mysqladmin --defaults-file="+getConfigFile()+" --password= password "+getPassword()
-            ).summary("setting password"));
-
-        if (hasCreationScript)
-            executeScriptFromInstalledFileAsync("creation-script.sql").asTask().getUnchecked();
-
-        // not sure necessary to stop then subsequently launch, but seems safest
-        // (if skipping, use a flag in launch to indicate we've just launched it)
-        stop();
-    }
-
-    protected void copyDatabaseConfigScript() {
-        newScript(CUSTOMIZING).execute();  //create the directory
-
-        String configScriptContents = processTemplate(entity.getAttribute(MySqlNode.TEMPLATE_CONFIGURATION_URL));
-        Reader configContents = new StringReader(configScriptContents);
-
-        getMachine().copyTo(configContents, Urls.mergePaths(getRunDir(), getConfigFile()));
-    }
-
-    protected boolean copyDatabaseCreationScript() {
-        String creationScriptContents = DatastoreMixins.getDatabaseCreationScriptAsString(entity);
-        if (creationScriptContents==null) return false;
-
-        File templateFile = null;
-        BufferedWriter writer = null;
-        try {
-            templateFile = File.createTempFile("mysql", null);
-            FileUtil.setFilePermissionsTo600(templateFile);
-            writer = new BufferedWriter(new FileWriter(templateFile));
-            writer.write(creationScriptContents);
-            writer.flush();
-            copyTemplate(templateFile.getAbsoluteFile(), getRunDir() + "/creation-script.sql");
-        } catch (IOException e) {
-            throw Exceptions.propagate(e);
-        } finally {
-            if (writer != null) Streams.closeQuietly(writer);
-            if (templateFile != null) templateFile.delete();
-        }
-        return true;
-    }
-
-    public String getMySqlServerOptionsString() {
-        Map<String, Object> options = entity.getConfig(MySqlNode.MYSQL_SERVER_CONF);
-        StringBuilder result = new StringBuilder();
-        if (groovyTruth(options)) {
-            for (Map.Entry<String, Object> entry : options.entrySet()) {
-                result.append(entry.getKey());
-                String value = entry.getValue().toString();
-                if (!Strings.isEmpty(value)) {
-                    result.append(" = ").append(value);
-                }
-                result.append('\n');
-            }
-        }
-        return result.toString();
-    }
-
-    @Override
-    public void launch() {
-        entity.setAttribute(MySqlNode.PID_FILE, getRunDir() + "/" + AbstractSoftwareProcessSshDriver.PID_FILENAME);
-        newScript(MutableMap.of("usePidFile", true), LAUNCHING)
-            .updateTaskAndFailOnNonZeroResultCode()
-            .body.append(format("nohup %s/bin/mysqld --defaults-file=%s --user=`whoami` > %s 2>&1 < /dev/null &", getBaseDir(), getConfigFile(), getLogFile()))
-            .execute();
-    }
-
-    @Override
-    public boolean isRunning() {
-        return newScript(MutableMap.of("usePidFile", false), CHECK_RUNNING)
-            .body.append(getStatusCmd())
-            .execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        newScript(MutableMap.of("usePidFile", true), STOPPING).execute();
-    }
-
-    @Override
-    public void kill() {
-        newScript(MutableMap.of("usePidFile", true), KILLING).execute();
-    }
-
-    @Override
-    public String getStatusCmd() {
-        return format("%s/bin/mysqladmin --defaults-file=%s status", getBaseDir(), Urls.mergePaths(getRunDir(), getConfigFile()));
-    }
-
-    @Override
-    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands) {
-        String filename = "mysql-commands-"+Identifiers.makeRandomId(8);
-        DynamicTasks.queue(SshEffectorTasks.put(Urls.mergePaths(getRunDir(), filename)).contents(commands).summary("copying datastore script to execute "+filename));
-        return executeScriptFromInstalledFileAsync(filename);
-    }
-
-    public ProcessTaskWrapper<Integer> executeScriptFromInstalledFileAsync(String filenameAlreadyInstalledAtServer) {
-        return DynamicTasks.queue(
-                SshEffectorTasks.ssh(
-                                "cd "+getRunDir(),
-                                getBaseDir()+"/bin/mysql --defaults-file="+getConfigFile()+" < "+filenameAlreadyInstalledAtServer)
-                        .requiringExitCodeZero()
-                        .summary("executing datastore script "+filenameAlreadyInstalledAtServer));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlDriver.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
deleted file mode 100644
index 02ad039..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
+++ /dev/null
@@ -1,33 +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 brooklyn.entity.database.postgresql;
-
-import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
-
-import brooklyn.entity.basic.SoftwareProcessDriver;
-
-/**
- * The {@link brooklyn.entity.basic.SoftwareProcessDriver} for PostgreSQL.
- */
-public interface PostgreSqlDriver extends SoftwareProcessDriver {
-
-    String getStatusCmd();
-
-    ProcessTaskWrapper<Integer> executeScriptAsync(String commands);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNode.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNode.java
deleted file mode 100644
index 20f4b76..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNode.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 brooklyn.entity.database.postgresql;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.Effector;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.entity.trait.HasShortName;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.database.DatabaseNode;
-import brooklyn.entity.database.DatastoreMixins;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.effector.Effectors;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-
-import org.apache.brooklyn.location.basic.PortRanges;
-
-/**
- * PostgreSQL database node entity.
- * <p>
- * <ul>
- * <li>You may need to increase shared memory settings in the kernel depending on the setting of
- * the {@link #SHARED_MEMORY_BUFFER} key. The minimumm value is <em>128kB</em>. See the PostgreSQL
- * <a href="http://www.postgresql.org/docs/9.1/static/kernel-resources.html">documentation</a>.
- * <li>You will also need to enable passwordless sudo.
- * </ul>
- */
-@Catalog(name="PostgreSQL Node", description="PostgreSQL is an object-relational database management system (ORDBMS)", iconUrl="classpath:///postgresql-logo-200px.png")
-@ImplementedBy(PostgreSqlNodeImpl.class)
-public interface PostgreSqlNode extends SoftwareProcess, HasShortName, DatastoreCommon, DatabaseNode {
-    
-    @SetFromFlag("version")
-    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "9.3-1");//"9.1-4");
-
-    @SetFromFlag("configFileUrl")
-    ConfigKey<String> CONFIGURATION_FILE_URL = ConfigKeys.newStringConfigKey(
-            "postgresql.config.file.url", "URL where PostgreSQL configuration file can be found; "
-                + "if not supplied the blueprint uses the default and customises it");
-
-    @SetFromFlag("authConfigFileUrl")
-    ConfigKey<String> AUTHENTICATION_CONFIGURATION_FILE_URL = ConfigKeys.newStringConfigKey(
-            "postgresql.authConfig.file.url", "URL where PostgreSQL host-based authentication configuration file can be found; "
-                + "if not supplied the blueprint uses the default and customises it");
-
-    @SetFromFlag("port")
-    PortAttributeSensorAndConfigKey POSTGRESQL_PORT = new PortAttributeSensorAndConfigKey(
-            "postgresql.port", "PostgreSQL port", PortRanges.fromString("5432+"));
-
-    @SetFromFlag("sharedMemory")
-    ConfigKey<String> SHARED_MEMORY = ConfigKeys.newStringConfigKey(
-            "postgresql.sharedMemory", "Size of shared memory buffer (must specify as kB, MB or GB, minimum 128kB)", "4MB");
-
-    @SetFromFlag("maxConnections")
-    ConfigKey<Integer> MAX_CONNECTIONS = ConfigKeys.newIntegerConfigKey(
-            "postgresql.maxConnections", "Maximum number of connections to the database", 100);
-
-    @SetFromFlag("disconnectOnStop")
-    ConfigKey<Boolean> DISCONNECT_ON_STOP = ConfigKeys.newBooleanConfigKey(
-            "postgresql.disconnect.on.stop", "If true, PostgreSQL will immediately disconnet (pg_ctl -m immediate stop) all current connections when the node is stopped", true);
-
-    @SetFromFlag("pollPeriod")
-    ConfigKey<Long> POLL_PERIOD = ConfigKeys.newLongConfigKey(
-            "postgresql.sensorpoll", "Poll period (in milliseconds)", 1000L);
-
-    Effector<String> EXECUTE_SCRIPT = Effectors.effector(DatastoreMixins.EXECUTE_SCRIPT)
-            .description("Executes the given script contents using psql")
-            .buildAbstract();
-
-    Integer getPostgreSqlPort();
-    String getSharedMemory();
-    Integer getMaxConnections();
-
-    String executeScript(String commands);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
deleted file mode 100644
index d82e637..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
+++ /dev/null
@@ -1,171 +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 brooklyn.entity.database.postgresql;
-
-import org.apache.brooklyn.api.entity.Effector;
-import org.apache.brooklyn.core.util.ResourceUtils;
-import org.apache.brooklyn.core.util.config.ConfigBag;
-import org.apache.brooklyn.core.util.task.DynamicTasks;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.EffectorStartableImpl;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.chef.ChefConfig;
-import brooklyn.entity.chef.ChefLifecycleEffectorTasks;
-import brooklyn.entity.chef.ChefServerTasks;
-import brooklyn.entity.effector.EffectorBody;
-import brooklyn.entity.effector.Effectors;
-import brooklyn.entity.software.SshEffectorTasks;
-import brooklyn.event.feed.ssh.SshFeed;
-import brooklyn.event.feed.ssh.SshPollConfig;
-
-import org.apache.brooklyn.location.basic.Locations;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.collections.Jsonya;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.ssh.BashCommands;
-
-public class PostgreSqlNodeChefImplFromScratch extends EffectorStartableImpl implements PostgreSqlNode {
-
-    private static final Logger LOG = LoggerFactory.getLogger(PostgreSqlNodeChefImplFromScratch.class);
-
-    public static final Effector<String> EXECUTE_SCRIPT = Effectors.effector(String.class, "executeScript")
-            .description("invokes a script")
-            .parameter(ExecuteScriptEffectorBody.SCRIPT)
-            .impl(new ExecuteScriptEffectorBody()).build();
-    
-    private SshFeed feed;
-
-    public void init() {
-        super.init();
-        new ChefPostgreSqlLifecycle().attachLifecycleEffectors(this);
-    }
-
-    @Override
-    public Integer getPostgreSqlPort() { return getAttribute(POSTGRESQL_PORT); }
-
-    @Override
-    public String getSharedMemory() { return getConfig(SHARED_MEMORY); }
-
-    @Override
-    public Integer getMaxConnections() { return getConfig(MAX_CONNECTIONS); }
-
-    @Override
-    public String getShortName() {
-        return "PostgreSQL";
-    }
-
-    public static class ChefPostgreSqlLifecycle extends ChefLifecycleEffectorTasks {
-        {
-            usePidFile("/var/run/postgresql/*.pid");
-            useService("postgresql");
-        }
-        protected void startWithKnifeAsync() {
-            Entities.warnOnIgnoringConfig(entity(), ChefConfig.CHEF_LAUNCH_RUN_LIST);
-            Entities.warnOnIgnoringConfig(entity(), ChefConfig.CHEF_LAUNCH_ATTRIBUTES);
-            
-            DynamicTasks.queue(
-                    ChefServerTasks
-                        .knifeConvergeRunList("postgresql::server")
-                        .knifeAddAttributes(Jsonya
-                            .at("postgresql", "config").add(
-                                "port", entity().getPostgreSqlPort(), 
-                                "listen_addresses", "*").getRootMap())
-                        .knifeAddAttributes(Jsonya
-                            .at("postgresql", "pg_hba").list().map().add(
-                                "type", "host", "db", "all", "user", "all", 
-                                "addr", "0.0.0.0/0", "method", "md5").getRootMap()) 
-                        // no other arguments currenty supported; chef will pick a password for us
-                );
-        }
-        protected void postStartCustom() {
-            super.postStartCustom();
-
-            // now run the creation script
-            String creationScript;
-            String creationScriptUrl = entity().getConfig(PostgreSqlNode.CREATION_SCRIPT_URL);
-            if (creationScriptUrl != null) {
-                creationScript = ResourceUtils.create(entity()).getResourceAsString(creationScriptUrl);
-            } else {
-                creationScript = entity().getConfig(PostgreSqlNode.CREATION_SCRIPT_CONTENTS);
-            }
-            entity().executeScript(creationScript);
-
-            // and finally connect sensors
-            entity().connectSensors();
-        }
-        protected void preStopCustom() {
-            entity().disconnectSensors();
-            super.preStopCustom();
-        }
-        protected PostgreSqlNodeChefImplFromScratch entity() {
-            return (PostgreSqlNodeChefImplFromScratch) super.entity();
-        }
-    }
-    
-    public static class ExecuteScriptEffectorBody extends EffectorBody<String> {
-        public static final ConfigKey<String> SCRIPT = ConfigKeys.newStringConfigKey("script", "contents of script to run");
-        
-        public String call(ConfigBag parameters) {
-            return DynamicTasks.queue(SshEffectorTasks.ssh(
-                    BashCommands.pipeTextTo(
-                        parameters.get(SCRIPT),
-                        BashCommands.sudoAsUser("postgres", "psql --file -")))
-                    .requiringExitCodeZero()).getStdout();
-        }
-    }
-    
-    protected void connectSensors() {
-        setAttribute(DATASTORE_URL, String.format("postgresql://%s:%s/", getAttribute(HOSTNAME), getAttribute(POSTGRESQL_PORT)));
-
-        Maybe<SshMachineLocation> machine = Locations.findUniqueSshMachineLocation(getLocations());
-
-        if (machine.isPresent()) {
-            feed = SshFeed.builder()
-                    .entity(this)
-                    .machine(machine.get())
-                    .poll(new SshPollConfig<Boolean>(SERVICE_UP)
-                            .command("ps -ef | grep [p]ostgres")
-                            .setOnSuccess(true)
-                            .setOnFailureOrException(false))
-                    .build();
-        } else {
-            LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; setting serviceUp immediately", getLocations());
-        }
-    }
-
-    protected void disconnectSensors() {
-        if (feed != null) feed.stop();
-    }
-
-    @Override
-    public String executeScript(String commands) {
-        return Entities.invokeEffector(this, this, EXECUTE_SCRIPT,
-                ConfigBag.newInstance().configure(ExecuteScriptEffectorBody.SCRIPT, commands).getAllConfig()).getUnchecked();
-    }
-
-    @Override
-    public void populateServiceNotUpDiagnostics() {
-        // TODO no-op currently; should check ssh'able etc
-    }    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java
deleted file mode 100644
index c4b02de..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.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 brooklyn.entity.database.postgresql;
-
-import org.apache.brooklyn.core.util.config.ConfigBag;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.effector.EffectorBody;
-
-public class PostgreSqlNodeImpl extends SoftwareProcessImpl implements PostgreSqlNode {
-
-    private static final Logger LOG = LoggerFactory.getLogger(PostgreSqlNodeImpl.class);
-
-    public Class<?> getDriverInterface() {
-        return PostgreSqlDriver.class;
-    }
-    @Override
-    public PostgreSqlDriver getDriver() {
-        return (PostgreSqlDriver) super.getDriver();
-    }
-
-    @Override
-    public Integer getPostgreSqlPort() { return getAttribute(POSTGRESQL_PORT); }
-
-    @Override
-    public String getSharedMemory() { return getConfig(SHARED_MEMORY); }
-
-    @Override
-    public Integer getMaxConnections() { return getConfig(MAX_CONNECTIONS); }
-
-    @Override
-    public void init() {
-        super.init();
-        getMutableEntityType().addEffector(EXECUTE_SCRIPT, new EffectorBody<String>() {
-            @Override
-            public String call(ConfigBag parameters) {
-                return executeScript((String) parameters.getStringKey("commands"));
-            }
-        });
-    }
-
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-        connectServiceUpIsRunning();
-        setAttribute(DATASTORE_URL, String.format("postgresql://%s:%s/", getAttribute(HOSTNAME), getAttribute(POSTGRESQL_PORT)));
-    }
-
-    @Override
-    protected void disconnectSensors() {
-        disconnectServiceUpIsRunning();
-        super.disconnectSensors();
-    }
-    
-    @Override
-    public String getShortName() {
-        return "PostgreSQL";
-    }
-
-    @Override
-    public String executeScript(String commands) {
-        return getDriver()
-                .executeScriptAsync(commands)
-                .block()
-                .getStdout();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSpecs.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSpecs.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSpecs.java
deleted file mode 100644
index 5d90bdd..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSpecs.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 brooklyn.entity.database.postgresql;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-
-import brooklyn.entity.chef.ChefConfig;
-import brooklyn.entity.chef.ChefConfig.ChefModes;
-
-/**
- * Utiltiy for creating specs for {@link PostgreSqlNode} instances.
- */
-public class PostgreSqlSpecs {
-
-    private PostgreSqlSpecs() {}
-
-    public static EntitySpec<PostgreSqlNode> spec() {
-        return EntitySpec.create(PostgreSqlNode.class);
-    }
-
-    /** Requires {@code knife}. */
-    public static EntitySpec<PostgreSqlNode> specChef() {
-        EntitySpec<PostgreSqlNode> spec = EntitySpec.create(PostgreSqlNode.class, PostgreSqlNodeChefImplFromScratch.class);
-        spec.configure(ChefConfig.CHEF_MODE, ChefModes.KNIFE);
-        return spec;
-    }
-}


[23/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshTool.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshTool.java
new file mode 100644
index 0000000..4361f46
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshTool.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.core.util.internal.ssh;
+
+import static brooklyn.entity.basic.ConfigKeys.newConfigKey;
+import static brooklyn.entity.basic.ConfigKeys.newStringConfigKey;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.util.stream.KnownSizeInputStream;
+import brooklyn.util.time.Duration;
+
+/**
+ * Defines the methods available on the various different implementations of SSH,
+ * and configuration options which are also generally available.
+ * <p>
+ * The config keys in this class can be supplied (or their string equivalents, where the flags/props take {@code Map<String,?>})
+ * to influence configuration, either for the tool/session itself or for individual commands.
+ * <p>
+ * To specify some of these properties on a global basis, use the variants of the keys here
+ * contained in {@link ConfigKeys}
+ * (which are generally {@value #BROOKLYN_CONFIG_KEY_PREFIX} prefixed to the names of keys here).
+ */
+public interface SshTool extends ShellTool {
+    
+    /** Public-facing global config keys for Brooklyn are defined in ConfigKeys, 
+     * and have this prefix pre-prended to the config keys in this class. 
+     * These keys are detected from entity/global config and automatically applied to ssh executions. */
+    public static final String BROOKLYN_CONFIG_KEY_PREFIX = "brooklyn.ssh.config.";
+    
+    public static final ConfigKey<String> PROP_TOOL_CLASS = newStringConfigKey("tool.class", "SshTool implementation to use", null);
+    
+    public static final ConfigKey<String> PROP_HOST = newStringConfigKey("host", "Host to connect to (required)", null);
+    public static final ConfigKey<Integer> PROP_PORT = newConfigKey("port", "Port on host to connect to", 22);
+    public static final ConfigKey<String> PROP_USER = newConfigKey("user", "User to connect as", System.getProperty("user.name"));
+    public static final ConfigKey<String> PROP_PASSWORD = newStringConfigKey("password", "Password to use to connect", null);
+    
+    public static final ConfigKey<String> PROP_PRIVATE_KEY_FILE = newStringConfigKey("privateKeyFile", "the path of an ssh private key file; leave blank to use defaults (i.e. ~/.ssh/id_rsa and id_dsa)", null);
+    public static final ConfigKey<String> PROP_PRIVATE_KEY_DATA = newStringConfigKey("privateKeyData", "the private ssh key (e.g. contents of an id_rsa or id_dsa file)", null);
+    public static final ConfigKey<String> PROP_PRIVATE_KEY_PASSPHRASE = newStringConfigKey("privateKeyPassphrase", "the passphrase for the ssh private key", null);
+    public static final ConfigKey<Boolean> PROP_STRICT_HOST_KEY_CHECKING = newConfigKey("strictHostKeyChecking", "whether to check the remote host's identification; defaults to false", false);
+    public static final ConfigKey<Boolean> PROP_ALLOCATE_PTY = newConfigKey("allocatePTY", "whether to allocate PTY (vt100); if true then stderr is sent to stdout, but sometimes required for sudo'ing due to requiretty", false);
+
+    public static final ConfigKey<Long> PROP_CONNECT_TIMEOUT = newConfigKey("connectTimeout", "Timeout in millis when establishing an SSH connection; if 0 then uses default (usually 30s)", 0L);
+    public static final ConfigKey<Long> PROP_SESSION_TIMEOUT = newConfigKey("sessionTimeout", "Timeout in millis for an ssh session; if 0 then uses default", 0L);
+    public static final ConfigKey<Integer> PROP_SSH_TRIES = newConfigKey("sshTries", "Max number of times to attempt ssh operations", 4);
+    public static final ConfigKey<Long> PROP_SSH_TRIES_TIMEOUT = newConfigKey("sshTriesTimeout", "Time limit for attempting retries; will not interrupt tasks, but stops retrying after a total amount of elapsed time", Duration.TWO_MINUTES.toMilliseconds());
+    public static final ConfigKey<Long> PROP_SSH_RETRY_DELAY = newConfigKey("sshRetryDelay", "Time (in milliseconds) before first ssh-retry, after which it will do exponential backoff", 50L);
+
+    // NB -- items above apply for _session_ (a tool), below apply for a _call_
+    // TODO would be nice to track which arguments are used, so we can indicate whether extras are supplied
+
+    public static final ConfigKey<String> PROP_PERMISSIONS = newConfigKey("permissions", "Default permissions for files copied/created on remote machine; must be four-digit octal string, default '0644'", "0644");
+    public static final ConfigKey<Long> PROP_LAST_MODIFICATION_DATE = newConfigKey("lastModificationDate", "Last-modification-date to be set on files copied/created (should be UTC/1000, ie seconds since 1970; default 0 usually means current)", 0L);
+    public static final ConfigKey<Long> PROP_LAST_ACCESS_DATE = newConfigKey("lastAccessDate", "Last-access-date to be set on files copied/created (should be UTC/1000, ie seconds since 1970; default 0 usually means lastModificationDate)", 0L);
+    public static final ConfigKey<Integer> PROP_OWNER_UID = newConfigKey("ownerUid", "Default owner UID (not username) for files created on remote machine; default is unset", -1);
+    
+    // TODO remove unnecessary "public static final" modifiers
+    
+    // TODO Could define the following in SshMachineLocation, or some such?
+    //public static ConfigKey<String> PROP_LOG_PREFIX = newStringKey("logPrefix", "???", ???);
+    //public static ConfigKey<Boolean> PROP_NO_STDOUT_LOGGING = newStringKey("noStdoutLogging", "???", ???);
+    //public static ConfigKey<Boolean> PROP_NO_STDOUT_LOGGING = newStringKey("noStdoutLogging", "???", ???);
+
+    /**
+     * @throws SshException
+     */
+    public void connect();
+
+    /**
+     * @deprecated since 0.7.0; (since much earlier) this ignores the argument in favour of {@link #PROP_SSH_TRIES}
+     * 
+     * @param maxAttempts
+     * @throws SshException
+     */
+    public void connect(int maxAttempts);
+
+    public void disconnect();
+
+    public boolean isConnected();
+
+    /**
+     * @see super{@link #execScript(Map, List, Map)}
+     * @throws SshException If failed to connect
+     */
+    @Override
+    public int execScript(Map<String,?> props, List<String> commands, Map<String,?> env);
+
+    /**
+     * @see #execScript(Map, List, Map)
+     */
+    @Override
+    public int execScript(Map<String,?> props, List<String> commands);
+
+    /**
+     * @see super{@link #execCommands(Map, List, Map)}
+     * @throws SshException If failed to connect
+     */
+    @Override
+    public int execCommands(Map<String,?> properties, List<String> commands, Map<String,?> env);
+
+    /**
+     * @see #execCommands(Map, List, Map)
+     */
+    @Override
+    public int execCommands(Map<String,?> properties, List<String> commands);
+
+    /**
+     * Copies the file to the server at the given path.
+     * If path is null, empty, '.', '..', or ends with '/' then file name is used.
+     * <p>
+     * The file will not preserve the permission of last _access_ date.
+     * 
+     * Optional properties are:
+     * <ul>
+     *   <li>'permissions' (e.g. "0644") - see {@link #PROP_PERMISSIONS}
+     *   <li>'lastModificationDate' see {@link #PROP_LAST_MODIFICATION_DATE}; not supported by all SshTool implementations
+     *   <li>'lastAccessDate' see {@link #PROP_LAST_ACCESS_DATE}; not supported by all SshTool implementations
+     * </ul>
+     * 
+     * @return exit code (not supported by all SshTool implementations, usually throwing on error;
+     * sometimes possibly returning 0 even on error (?) )
+     */
+    public int copyToServer(Map<String,?> props, File localFile, String pathAndFileOnRemoteServer);
+
+    /**
+     * Closes the given input stream before returning.
+     * Consider using {@link KnownSizeInputStream} for efficiency when the size of the stream is known.
+     * 
+     * @see #copyToServer(Map, File, String)
+     */
+    public int copyToServer(Map<String,?> props, InputStream contents, String pathAndFileOnRemoteServer);
+
+    /**
+     * @see #copyToServer(Map, File, String)
+     */
+    public int copyToServer(Map<String,?> props, byte[] contents, String pathAndFileOnRemoteServer);
+
+    /**
+     * Copies the file from the server at the given path.
+     *
+     * @return exit code (not supported by all SshTool implementations, usually throwing on error;
+     * sometimes possibly returning 0 even on error (?) )
+     */
+    public int copyFromServer(Map<String,?> props, String pathAndFileOnRemoteServer, File local);
+
+    // TODO might be more efficicent than copyFrom by way of temp file
+//    /**
+//     * Reads from the file at the given path on the remote server.
+//     */
+//    public InputStream streamFromServer(Map<String,?> props, String pathAndFileOnRemoteServer);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliTool.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliTool.java
new file mode 100644
index 0000000..5fe0408
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliTool.java
@@ -0,0 +1,317 @@
+/*
+ * 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.util.internal.ssh.cli;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.internal.ssh.SshAbstractTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.cli.SshCliTool;
+import org.apache.brooklyn.core.util.internal.ssh.process.ProcessTool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.text.StringEscapes.BashStringEscapes;
+import brooklyn.util.text.Strings;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+/**
+ * For ssh and scp commands, delegating to system calls.
+ */
+public class SshCliTool extends SshAbstractTool implements SshTool {
+
+    // TODO No retry support, with backoffLimitedRetryHandler
+    
+    private static final Logger LOG = LoggerFactory.getLogger(SshCliTool.class);
+
+    public static final ConfigKey<String> PROP_SSH_EXECUTABLE = ConfigKeys.newStringConfigKey("sshExecutable", "command to execute for ssh (defaults to \"ssh\", but could be overridden to sshg3 for Tectia for example)", "ssh");
+    public static final ConfigKey<String> PROP_SSH_FLAGS = ConfigKeys.newStringConfigKey("sshFlags", "flags to pass to ssh, as a space separated list", "");
+    public static final ConfigKey<String> PROP_SCP_EXECUTABLE = ConfigKeys.newStringConfigKey("scpExecutable", "command to execute for scp (defaults to \"scp\", but could be overridden to scpg3 for Tectia for example)", "scp");
+
+    public static Builder<SshCliTool,?> builder() {
+        return new ConcreteBuilder();
+    }
+    
+    private static class ConcreteBuilder extends Builder<SshCliTool, ConcreteBuilder> {
+    }
+    
+    public static class Builder<T extends SshCliTool, B extends Builder<T,B>> extends AbstractSshToolBuilder<T,B> {
+        private String sshExecutable;
+        private String sshFlags;
+        private String scpExecutable;
+
+        @Override
+        public B from(Map<String,?> props) {
+            super.from(props);
+            sshExecutable = getOptionalVal(props, PROP_SSH_EXECUTABLE);
+            sshFlags = getOptionalVal(props, PROP_SSH_FLAGS);
+            scpExecutable = getOptionalVal(props, PROP_SCP_EXECUTABLE);
+            return self();
+        }
+        public B sshExecutable(String val) {
+            this.sshExecutable = val; return self();
+        }
+        public B scpExecutable(String val) {
+            this.scpExecutable = val; return self();
+        }
+        @SuppressWarnings("unchecked")
+        public T build() {
+            return (T) new SshCliTool(this);
+        }
+    }
+
+    private final String sshExecutable;
+    private final String sshFlags;
+    private final String scpExecutable;
+
+    public SshCliTool(Map<String,?> map) {
+        this(builder().from(map));
+    }
+    
+    private SshCliTool(Builder<?,?> builder) {
+        super(builder);
+        sshExecutable = checkNotNull(builder.sshExecutable);
+        sshFlags = checkNotNull(builder.sshFlags);
+        scpExecutable = checkNotNull(builder.scpExecutable);
+        if (LOG.isTraceEnabled()) LOG.trace("Created SshCliTool {} ({})", this, System.identityHashCode(this));
+    }
+    
+    @Override
+    public void connect() {
+        // no-op
+    }
+
+    @Override
+    public void connect(int maxAttempts) {
+        // no-op
+    }
+
+    @Override
+    public void disconnect() {
+        if (LOG.isTraceEnabled()) LOG.trace("Disconnecting SshCliTool {} ({}) - no-op", this, System.identityHashCode(this));
+        // no-op
+    }
+
+    @Override
+    public boolean isConnected() {
+        // TODO Always pretends to be connected
+        return true;
+    }
+
+    @Override
+    public int copyToServer(java.util.Map<String,?> props, byte[] contents, String pathAndFileOnRemoteServer) {
+        return copyTempFileToServer(props, writeTempFile(contents), pathAndFileOnRemoteServer);
+    }
+    
+    @Override
+    public int copyToServer(java.util.Map<String,?> props, InputStream contents, String pathAndFileOnRemoteServer) {
+        return copyTempFileToServer(props, writeTempFile(contents), pathAndFileOnRemoteServer);
+    }
+    
+    @Override
+    public int copyToServer(Map<String,?> props, File f, String pathAndFileOnRemoteServer) {
+        if (hasVal(props, PROP_LAST_MODIFICATION_DATE)) {
+            LOG.warn("Unsupported ssh feature, setting lastModificationDate for {}:{}", this, pathAndFileOnRemoteServer);
+        }
+        if (hasVal(props, PROP_LAST_ACCESS_DATE)) {
+            LOG.warn("Unsupported ssh feature, setting lastAccessDate for {}:{}", this, pathAndFileOnRemoteServer);
+        }
+        String permissions = getOptionalVal(props, PROP_PERMISSIONS);
+        
+        int uid = getOptionalVal(props, PROP_OWNER_UID);
+        
+        int result = scpToServer(props, f, pathAndFileOnRemoteServer);
+        if (result == 0) {
+            result = chmodOnServer(props, permissions, pathAndFileOnRemoteServer);
+            if (result == 0) {
+                if (uid != -1) {
+                    result = chownOnServer(props, uid, pathAndFileOnRemoteServer);
+                    if (result != 0) {
+                        LOG.warn("Error setting file owner to {}, after copying file {} to {}:{}; exit code {}", new Object[] { uid, pathAndFileOnRemoteServer, this, f, result });
+                    }
+                }
+            } else {
+                LOG.warn("Error setting file permissions to {}, after copying file {} to {}:{}; exit code {}", new Object[] { permissions, pathAndFileOnRemoteServer, this, f, result });
+            }
+        } else {
+            LOG.warn("Error copying file {} to {}:{}; exit code {}", new Object[] {pathAndFileOnRemoteServer, this, f, result});
+        }
+        return result;
+    }
+
+    private int chownOnServer(Map<String,?> props, int uid, String remote) {
+        return sshExec(props, "chown "+uid+" "+remote);
+    }
+    
+    private int copyTempFileToServer(Map<String,?> props, File f, String pathAndFileOnRemoteServer) {
+        try {
+            return copyToServer(props, f, pathAndFileOnRemoteServer);
+        } finally {
+            f.delete();
+        }
+    }
+
+    @Override
+    public int copyFromServer(Map<String,?> props, String pathAndFileOnRemoteServer, File localFile) {
+        return scpFromServer(props, pathAndFileOnRemoteServer, localFile);
+    }
+
+    @Override
+    public int execScript(final Map<String,?> props, final List<String> commands, final Map<String,?> env) {
+        return new ToolAbstractExecScript(props) {
+            public int run() {
+                String scriptContents = toScript(props, commands, env);
+                if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} as script: {}", host, scriptContents);
+                copyTempFileToServer(ImmutableMap.of("permissions", "0700"), writeTempFile(scriptContents), scriptPath);
+
+                String cmd = Strings.join(buildRunScriptCommand(), separator);
+                return asInt(sshExec(props, cmd), -1);
+            }
+        }.run();
+    }
+
+    @Override
+    public int execCommands(Map<String,?> props, List<String> commands, Map<String,?> env) {
+        Map<String,Object> props2 = new MutableMap<String,Object>();
+        if (props!=null) props2.putAll(props);
+        props2.put(SshTool.PROP_NO_EXTRA_OUTPUT.getName(), true);
+        return execScript(props2, commands, env);
+    }
+    
+    private int scpToServer(Map<String,?> props, File local, String remote) {
+        String to = (Strings.isEmpty(getUsername()) ? "" : getUsername()+"@")+getHostAddress()+":"+remote;
+        return scpExec(props, local.getAbsolutePath(), to);
+    }
+
+    private int scpFromServer(Map<String,?> props, String remote, File local) {
+        String from = (Strings.isEmpty(getUsername()) ? "" : getUsername()+"@")+getHostAddress()+":"+remote;
+        return scpExec(props, from, local.getAbsolutePath());
+    }
+    
+    private int chmodOnServer(Map<String,?> props, String permissions, String remote) {
+        return sshExec(props, "chmod "+permissions+" "+remote);
+    }
+
+    private int scpExec(Map<String,?> props, String from, String to) {
+        File tempFile = null;
+        try {
+            List<String> cmd = Lists.newArrayList();
+            cmd.add(getOptionalVal(props, PROP_SCP_EXECUTABLE, scpExecutable));
+            if (privateKeyFile != null) {
+                cmd.add("-i");
+                cmd.add(privateKeyFile.getAbsolutePath());
+            } else if (privateKeyData != null) {
+                tempFile = writeTempFile(privateKeyData);
+                cmd.add("-i");
+                cmd.add(tempFile.getAbsolutePath());
+            }
+            if (!strictHostKeyChecking) {
+                cmd.add("-o");
+                cmd.add("StrictHostKeyChecking=no");
+            }
+            if (port != 22) {
+                cmd.add("-P");
+                cmd.add(""+port);
+            }
+            cmd.add(from);
+            cmd.add(to);
+            
+            if (LOG.isTraceEnabled()) LOG.trace("Executing with command: {}", cmd);
+            int result = execProcess(props, cmd);
+            
+            if (LOG.isTraceEnabled()) LOG.trace("Executed command: {}; exit code {}", cmd, result);
+            return result;
+
+        } finally {
+            if (tempFile != null) tempFile.delete();
+        }
+    }
+    
+    private int sshExec(Map<String,?> props, String command) {
+        File tempKeyFile = null;
+        try {
+            List<String> cmd = Lists.newArrayList();
+            cmd.add(getOptionalVal(props, PROP_SSH_EXECUTABLE, sshExecutable));
+            String propsFlags = getOptionalVal(props, PROP_SSH_FLAGS, sshFlags);
+            if (propsFlags!=null && propsFlags.trim().length()>0)
+                cmd.addAll(Arrays.asList(propsFlags.trim().split(" ")));
+            if (privateKeyFile != null) {
+                cmd.add("-i");
+                cmd.add(privateKeyFile.getAbsolutePath());
+            } else if (privateKeyData != null) {
+                tempKeyFile = writeTempFile(privateKeyData);
+                cmd.add("-i");
+                cmd.add(tempKeyFile.getAbsolutePath());
+            }
+            if (!strictHostKeyChecking) {
+                cmd.add("-o");
+                cmd.add("StrictHostKeyChecking=no");
+            }
+            if (port != 22) {
+                cmd.add("-P");
+                cmd.add(""+port);
+            }
+            if (allocatePTY) {
+                // have to be careful with double -tt as it can leave a shell session active
+                // when done from bash (ie  ssh -tt localhost < /tmp/myscript.sh);
+                // hover that doesn't seem to be a problem the way we use it from brooklyn
+                // (and note single -t doesn't work _programmatically_ since the input isn't a terminal)
+                cmd.add("-tt");
+            }
+            cmd.add((Strings.isEmpty(getUsername()) ? "" : getUsername()+"@")+getHostAddress());
+            
+            cmd.add("bash -c "+BashStringEscapes.wrapBash(command));
+            // previously we tried these approaches:
+            //cmd.add("$(<"+tempCmdFile.getAbsolutePath()+")");
+            // only pays attention to the first word; the "; echo Executing ..." get treated as arguments
+            // to the script in the first word, when invoked from java (when invoked from prompt the behaviour is as desired)
+            //cmd.add("\""+command+"\"");
+            // only works if command is a single word
+            //cmd.add(tempCmdFile.getAbsolutePath());
+            // above of course only works if the metafile is copied across
+            
+            if (LOG.isTraceEnabled()) LOG.trace("Executing ssh with command: {} (with {})", command, cmd);
+            int result = execProcess(props, cmd);
+            
+            if (LOG.isTraceEnabled()) LOG.trace("Executed command: {}; exit code {}", cmd, result);
+            return result;
+            
+        } finally {
+            if (tempKeyFile != null) tempKeyFile.delete();
+        }
+    }
+
+    private int execProcess(Map<String,?> props, List<String> cmdWords) {
+        OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
+        OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
+        return ProcessTool.execSingleProcess(cmdWords, null, (File)null, out, err, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessTool.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessTool.java
new file mode 100644
index 0000000..8f33143
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessTool.java
@@ -0,0 +1,215 @@
+/*
+ * 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.util.internal.ssh.process;
+
+import static brooklyn.entity.basic.ConfigKeys.newConfigKey;
+import static brooklyn.entity.basic.ConfigKeys.newStringConfigKey;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.internal.ssh.ShellAbstractTool;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshException;
+import org.apache.brooklyn.core.util.internal.ssh.process.ProcessTool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.os.Os;
+import brooklyn.util.stream.StreamGobbler;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
+import com.google.common.io.ByteSource;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.Files;
+
+/** Implementation of {@link ShellTool} which runs locally. */
+public class ProcessTool extends ShellAbstractTool implements ShellTool {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ProcessTool.class);
+
+    // applies to calls
+    
+    public static final ConfigKey<Boolean> PROP_LOGIN_SHELL = newConfigKey("loginShell", "Causes the commands to be invoked with bash arguments to forcea  login shell", Boolean.FALSE);
+
+    public static final ConfigKey<String> PROP_DIRECTORY = newStringConfigKey("directory", "the working directory, for executing commands", null);
+    
+    public ProcessTool() {
+        this(null);
+    }
+    
+    public ProcessTool(Map<String,?> flags) {
+        super(getOptionalVal(flags, PROP_LOCAL_TEMP_DIR));
+        if (flags!=null) {
+            MutableMap<String, Object> flags2 = MutableMap.copyOf(flags);
+            // TODO should remember other flags here?  (e.g. NO_EXTRA_OUTPUT, RUN_AS_ROOT, etc)
+            flags2.remove(PROP_LOCAL_TEMP_DIR.getName());
+            if (!flags2.isEmpty())
+                LOG.warn(""+this+" ignoring unsupported constructor flags: "+flags);
+        }
+    }
+
+    @Override
+    public int execScript(final Map<String,?> props, final List<String> commands, final Map<String,?> env) {
+        return new ToolAbstractExecScript(props) {
+            public int run() {
+                try {
+                    String directory = getOptionalVal(props, PROP_DIRECTORY);
+                    File directoryDir = (directory != null) ? new File(Os.tidyPath(directory)) : null;
+                    
+                    String scriptContents = toScript(props, commands, env);
+
+                    if (LOG.isTraceEnabled()) LOG.trace("Running shell process (process) as script:\n{}", scriptContents);
+                    File to = new File(scriptPath);
+                    Files.createParentDirs(to);
+                    ByteSource.wrap(scriptContents.getBytes()).copyTo(Files.asByteSink(to));
+
+                    List<String> cmds = buildRunScriptCommand();
+                    cmds.add(0, "chmod +x "+scriptPath);
+                    return asInt(execProcesses(cmds, null, directoryDir, out, err, separator, getOptionalVal(props, PROP_LOGIN_SHELL), this), -1);
+                } catch (IOException e) {
+                    throw Throwables.propagate(e);
+                }
+            }
+        }.run();
+    }
+
+    @Override
+    public int execCommands(Map<String,?> props, List<String> commands, Map<String,?> env) {
+        if (Boolean.FALSE.equals(props.get("blocks"))) {
+            throw new IllegalArgumentException("Cannot exec non-blocking: command="+commands);
+        }
+        OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
+        OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
+        String separator = getOptionalVal(props, PROP_SEPARATOR);
+        String directory = getOptionalVal(props, PROP_DIRECTORY);
+        File directoryDir = (directory != null) ? new File(Os.tidyPath(directory)) : null;
+
+        List<String> allcmds = toCommandSequence(commands, null);
+
+        String singlecmd = Joiner.on(separator).join(allcmds);
+        if (Boolean.TRUE.equals(getOptionalVal(props, PROP_RUN_AS_ROOT))) {
+            LOG.warn("Cannot run as root when executing as command; run as a script instead (will run as normal user): "+singlecmd);
+        }
+        if (LOG.isTraceEnabled()) LOG.trace("Running shell command (process): {}", singlecmd);
+        
+        return asInt(execProcesses(allcmds, env, directoryDir, out, err, separator, getOptionalVal(props, PROP_LOGIN_SHELL), this), -1);
+    }
+
+    /**
+     * as {@link #execProcesses(List, Map, OutputStream, OutputStream, String, boolean, Object)} but not using a login shell
+     * @deprecated since 0.7; use {@link #execProcesses(List, Map, File, OutputStream, OutputStream, String, boolean, Object)}
+     */
+    @Deprecated
+    public static int execProcesses(List<String> cmds, Map<String,?> env, OutputStream out, OutputStream err, String separator, Object contextForLogging) {
+        return execProcesses(cmds, env, (File)null, out, err, separator, false, contextForLogging);
+    }
+
+    /**
+     * @deprecated since 0.7; use {@link #execProcesses(List, Map, File, OutputStream, OutputStream, String, boolean, Object)}
+     */
+    @Deprecated
+    public static int execProcesses(List<String> cmds, Map<String,?> env, OutputStream out, OutputStream err, String separator, boolean asLoginShell, Object contextForLogging) {
+        return execProcesses(cmds, env, (File)null, out, err, separator, asLoginShell, contextForLogging);
+    }
+    
+    /** executes a set of commands by sending them as a single process to `bash -c` 
+     * (single command argument of all the commands, joined with separator)
+     * <p>
+     * consequence of this is that you should not normally need to escape things oddly in your commands, 
+     * type them just as you would into a bash shell (if you find exceptions please note them here!)
+     */
+    public static int execProcesses(List<String> cmds, Map<String,?> env, File directory, OutputStream out, OutputStream err, String separator, boolean asLoginShell, Object contextForLogging) {
+        MutableList<String> commands = new MutableList<String>().append("bash");
+        if (asLoginShell) commands.append("-l");
+        commands.append("-c", Strings.join(cmds, Preconditions.checkNotNull(separator, "separator")));
+        return execSingleProcess(commands, env, directory, out, err, contextForLogging);
+    }
+    
+    /**
+     * @deprecated since 0.7; use {@link #execSingleProcess(List, Map, File, OutputStream, OutputStream, Object)}
+     */
+    @Deprecated
+    public static int execSingleProcess(List<String> cmdWords, Map<String,?> env, OutputStream out, OutputStream err, Object contextForLogging) {
+        return execSingleProcess(cmdWords, env, (File)null, out, err, contextForLogging);
+    }
+    
+    /** executes a single process made up of the given command words (*not* bash escaped);
+     * should be portable across OS's */
+    public static int execSingleProcess(List<String> cmdWords, Map<String,?> env, File directory, OutputStream out, OutputStream err, Object contextForLogging) {
+        StreamGobbler errgobbler = null;
+        StreamGobbler outgobbler = null;
+        
+        ProcessBuilder pb = new ProcessBuilder(cmdWords);
+        if (env!=null) {
+            for (Map.Entry<String,?> kv: env.entrySet()) pb.environment().put(kv.getKey(), String.valueOf(kv.getValue())); 
+        }
+        if (directory != null) {
+            pb.directory(directory);
+        }
+        
+        try {
+            Process p = pb.start();
+            
+            if (out != null) {
+                InputStream outstream = p.getInputStream();
+                outgobbler = new StreamGobbler(outstream, out, (Logger) null);
+                outgobbler.start();
+            }
+            if (err != null) {
+                InputStream errstream = p.getErrorStream();
+                errgobbler = new StreamGobbler(errstream, err, (Logger) null);
+                errgobbler.start();
+            }
+            
+            int result = p.waitFor();
+            
+            if (outgobbler != null) outgobbler.blockUntilFinished();
+            if (errgobbler != null) errgobbler.blockUntilFinished();
+            
+            if (result==255)
+                // this is not definitive, but tests (and code?) expects throw exception if can't connect;
+                // only return exit code when it is exit code from underlying process;
+                // we have no way to distinguish 255 from ssh failure from 255 from the command run through ssh ...
+                // but probably 255 is from CLI ssh
+                throw new SshException("exit code 255 from CLI ssh; probably failed to connect");
+            
+            return result;
+        } catch (InterruptedException e) {
+            throw Exceptions.propagate(e);
+        } catch (IOException e) {
+            throw Exceptions.propagate(e);
+        } finally {
+            closeWhispering(outgobbler, contextForLogging, "execProcess");
+            closeWhispering(errgobbler, contextForLogging, "execProcess");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjClientConnection.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjClientConnection.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjClientConnection.java
new file mode 100644
index 0000000..c042415
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjClientConnection.java
@@ -0,0 +1,282 @@
+/*
+ * 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.util.internal.ssh.sshj;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.File;
+import java.io.IOException;
+
+import net.schmizz.sshj.SSHClient;
+import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
+import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
+import net.schmizz.sshj.userauth.password.PasswordUtils;
+
+import org.apache.brooklyn.core.util.internal.ssh.SshAbstractTool.SshAction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.GroovyJavaMethods;
+
+import com.google.common.base.Objects;
+import com.google.common.net.HostAndPort;
+
+/** based on code from jclouds */
+public class SshjClientConnection implements SshAction<SSHClient> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SshjClientConnection.class);
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+
+        protected HostAndPort hostAndPort;
+        protected String username;
+        protected String password;
+        protected String privateKeyPassphrase;
+        protected String privateKeyData;
+        protected File privateKeyFile;
+        protected long connectTimeout;
+        protected long sessionTimeout;
+        protected boolean strictHostKeyChecking;
+
+        public Builder hostAndPort(HostAndPort hostAndPort) {
+            this.hostAndPort = hostAndPort;
+            return this;
+        }
+
+        public Builder username(String username) {
+            this.username = username;
+            return this;
+        }
+
+        public Builder password(String val) {
+            this.password = val;
+            return this;
+        }
+
+        /** @deprecated use privateKeyData */
+        public Builder privateKey(String val) {
+            this.privateKeyData = val;
+            return this;
+        }
+
+        public Builder privateKeyPassphrase(String val) {
+            this.privateKeyPassphrase = val;
+            return this;
+        }
+        
+        public Builder privateKeyData(String val) {
+            this.privateKeyData = val;
+            return this;
+        }
+        
+        public Builder privateKeyFile(File val) {
+            this.privateKeyFile = val;
+            return this;
+        }
+        
+        public Builder strictHostKeyChecking(boolean val) {
+            this.strictHostKeyChecking = val;
+            return this;
+        }
+
+        public Builder connectTimeout(long connectTimeout) {
+            this.connectTimeout = connectTimeout;
+            return this;
+        }
+
+        public Builder sessionTimeout(long sessionTimeout) {
+            this.sessionTimeout = sessionTimeout;
+            return this;
+        }
+
+        public SshjClientConnection build() {
+            return new SshjClientConnection(this);
+        }
+
+        protected static Builder fromSSHClientConnection(SshjClientConnection in) {
+            return new Builder().hostAndPort(in.getHostAndPort()).connectTimeout(in.getConnectTimeout()).sessionTimeout(
+                    in.getSessionTimeout()).username(in.username).password(in.password).privateKey(in.privateKeyData).privateKeyFile(in.privateKeyFile);
+        }
+    }
+
+    private final HostAndPort hostAndPort;
+    private final String username;
+    private final String password;
+    private final String privateKeyPassphrase;
+    private final String privateKeyData;
+    private final File privateKeyFile;
+    private final boolean strictHostKeyChecking;
+    private final int connectTimeout;
+    private final int sessionTimeout;
+    
+    SSHClient ssh;
+
+    private SshjClientConnection(Builder builder) {
+        this.hostAndPort = checkNotNull(builder.hostAndPort);
+        this.username = builder.username;
+        this.password = builder.password;
+        this.privateKeyPassphrase = builder.privateKeyPassphrase;
+        this.privateKeyData = builder.privateKeyData;
+        this.privateKeyFile = builder.privateKeyFile;
+        this.strictHostKeyChecking = builder.strictHostKeyChecking;
+        this.connectTimeout = checkInt("connectTimeout", builder.connectTimeout, Integer.MAX_VALUE);
+        this.sessionTimeout = checkInt("sessionTimeout", builder.sessionTimeout, Integer.MAX_VALUE);
+    }
+
+    static Integer checkInt(String context, long value, Integer ifTooLarge) {
+        if (value > Integer.MAX_VALUE) {
+            LOG.warn("Value '"+value+"' for "+context+" too large in SshjClientConnection; using "+value);
+            return ifTooLarge;
+        }
+        return (int)value;
+    }
+
+    public boolean isConnected() {
+        return ssh != null && ssh.isConnected();
+    }
+
+    public boolean isAuthenticated() {
+        return ssh != null && ssh.isAuthenticated();
+    }
+
+    @Override
+    public void clear() {
+        if (ssh != null && ssh.isConnected()) {
+            try {
+                if (LOG.isTraceEnabled()) LOG.trace("Disconnecting SshjClientConnection {} ({})", this, System.identityHashCode(this));
+                ssh.disconnect();
+            } catch (IOException e) {
+                if (LOG.isDebugEnabled()) LOG.debug("<< exception disconnecting from {}: {}", e, e.getMessage());
+            }
+        }
+        ssh = null;
+    }
+
+    @Override
+    public SSHClient create() throws Exception {
+        if (LOG.isTraceEnabled()) LOG.trace("Connecting SshjClientConnection {} ({})", this, System.identityHashCode(this));
+        ssh = new net.schmizz.sshj.SSHClient();
+        if (!strictHostKeyChecking) {
+            ssh.addHostKeyVerifier(new PromiscuousVerifier());
+        }
+        if (connectTimeout != 0) {
+            ssh.setConnectTimeout(connectTimeout);
+        }
+        if (sessionTimeout != 0) {
+            ssh.setTimeout(sessionTimeout);
+        }
+        ssh.connect(hostAndPort.getHostText(), hostAndPort.getPortOrDefault(22));
+        
+        if (password != null) {
+            ssh.authPassword(username, password);
+        } else if (privateKeyData != null) {
+            OpenSSHKeyFile key = new OpenSSHKeyFile();
+            key.init(privateKeyData, null, 
+                    GroovyJavaMethods.truth(privateKeyPassphrase) ? 
+                            PasswordUtils.createOneOff(privateKeyPassphrase.toCharArray())
+                            : null);
+            ssh.authPublickey(username, key);
+        } else if (privateKeyFile != null) {
+            OpenSSHKeyFile key = new OpenSSHKeyFile();
+            key.init(privateKeyFile, 
+                    GroovyJavaMethods.truth(privateKeyPassphrase) ? 
+                            PasswordUtils.createOneOff(privateKeyPassphrase.toCharArray())
+                            : null);
+            ssh.authPublickey(username, key);
+        } else {
+            // Accept defaults (in ~/.ssh)
+            ssh.authPublickey(username);
+        }
+        
+        return ssh;
+    }
+
+    /**
+     * @return host and port, where port if not present defaults to {@code 22}
+     */
+    public HostAndPort getHostAndPort() {
+        return hostAndPort;
+    }
+
+    /**
+     * @return username used in this ssh
+     */
+    public String getUsername() {
+        return username;
+    }
+
+    /**
+     * 
+     * @return how long to wait for the initial connection to be made
+     */
+    public int getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    /**
+     * 
+     * @return how long to keep the ssh open, or {@code 0} for indefinitely
+     */
+    public int getSessionTimeout() {
+        return sessionTimeout;
+    }
+
+    /**
+     * 
+     * @return the current ssh or {@code null} if not connected
+     */
+    public SSHClient getSSHClient() {
+        return ssh;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        SshjClientConnection that = SshjClientConnection.class.cast(o);
+        return equal(this.hostAndPort, that.hostAndPort) && equal(this.username, that.username) 
+                && equal(this.password, that.password) && equal(this.privateKeyData, that.privateKeyData)
+                && equal(this.privateKeyFile, that.privateKeyFile) && equal(this.ssh, that.ssh);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(hostAndPort, username, password, privateKeyData, ssh);
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper("")
+                .add("hostAndPort", hostAndPort)
+                .add("user", username)
+                .add("ssh", ssh != null ? ssh.hashCode() : null)
+                .add("password", (password != null ? "xxxxxx" : null))
+                .add("privateKeyFile", privateKeyFile)
+                .add("privateKey", (privateKeyData != null ? "xxxxxx" : null))
+                .add("connectTimeout", connectTimeout)
+                .add("sessionTimeout", sessionTimeout).toString();
+    }
+}



[06/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/xstream/CompilerCompatibilityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/xstream/CompilerCompatibilityTest.java b/core/src/test/java/org/apache/brooklyn/core/util/xstream/CompilerCompatibilityTest.java
new file mode 100644
index 0000000..d18da28
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/xstream/CompilerCompatibilityTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.util.xstream;
+
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+
+import org.apache.brooklyn.core.util.xstream.CompilerIndependentOuterClassFieldMapper;
+import org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest.EnclosingClass.DynamicClass;
+import org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest.EnclosingClass.DynamicExtendingClass;
+import org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest.EnclosingClass.EnclosingDynamicClass;
+import org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest.EnclosingClass.EnclosingDynamicClass.NestedDynamicClass;
+import org.eclipse.jetty.util.log.Log;
+import org.testng.annotations.Test;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.mapper.MapperWrapper;
+
+// To get the generated synthetic fields use the command:
+/*
+   find core/target/test-classes -name CompilerCompatibilityTest\$EnclosingClass\$* | \
+   sed s@core/target/test-classes/@@ | sed 's@.class$@@' | sed s@/@.@g | \
+   xargs javap -classpath core/target/test-classes/ | grep -B1 this
+*/
+@SuppressWarnings("unused")
+public class CompilerCompatibilityTest {
+    private EnclosingClass enclosingClass = new EnclosingClass();
+    private DynamicClass dynamicClass = enclosingClass.new DynamicClass();
+    private DynamicExtendingClass dynamicExtendingClass = enclosingClass.new DynamicExtendingClass();
+    private EnclosingDynamicClass enclosingDynamicClass = enclosingClass.new EnclosingDynamicClass();
+    private NestedDynamicClass nestedDynamicClass = enclosingDynamicClass.new NestedDynamicClass();
+//  NOT SUPPORTED
+//  private DynamicExtendingClassWithDifferentScope dynamicExtendingClassWithDifferentScope =
+//      enclosingClass.new DynamicExtendingClassWithDifferentScope(enclosingDynamicClass);
+
+    public static class EnclosingClass {
+        public class DynamicClass {
+            //Oracle/OpenJDK/IBM generates
+            //final EnclosingClass this$0;
+
+            //eclipse-[groovy-]compiler generates
+            //final EnclosingClass this$1;
+        }
+
+        public class DynamicExtendingClass extends DynamicClass {
+            //The field here masks the parent field
+
+            //Oracle/OpenJDK/IBM generates
+            //final EnclosingClass this$0;
+
+            //eclipse-[groovy-]compiler generates
+            //final EnclosingClass this$1;
+        }
+
+        public class EnclosingDynamicClass {
+            //Oracle/OpenJDK/IBM generates
+            //final EnclosingClass this$0;
+
+            //eclipse-[groovy-]compiler generates
+            //final EnclosingClass this$1;
+
+            public class NestedDynamicClass {
+                //Oracle/OpenJDK/IBM generates
+                //final EnclosingClass this$1;
+
+                //eclipse-[groovy-]compiler generates
+                //final EnclosingClass this$2;
+            }
+        }
+
+//        WARNING: Combination NOT SUPPORTED. Not enough information in XML to deserialize reliably,
+//        having in mind that different compilers could be used for parent/child classes.
+//        If we really need to, we can extend the heuristic to check for field types or assume that
+//        only one compiler was used for the whole class hierarchy covering some more cases.
+//
+//        The problem is that we have two fields with different names, without relation between the
+//        indexes in each one. Changing compilers (or combination of compilers) could change the 
+//        indexes independently in each field. This makes it impossible to infer which field in the xml
+//        maps to which field in the object.
+//        When having identical field names with parent classes XStream will put a defined-in attribute
+//        which makes it possible to deserialize, but it can't be forced to put it in each element.
+//
+        public class DynamicExtendingClassWithDifferentScope extends NestedDynamicClass {
+            //Oracle/OpenJDK/IBM generates
+            //final EnclosingClass this$0;
+
+            //eclipse-[groovy-]compiler generates
+            //final EnclosingClass this$1;
+
+            //constructor required to compile
+            public DynamicExtendingClassWithDifferentScope(EnclosingDynamicClass superEnclosingScope) {
+                superEnclosingScope.super();
+            }
+        }
+    }
+
+    @Test
+    public void testXStreamDeserialize() throws Exception {
+        deserialize("/brooklyn/entity/rebind/compiler_compatibility_eclipse.xml");
+        deserialize("/brooklyn/entity/rebind/compiler_compatibility_oracle.xml");
+    }
+
+    private void deserialize(String inputUrl) throws Exception {
+        XStream xstream = new XStream() {
+            @Override
+            protected MapperWrapper wrapMapper(MapperWrapper next) {
+                return new CompilerIndependentOuterClassFieldMapper(super.wrapMapper(next));
+            }
+        };
+
+        InputStream in = this.getClass().getResourceAsStream(inputUrl);
+        try {
+            Object obj = xstream.fromXML(in);
+            assertNonNullOuterFields(obj);
+        } catch (Exception e) {
+        	System.out.println(e.getMessage());
+        	throw e;
+        } finally {
+            in.close();
+        }
+    }
+
+    private void assertNonNullOuterFields(Object obj) throws Exception {
+        Field[] testInstances = obj.getClass().getDeclaredFields();
+        for (Field instanceField : testInstances) {
+            Object instance = instanceField.get(obj);
+            Class<?> type = instance.getClass();
+            do {
+                for (Field field : type.getDeclaredFields()) {
+                    if (field.getName().startsWith("this$")) {
+                        Object value = field.get(instance);
+                        assertTrue(value != null, field + " should not be null");
+                    }
+                }
+                type = type.getSuperclass();
+            } while (type != null);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/xstream/ConverterTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/xstream/ConverterTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/util/xstream/ConverterTestFixture.java
new file mode 100644
index 0000000..16c7d71
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/xstream/ConverterTestFixture.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.core.util.xstream;
+
+import org.testng.Assert;
+
+import com.thoughtworks.xstream.XStream;
+
+public class ConverterTestFixture {
+
+    protected Object assertX(Object obj, String fmt) {
+        XStream xstream = new XStream();
+        registerConverters(xstream);
+        String s1 = xstream.toXML(obj);
+        Assert.assertEquals(s1, fmt);
+        Object out = xstream.fromXML(s1);
+        Assert.assertEquals(out, obj);
+        return out;
+    }
+
+    protected void registerConverters(XStream xstream) {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingConverterTest.java b/core/src/test/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingConverterTest.java
new file mode 100644
index 0000000..65374e4
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingConverterTest.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.core.util.xstream;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+import org.apache.brooklyn.core.util.xstream.EnumCaseForgivingConverter;
+import org.testng.annotations.Test;
+
+public class EnumCaseForgivingConverterTest {
+
+    public enum MyEnum {
+        FOO,
+        BaR;
+    }
+    
+    @Test
+    public void testFindsCaseInsensitive() throws Exception {
+        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "FOO"), MyEnum.FOO);
+        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "foo"), MyEnum.FOO);
+        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "Foo"), MyEnum.FOO);
+        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "BAR"), MyEnum.BaR);
+        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "bar"), MyEnum.BaR);
+        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "Bar"), MyEnum.BaR);
+    }
+    
+    @Test
+    public void testFailsIfNoMatch() throws Exception {
+        try {
+            assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "DoesNotExist"), MyEnum.BaR);
+            fail();
+        } catch (IllegalArgumentException e) {
+            if (!e.toString().matches(".*No enum.*MyEnum.DOESNOTEXIST")) throw e;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/xstream/ImmutableListConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/xstream/ImmutableListConverterTest.java b/core/src/test/java/org/apache/brooklyn/core/util/xstream/ImmutableListConverterTest.java
new file mode 100644
index 0000000..1a708ce
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/xstream/ImmutableListConverterTest.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.util.xstream;
+
+import java.net.UnknownHostException;
+
+import org.apache.brooklyn.core.util.xstream.ImmutableListConverter;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.thoughtworks.xstream.XStream;
+
+@Test
+public class ImmutableListConverterTest extends ConverterTestFixture {
+
+    protected void registerConverters(XStream xstream) {
+        super.registerConverters(xstream);
+        xstream.aliasType("ImmutableList", ImmutableList.class);
+        xstream.registerConverter(new ImmutableListConverter(xstream.getMapper()));
+    }
+
+    @Test
+    public void testImmutableEmptyList() throws UnknownHostException {
+        assertX(ImmutableList.of(), "<ImmutableList/>");
+    }
+
+    @Test
+    public void testImmutableSingletonDoubleList() throws UnknownHostException {
+        assertX(ImmutableList.of(1.2d), "<ImmutableList>\n  <double>1.2</double>\n</ImmutableList>");
+    }
+
+    @Test
+    public void testImmutableTwoValStringList() throws UnknownHostException {
+        assertX(ImmutableList.of("a","b"), "<ImmutableList>\n  <string>a</string>\n  <string>b</string>\n</ImmutableList>");
+    }
+
+    @Test
+    public void testImmutableEmptyListStaysImmutable() throws UnknownHostException {
+        Object x = assertX(ImmutableList.of(), "<ImmutableList/>");
+        Assert.assertTrue(x instanceof ImmutableList);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/xstream/InetAddressConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/xstream/InetAddressConverterTest.java b/core/src/test/java/org/apache/brooklyn/core/util/xstream/InetAddressConverterTest.java
new file mode 100644
index 0000000..bec2cc4
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/xstream/InetAddressConverterTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.util.xstream;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.apache.brooklyn.core.util.xstream.Inet4AddressConverter;
+import org.testng.annotations.Test;
+
+import com.thoughtworks.xstream.XStream;
+
+@Test
+public class InetAddressConverterTest extends ConverterTestFixture {
+
+    protected void registerConverters(XStream xstream) {
+        super.registerConverters(xstream);
+        xstream.registerConverter(new Inet4AddressConverter());
+    }
+
+    public void testFoo1234() throws UnknownHostException {
+        assertX(InetAddress.getByAddress("foo", new byte[] { 1, 2, 3, 4 }), 
+                "<java.net.Inet4Address>foo/1.2.3.4</java.net.Inet4Address>");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/xstream/StringKeyMapConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/xstream/StringKeyMapConverterTest.java b/core/src/test/java/org/apache/brooklyn/core/util/xstream/StringKeyMapConverterTest.java
new file mode 100644
index 0000000..6a15ee9
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/xstream/StringKeyMapConverterTest.java
@@ -0,0 +1,78 @@
+/*
+ * 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.util.xstream;
+
+import java.net.UnknownHostException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.xstream.StringKeyMapConverter;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.collect.Maps;
+import com.thoughtworks.xstream.XStream;
+
+@SuppressWarnings({ "rawtypes", "unchecked" })
+@Test
+public class StringKeyMapConverterTest extends ConverterTestFixture {
+
+    protected void registerConverters(XStream xstream) {
+        super.registerConverters(xstream);
+        xstream.alias("map", Map.class, LinkedHashMap.class);
+        xstream.alias("MutableMap", MutableMap.class);
+        xstream.registerConverter(new StringKeyMapConverter(xstream.getMapper()), /* priority */ 10);
+    }
+
+    @Test
+    public void testSimple() throws UnknownHostException {
+        Map m = Maps.newLinkedHashMap();
+        m.put("a", "v");
+        assertX(m, "<map>\n  <a>v</a>\n</map>");
+    }
+    
+    @Test
+    public void testDouble() throws UnknownHostException {
+        Map m = Maps.newLinkedHashMap();
+        m.put("a", "v");
+        m.put("x", 1.0d);
+        assertX(m, "<map>\n  <a>v</a>\n  <x type=\"double\">1.0</x>\n</map>");
+    }
+    
+    @Test
+    public void testEmpty() throws UnknownHostException {
+        Map m = Maps.newLinkedHashMap();
+        assertX(m, "<map/>");
+    }
+    
+    @Test
+    public void testBigSpacedKeyInMutableMap() throws UnknownHostException {
+        Map m = MutableMap.of("a b", "x");
+        assertX(m, "<MutableMap>\n  <entry key=\"a b\">x</entry>\n</MutableMap>");
+    }
+
+    @Test
+    public void testWithNumericKey() throws UnknownHostException {
+        Map m = Maps.newLinkedHashMap();
+        m.put("123", "v");
+        m.put("a", "v2");
+        assertX(m, "<map>\n  <entry key=\"123\">v</entry>\n  <a>v2</a>\n</map>");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/xstream/XmlUtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/xstream/XmlUtilTest.java b/core/src/test/java/org/apache/brooklyn/core/util/xstream/XmlUtilTest.java
new file mode 100644
index 0000000..dd97d17
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/xstream/XmlUtilTest.java
@@ -0,0 +1,34 @@
+/*
+ * 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.util.xstream;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.core.util.xstream.XmlUtil;
+import org.testng.annotations.Test;
+
+
+public class XmlUtilTest {
+
+    @Test
+    public void testXpath() throws Exception {
+        String xml = "<a><b>myb</b></a>";
+        assertEquals(XmlUtil.xpath(xml, "/a/b[text()]"), "myb");
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/basic/AbstractLocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/basic/AbstractLocationTest.java b/core/src/test/java/org/apache/brooklyn/location/basic/AbstractLocationTest.java
index 089b719..d24ac65 100644
--- a/core/src/test/java/org/apache/brooklyn/location/basic/AbstractLocationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/basic/AbstractLocationTest.java
@@ -29,6 +29,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
@@ -37,7 +38,6 @@ import org.testng.annotations.Test;
 import brooklyn.entity.basic.Entities;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/basic/LegacyAbstractLocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/basic/LegacyAbstractLocationTest.java b/core/src/test/java/org/apache/brooklyn/location/basic/LegacyAbstractLocationTest.java
index 10e59b3..c53762e 100644
--- a/core/src/test/java/org/apache/brooklyn/location/basic/LegacyAbstractLocationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/basic/LegacyAbstractLocationTest.java
@@ -26,11 +26,11 @@ import static org.testng.Assert.assertTrue;
 import java.util.Collections;
 import java.util.Map;
 
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableList;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/basic/LocationConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/basic/LocationConfigTest.java b/core/src/test/java/org/apache/brooklyn/location/basic/LocationConfigTest.java
index 1f265fd..cbf1aaa 100644
--- a/core/src/test/java/org/apache/brooklyn/location/basic/LocationConfigTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/basic/LocationConfigTest.java
@@ -22,6 +22,7 @@ import static org.testng.Assert.assertEquals;
 
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
@@ -31,7 +32,6 @@ import org.testng.annotations.Test;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/basic/LocationConfigUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/basic/LocationConfigUtilsTest.java b/core/src/test/java/org/apache/brooklyn/location/basic/LocationConfigUtilsTest.java
index e9197a1..1360f6b 100644
--- a/core/src/test/java/org/apache/brooklyn/location/basic/LocationConfigUtilsTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/basic/LocationConfigUtilsTest.java
@@ -23,11 +23,10 @@ import static org.testng.Assert.assertTrue;
 
 import java.io.File;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import brooklyn.util.config.ConfigBag;
-
 @Test
 public class LocationConfigUtilsTest {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/basic/PortRangesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/basic/PortRangesTest.java b/core/src/test/java/org/apache/brooklyn/location/basic/PortRangesTest.java
index 2b7ab69..de23b55 100644
--- a/core/src/test/java/org/apache/brooklyn/location/basic/PortRangesTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/basic/PortRangesTest.java
@@ -25,8 +25,7 @@ import java.util.Iterator;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 import org.apache.brooklyn.api.location.PortRange;
-
-import brooklyn.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationIntegrationTest.java
index 68a53c5..19b58fd 100644
--- a/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationIntegrationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationIntegrationTest.java
@@ -23,12 +23,14 @@ import java.security.KeyPair;
 import java.util.Arrays;
 import java.util.Map;
 
-import brooklyn.util.internal.ssh.SshTool;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.sshj.SshjTool;
+import org.apache.brooklyn.core.util.internal.ssh.sshj.SshjTool.SshjToolBuilder;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.testng.Assert;
@@ -38,9 +40,6 @@ import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.Entities;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.crypto.SecureKeys;
-import brooklyn.util.internal.ssh.sshj.SshjTool;
-import brooklyn.util.internal.ssh.sshj.SshjTool.SshjToolBuilder;
 
 import com.google.common.base.Preconditions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationPerformanceTest.java b/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationPerformanceTest.java
index 93e33a1..f7f8bf9 100644
--- a/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationPerformanceTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationPerformanceTest.java
@@ -25,6 +25,7 @@ import java.util.Map;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 import org.apache.brooklyn.test.PerformanceTestUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,7 +34,6 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.net.Networking;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.text.Identifiers;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationReuseIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationReuseIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationReuseIntegrationTest.java
index 6ba27e7..fd5884c 100644
--- a/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationReuseIntegrationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationReuseIntegrationTest.java
@@ -35,11 +35,11 @@ import brooklyn.entity.basic.Entities;
 
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.sshj.SshjTool;
 
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.internal.ssh.sshj.SshjTool;
 import brooklyn.util.net.Networking;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationTest.java b/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationTest.java
index b4ee5ef..ca51182 100644
--- a/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/basic/SshMachineLocationTest.java
@@ -43,6 +43,13 @@ 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.management.ManagementContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.file.ArchiveUtils;
+import org.apache.brooklyn.core.util.internal.ssh.RecordingSshTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshException;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.testng.annotations.AfterMethod;
@@ -58,18 +65,11 @@ import brooklyn.entity.effector.EffectorTaskTest;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.file.ArchiveUtils;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.internal.ssh.RecordingSshTool;
-import brooklyn.util.internal.ssh.SshException;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.net.Networking;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.BasicExecutionContext;
-import brooklyn.util.task.BasicExecutionManager;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Charsets;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/cloud/CloudMachineNamerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/cloud/CloudMachineNamerTest.java b/core/src/test/java/org/apache/brooklyn/location/cloud/CloudMachineNamerTest.java
index 9d4acad..fe26a43 100644
--- a/core/src/test/java/org/apache/brooklyn/location/cloud/CloudMachineNamerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/cloud/CloudMachineNamerTest.java
@@ -22,6 +22,7 @@ import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.cloud.names.AbstractCloudMachineNamer;
 import org.apache.brooklyn.location.cloud.names.CloudMachineNamer;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
@@ -35,8 +36,9 @@ import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.Entities;
+
 import org.apache.brooklyn.location.cloud.names.BasicCloudMachineNamer;
-import brooklyn.util.config.ConfigBag;
+
 import brooklyn.util.text.Strings;
 public class CloudMachineNamerTest {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/location/cloud/CustomMachineNamerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/location/cloud/CustomMachineNamerTest.java b/core/src/test/java/org/apache/brooklyn/location/cloud/CustomMachineNamerTest.java
index f0e7d11..0afad81 100644
--- a/core/src/test/java/org/apache/brooklyn/location/cloud/CustomMachineNamerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/location/cloud/CustomMachineNamerTest.java
@@ -19,6 +19,7 @@
 package org.apache.brooklyn.location.cloud;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -29,8 +30,8 @@ import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.Entities;
+
 import org.apache.brooklyn.location.cloud.names.CustomMachineNamer;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/test/entity/BlockingEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/test/entity/BlockingEntity.java b/core/src/test/java/org/apache/brooklyn/test/entity/BlockingEntity.java
index 3586701..7df9a89 100644
--- a/core/src/test/java/org/apache/brooklyn/test/entity/BlockingEntity.java
+++ b/core/src/test/java/org/apache/brooklyn/test/entity/BlockingEntity.java
@@ -21,10 +21,10 @@ package org.apache.brooklyn.test.entity;
 import java.util.concurrent.CountDownLatch;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * Mock entity that blocks on startup via the {@link CountDownLatch} argument.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/test/entity/TestEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/test/entity/TestEntity.java b/core/src/test/java/org/apache/brooklyn/test/entity/TestEntity.java
index 01b835e..8f0eff4 100644
--- a/core/src/test/java/org/apache/brooklyn/test/entity/TestEntity.java
+++ b/core/src/test/java/org/apache/brooklyn/test/entity/TestEntity.java
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.testng.collections.Lists;
 import org.testng.internal.annotations.Sets;
 
@@ -49,7 +50,6 @@ import brooklyn.event.basic.MapConfigKey;
 import brooklyn.event.basic.Sensors;
 import brooklyn.event.basic.SetConfigKey;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * Mock entity for testing.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/resources/brooklyn/entity/rebind/compiler_compatibility_eclipse.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/entity/rebind/compiler_compatibility_eclipse.xml b/core/src/test/resources/brooklyn/entity/rebind/compiler_compatibility_eclipse.xml
index dc972ef..7dd5ac6 100644
--- a/core/src/test/resources/brooklyn/entity/rebind/compiler_compatibility_eclipse.xml
+++ b/core/src/test/resources/brooklyn/entity/rebind/compiler_compatibility_eclipse.xml
@@ -17,25 +17,25 @@
     specific language governing permissions and limitations
     under the License.
 -->
-<brooklyn.util.xstream.CompilerCompatibilityTest>
-  <enclosingClass/>
+<org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest>
+  <enclosingClass />
   <dynamicClass>
-    <this_-1 reference="../../enclosingClass"/>
+    <this_-1 reference="../../enclosingClass" />
   </dynamicClass>
   <dynamicExtendingClass>
-    <this_-1 defined-in="brooklyn.util.xstream.CompilerCompatibilityTest$EnclosingClass$DynamicClass" reference="../../enclosingClass"/>
-    <this_-1 reference="../../enclosingClass"/>
+    <this_-1 defined-in="org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest$EnclosingClass$DynamicClass" reference="../../enclosingClass" />
+    <this_-1 reference="../../enclosingClass" />
   </dynamicExtendingClass>
   <enclosingDynamicClass>
-    <this_-1 reference="../../enclosingClass"/>
+    <this_-1 reference="../../enclosingClass" />
   </enclosingDynamicClass>
   <nestedDynamicClass>
-    <this_-2 reference="../../enclosingDynamicClass"/>
+    <this_-2 reference="../../enclosingDynamicClass" />
   </nestedDynamicClass>
 <!-- NOT SUPPORTED
   <dynamicExtendingClassWithDifferentScope>
-    <this_-2 reference="../../enclosingDynamicClass"/>
-    <this_-1 reference="../../enclosingClass"/>
+    <this_-2 reference="../../enclosingDynamicClass" />
+    <this_-1 reference="../../enclosingClass" />
   </dynamicExtendingClassWithDifferentScope>
 -->
-</brooklyn.util.xstream.CompilerCompatibilityTest>
+</org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/resources/brooklyn/entity/rebind/compiler_compatibility_oracle.xml
----------------------------------------------------------------------
diff --git a/core/src/test/resources/brooklyn/entity/rebind/compiler_compatibility_oracle.xml b/core/src/test/resources/brooklyn/entity/rebind/compiler_compatibility_oracle.xml
index a01692e..2b49251 100644
--- a/core/src/test/resources/brooklyn/entity/rebind/compiler_compatibility_oracle.xml
+++ b/core/src/test/resources/brooklyn/entity/rebind/compiler_compatibility_oracle.xml
@@ -17,25 +17,25 @@
     specific language governing permissions and limitations
     under the License.
 -->
-<brooklyn.util.xstream.CompilerCompatibilityTest>
-  <enclosingClass/>
+<org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest>
+  <enclosingClass />
   <dynamicClass>
-    <outer-class reference="../../enclosingClass"/>
+    <outer-class reference="../../enclosingClass" />
   </dynamicClass>
   <dynamicExtendingClass>
-    <outer-class defined-in="brooklyn.util.xstream.CompilerCompatibilityTest$EnclosingClass$DynamicClass" reference="../../enclosingClass"/>
+    <outer-class defined-in="org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest$EnclosingClass$DynamicClass" reference="../../enclosingClass" />
     <outer-class reference="../../enclosingClass"/>
   </dynamicExtendingClass>
   <enclosingDynamicClass>
-    <outer-class reference="../../enclosingClass"/>
+    <outer-class reference="../../enclosingClass" />
   </enclosingDynamicClass>
   <nestedDynamicClass>
-    <this_-1 reference="../../enclosingDynamicClass"/>
+    <this_-1 reference="../../enclosingDynamicClass" />
   </nestedDynamicClass>
 <!-- NOT SUPPORTED
   <dynamicExtendingClassWithDifferentScope>
-    <this_-1 reference="../../enclosingDynamicClass"/>
-    <outer-class reference="../../enclosingClass"/>
+    <this_-1 reference="../../enclosingDynamicClass" />
+    <outer-class reference="../../enclosingClass" />
   </dynamicExtendingClassWithDifferentScope>
 -->
-</brooklyn.util.xstream.CompilerCompatibilityTest>
+</org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 d53cf44..6fd3462 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
@@ -28,6 +28,8 @@ import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.catalog.CatalogConfig;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.util.BrooklynMavenArtifacts;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.entity.dns.geoscaling.GeoscalingDnsService;
 import org.apache.brooklyn.entity.proxy.AbstractController;
 import org.apache.brooklyn.entity.webapp.ElasticJavaWebAppService;
@@ -43,11 +45,9 @@ import brooklyn.entity.group.DynamicRegionsFabric;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 
 import org.apache.brooklyn.launcher.BrooklynLauncher;
-
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.BrooklynMavenArtifacts;
+
 import brooklyn.util.CommandLineUtil;
-import brooklyn.util.ResourceUtils;
 
 import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 507ed37..da88bff 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
@@ -34,6 +34,10 @@ import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.apache.brooklyn.entity.nosql.cassandra.CassandraDatacenter;
 import org.apache.brooklyn.entity.nosql.cassandra.CassandraFabric;
 import org.apache.brooklyn.entity.nosql.cassandra.CassandraNode;
@@ -63,15 +67,11 @@ import brooklyn.policy.ha.ServiceFailureDetector;
 import brooklyn.policy.ha.ServiceReplacer;
 import brooklyn.policy.ha.ServiceRestarter;
 import brooklyn.util.CommandLineUtil;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 5b72a58..441999f 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
@@ -30,6 +30,8 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.catalog.CatalogConfig;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.BrooklynMavenArtifacts;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.entity.webapp.ControlledDynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
@@ -49,12 +51,10 @@ import brooklyn.entity.java.JavaEntityMethods;
 import brooklyn.event.basic.Sensors;
 
 import org.apache.brooklyn.launcher.BrooklynLauncher;
-
 import org.apache.brooklyn.location.basic.PortRanges;
+
 import brooklyn.policy.autoscaling.AutoScalerPolicy;
-import brooklyn.util.BrooklynMavenArtifacts;
 import brooklyn.util.CommandLineUtil;
-import brooklyn.util.ResourceUtils;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java b/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
index bc8eab1..8327cf1 100644
--- a/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
+++ b/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
@@ -26,6 +26,8 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 import org.jclouds.compute.config.AdminAccessConfiguration;
 import org.jclouds.scriptbuilder.functions.InitAdminAccess;
 import org.jclouds.scriptbuilder.statements.login.AdminAccess;
@@ -42,8 +44,6 @@ import brooklyn.event.basic.Sensors;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.policy.basic.AbstractPolicy;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.text.Identifiers;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePool.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePool.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePool.java
index fa71a3a..f447482 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePool.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/BrooklynMachinePool.java
@@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,7 +41,6 @@ import org.apache.brooklyn.location.jclouds.pool.MachineSet;
 import org.apache.brooklyn.location.jclouds.pool.ReusableMachineTemplate;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.task.BasicExecutionContext;
 
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistry.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistry.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistry.java
index a835e2c..8d48cf5 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistry.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistry.java
@@ -18,10 +18,9 @@
  */
 package org.apache.brooklyn.location.jclouds;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.jclouds.compute.ComputeService;
 
-import brooklyn.util.config.ConfigBag;
-
 public interface ComputeServiceRegistry {
     
     public ComputeService findComputeService(ConfigBag conf, boolean allowReuse);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
index f3f39bb..670379d 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/ComputeServiceRegistryImpl.java
@@ -27,6 +27,7 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
 import org.jclouds.Constants;
 import org.jclouds.ContextBuilder;
@@ -41,7 +42,6 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.basic.Sanitizer;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Predicates;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolver.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolver.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolver.java
index e8f63b3..eb9ebfa 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolver.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsByonLocationResolver.java
@@ -31,6 +31,7 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.basic.BasicLocationRegistry;
@@ -41,7 +42,6 @@ import org.apache.brooklyn.location.basic.LocationInternal;
 import org.apache.brooklyn.location.basic.LocationPropertiesFromBrooklynProperties;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.text.KeyValueParser;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
index 2583234..1c1254c 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocation.java
@@ -57,6 +57,15 @@ import org.apache.brooklyn.api.location.MachineLocationCustomizer;
 import org.apache.brooklyn.api.location.MachineManagementMixins;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.api.management.AccessController;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+import org.apache.brooklyn.core.util.flags.MethodCoercions;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.apache.brooklyn.location.access.PortMapping;
 import org.apache.brooklyn.location.basic.AbstractLocation;
 import org.apache.brooklyn.location.cloud.AbstractCloudMachineProvisioningLocation;
@@ -146,21 +155,13 @@ import org.apache.brooklyn.location.cloud.names.CloudMachineNamer;
 import org.apache.brooklyn.location.jclouds.JcloudsPredicates.NodeInLocation;
 import org.apache.brooklyn.location.jclouds.templates.PortableTemplateBuilder;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.crypto.SecureKeys;
 import brooklyn.util.exceptions.CompoundRuntimeException;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.ReferenceWithError;
-import brooklyn.util.flags.MethodCoercions;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.internal.ssh.ShellTool;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.javalang.Enums;
 import brooklyn.util.javalang.Reflections;
 import brooklyn.util.net.Cidr;
@@ -177,7 +178,6 @@ import brooklyn.util.text.ByteSizeStrings;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.KeyValueParser;
 import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 import io.cloudsoft.winrm4j.pywinrm.Session;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationConfig.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationConfig.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationConfig.java
index 9fce742..1922b39 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationConfig.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationConfig.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Semaphore;
 
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 import org.apache.brooklyn.location.jclouds.networking.JcloudsPortForwarderExtension;
 import org.jclouds.Constants;
 import org.jclouds.compute.domain.Image;
@@ -33,11 +34,11 @@ import org.jclouds.domain.LoginCredentials;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicConfigKey;
+
 import org.apache.brooklyn.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.location.access.PortForwardManager;
 import org.apache.brooklyn.location.basic.LocationConfigKeys;
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
-import brooklyn.util.internal.ssh.SshTool;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationCustomizer.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationCustomizer.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationCustomizer.java
index b6cb363..d7cf619 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationCustomizer.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsLocationCustomizer.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.location.jclouds;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.domain.Template;
 import org.jclouds.compute.domain.TemplateBuilder;
@@ -25,8 +26,6 @@ import org.jclouds.compute.options.TemplateOptions;
 
 import com.google.common.annotations.Beta;
 
-import brooklyn.util.config.ConfigBag;
-
 /**
  * Customization hooks to allow apps to perform specific customisation at each stage of jclouds machine provisioning.
  * For example, an app could attach an EBS volume to an EC2 node, or configure a desired availability zone.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamer.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamer.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamer.java
index 4f4587e..e2cd2e1 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamer.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamer.java
@@ -18,8 +18,8 @@
  */
 package org.apache.brooklyn.location.jclouds;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.cloud.names.BasicCloudMachineNamer;
-import brooklyn.util.config.ConfigBag;
 
 public class JcloudsMachineNamer extends BasicCloudMachineNamer {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsPropertiesFromBrooklynProperties.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsPropertiesFromBrooklynProperties.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsPropertiesFromBrooklynProperties.java
index f307041..87e8ce4 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsPropertiesFromBrooklynProperties.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsPropertiesFromBrooklynProperties.java
@@ -20,14 +20,16 @@ package org.apache.brooklyn.location.jclouds;
 
 import java.util.Map;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.basic.DeprecatedKeysMappingBuilder;
 import org.apache.brooklyn.location.basic.LocationPropertiesFromBrooklynProperties;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigUtils;
+
 import org.apache.brooklyn.location.basic.LocationConfigKeys;
-import brooklyn.util.config.ConfigBag;
+
 import brooklyn.util.javalang.JavaClassNames;
 
 import com.google.common.base.Splitter;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
index a2a5735..3ce7892 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsSshMachineLocation.java
@@ -34,6 +34,7 @@ import javax.annotation.Nullable;
 import org.apache.brooklyn.api.location.HardwareDetails;
 import org.apache.brooklyn.api.location.MachineDetails;
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.location.basic.BasicHardwareDetails;
 import org.apache.brooklyn.location.basic.BasicMachineDetails;
 import org.apache.brooklyn.location.basic.BasicOsDetails;
@@ -55,7 +56,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.net.Networking;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsUtil.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsUtil.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsUtil.java
index e3026df..c981f26 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsUtil.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsUtil.java
@@ -36,6 +36,7 @@ import java.util.concurrent.TimeoutException;
 
 import javax.annotation.Nullable;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.jclouds.Constants;
 import org.jclouds.ContextBuilder;
 import org.jclouds.aws.ec2.AWSEC2Api;
@@ -80,7 +81,6 @@ import com.google.inject.Module;
 
 import brooklyn.entity.basic.Sanitizer;
 import brooklyn.util.collections.MutableList;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.net.Protocol;
 import brooklyn.util.ssh.BashCommands;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
index 753d772..1204856 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/JcloudsWinRmMachineLocation.java
@@ -25,13 +25,13 @@ import java.net.UnknownHostException;
 import java.util.Iterator;
 import java.util.Set;
 
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.location.basic.WinRmMachineLocation;
 import org.jclouds.compute.domain.NodeMetadata;
 import org.jclouds.compute.domain.Template;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.net.Networking;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
index d48a67c..f7bbc2c 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/SudoTtyFixingCustomizer.java
@@ -18,16 +18,15 @@
  */
 package org.apache.brooklyn.location.jclouds;
 
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks.OnFailingTask;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 import org.jclouds.compute.ComputeService;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.ssh.SshTasks.OnFailingTask;
-
 /**
  * Wraps Brooklyn's sudo-tty mitigations in a {@link JcloudsLocationCustomizer} for easy(-ish) consumption
  * in YAML blueprints:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
index 687a486..eb01bb1 100644
--- a/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
+++ b/locations/jclouds/src/main/java/org/apache/brooklyn/location/jclouds/networking/JcloudsLocationSecurityGroupCustomizer.java
@@ -28,6 +28,7 @@ import java.util.concurrent.ExecutionException;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.location.geo.LocalhostExternalIpLoader;
 import org.apache.brooklyn.location.jclouds.JcloudsLocation;
 import org.apache.brooklyn.location.jclouds.JcloudsLocationCustomizer;
@@ -45,11 +46,10 @@ import org.jclouds.providers.ProviderMetadata;
 import org.jclouds.providers.Providers;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
 import org.apache.brooklyn.location.jclouds.BasicJcloudsLocationCustomizer;
+
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.net.Cidr;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/test/java/brooklyn/entity/rebind/persister/jclouds/BlobStoreExpiryTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/brooklyn/entity/rebind/persister/jclouds/BlobStoreExpiryTest.java b/locations/jclouds/src/test/java/brooklyn/entity/rebind/persister/jclouds/BlobStoreExpiryTest.java
index 6260a8c..18211c1 100644
--- a/locations/jclouds/src/test/java/brooklyn/entity/rebind/persister/jclouds/BlobStoreExpiryTest.java
+++ b/locations/jclouds/src/test/java/brooklyn/entity/rebind/persister/jclouds/BlobStoreExpiryTest.java
@@ -28,6 +28,8 @@ import java.util.List;
 import java.util.Map.Entry;
 
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.http.client.HttpClient;
 import org.jclouds.blobstore.BlobStoreContext;
@@ -44,13 +46,13 @@ import org.testng.annotations.Test;
 
 import brooklyn.config.BrooklynProperties;
 import brooklyn.entity.basic.Entities;
+
 import org.apache.brooklyn.location.basic.LocationConfigKeys;
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
 import org.apache.brooklyn.location.jclouds.JcloudsLocation;
 import org.apache.brooklyn.location.jclouds.JcloudsUtil;
+
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyLiveTest.java b/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyLiveTest.java
index bf5f87b..75eed65 100644
--- a/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyLiveTest.java
+++ b/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyLiveTest.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.slf4j.Logger;
@@ -40,7 +41,6 @@ import brooklyn.entity.BrooklynAppLiveTestSupport;
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.text.Identifiers;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyTest.java b/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyTest.java
index af248de..ed4e2ee 100644
--- a/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyTest.java
+++ b/locations/jclouds/src/test/java/brooklyn/policy/os/CreateUserPolicyTest.java
@@ -29,6 +29,7 @@ import java.util.regex.Pattern;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.slf4j.Logger;
@@ -41,8 +42,6 @@ import brooklyn.entity.BrooklynAppUnitTestSupport;
 
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
-import brooklyn.util.internal.ssh.SshTool;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedLiveTest.java
index 9c70305..1faa83b 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedLiveTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/AbstractJcloudsStubbedLiveTest.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.location.jclouds;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.RunNodesException;
 import org.jclouds.compute.domain.NodeMetadata;
@@ -30,8 +31,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.BeforeMethod;
 
-import brooklyn.util.config.ConfigBag;
-
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BailOutJcloudsLocation.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BailOutJcloudsLocation.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BailOutJcloudsLocation.java
index c323b7f..b83bce8 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BailOutJcloudsLocation.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/BailOutJcloudsLocation.java
@@ -27,6 +27,7 @@ import javax.annotation.Nullable;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.jclouds.compute.ComputeService;
 import org.jclouds.compute.domain.Image;
 import org.jclouds.compute.domain.Template;
@@ -41,7 +42,6 @@ import brooklyn.config.BrooklynProperties;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.CompoundRuntimeException;
 import brooklyn.util.exceptions.Exceptions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
index f173646..5e535e4 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTemplateOptionsCustomisersLiveTest.java
@@ -19,9 +19,11 @@
 package org.apache.brooklyn.location.jclouds;
 
 import brooklyn.config.ConfigKey;
-import brooklyn.util.config.ConfigBag;
+
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.jclouds.aws.ec2.compute.AWSEC2TemplateOptions;
 import org.jclouds.compute.options.TemplateOptions;
 import org.jclouds.ec2.domain.BlockDeviceMapping;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTest.java
index 83ffb78..de9f950 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsLocationTest.java
@@ -32,6 +32,7 @@ import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineLocationCustomizer;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.cloud.names.CustomMachineNamer;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.jclouds.scriptbuilder.domain.OsFamily;
@@ -61,7 +62,6 @@ import org.apache.brooklyn.location.jclouds.JcloudsLocation.UserCreation;
 
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamerTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamerTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamerTest.java
index 5e25a8c..90c1bbb 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamerTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/JcloudsMachineNamerTest.java
@@ -18,12 +18,12 @@
  */
 package org.apache.brooklyn.location.jclouds;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.text.Strings;
 
 public class JcloudsMachineNamerTest {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationLiveTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationLiveTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationLiveTest.java
index 6043a09..5f717a3 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationLiveTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationLiveTest.java
@@ -27,6 +27,7 @@ import java.io.File;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
@@ -35,7 +36,6 @@ import org.testng.annotations.Test;
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.rebind.RebindTestUtils;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java
index cc52ef2..746ff89 100644
--- a/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java
+++ b/locations/jclouds/src/test/java/org/apache/brooklyn/location/jclouds/RebindJcloudsLocationTest.java
@@ -26,8 +26,9 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.rebind.RebindTestFixtureWithApp;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.net.HostAndPort;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/enricher/DeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/DeltaEnricher.java b/policy/src/main/java/brooklyn/enricher/DeltaEnricher.java
index 39b052f..9b6128c 100644
--- a/policy/src/main/java/brooklyn/enricher/DeltaEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/DeltaEnricher.java
@@ -25,9 +25,9 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import brooklyn.enricher.basic.AbstractTransformingEnricher;
-import brooklyn.util.flags.TypeCoercions;
 
 /**
  * Converts an absolute sensor into a delta sensor (i.e. the diff between the current and previous value)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java b/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
index 209b45a..884d568 100644
--- a/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
+++ b/policy/src/main/java/brooklyn/enricher/HttpLatencyDetector.java
@@ -32,6 +32,7 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,7 +45,6 @@ import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.javalang.AtomicReferences;
 import brooklyn.util.javalang.Boxing;
 import brooklyn.util.javalang.JavaClassNames;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/enricher/RollingMeanEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/RollingMeanEnricher.java b/policy/src/main/java/brooklyn/enricher/RollingMeanEnricher.java
index 0eca706..13648af 100644
--- a/policy/src/main/java/brooklyn/enricher/RollingMeanEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/RollingMeanEnricher.java
@@ -24,9 +24,9 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.enricher.basic.AbstractTypeTransformingEnricher;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.javalang.JavaClassNames;
 
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java b/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
index 9993d28..b9688d9 100644
--- a/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
+++ b/policy/src/main/java/brooklyn/enricher/RollingTimeWindowMeanEnricher.java
@@ -25,12 +25,12 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractTypeTransformingEnricher;
 import brooklyn.enricher.basic.YamlRollingTimeWindowMeanEnricher;
 import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.time.Duration;
 



[07/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/DynamicSequentialTaskTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/DynamicSequentialTaskTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/DynamicSequentialTaskTest.java
new file mode 100644
index 0000000..c4f8d4c
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/DynamicSequentialTaskTest.java
@@ -0,0 +1,371 @@
+/*
+ * 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.util.task;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+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 org.apache.brooklyn.api.management.HasTaskChildren;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.DynamicSequentialTask;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskTags;
+import org.apache.brooklyn.core.util.task.Tasks;
+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 brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.time.CountdownTimer;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+public class DynamicSequentialTaskTest {
+
+    private static final Logger log = LoggerFactory.getLogger(DynamicSequentialTaskTest.class);
+    
+    public static final Duration TIMEOUT = Duration.TEN_SECONDS;
+    public static final Duration TINY_TIME = Duration.millis(20);
+    
+    BasicExecutionManager em;
+    BasicExecutionContext ec;
+    List<String> messages;
+    Semaphore cancellations;
+    Stopwatch stopwatch;
+    Map<String,Semaphore> monitorableJobSemaphoreMap;
+    Map<String,Task<String>> monitorableTasksMap;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() {
+        em = new BasicExecutionManager("mycontext");
+        ec = new BasicExecutionContext(em);
+        cancellations = new Semaphore(0);
+        messages = new ArrayList<String>();
+        monitorableJobSemaphoreMap = MutableMap.of();
+        monitorableTasksMap = MutableMap.of();
+        monitorableTasksMap.clear();
+        stopwatch = Stopwatch.createStarted();
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (em != null) em.shutdownNow();
+    }
+
+    @Test
+    public void testSimple() throws InterruptedException, ExecutionException {
+        Callable<String> mainJob = new Callable<String>() {
+            public String call() {
+                log.info("main job - "+Tasks.current());
+                messages.add("main");
+                DynamicTasks.queue( sayTask("world") );
+                return "bye";
+            }            
+        };
+        DynamicSequentialTask<String> t = new DynamicSequentialTask<String>(mainJob);
+        // this should be added before anything added when the task is invoked
+        t.queue(sayTask("hello"));
+        
+        Assert.assertEquals(messages, Lists.newArrayList());
+        Assert.assertEquals(t.isBegun(), false);
+        Assert.assertEquals(Iterables.size(t.getChildren()), 1);
+        
+        ec.submit(t);
+        Assert.assertEquals(t.isSubmitted(), true);
+        Assert.assertEquals(t.getUnchecked(Duration.ONE_SECOND), "bye");
+        long elapsed = t.getEndTimeUtc() - t.getSubmitTimeUtc();
+        Assert.assertTrue(elapsed < 1000, "elapsed time should have been less than 1s but was "+
+                Time.makeTimeString(elapsed, true));
+        Assert.assertEquals(Iterables.size(t.getChildren()), 2);
+        Assert.assertEquals(messages.size(), 3, "expected 3 entries, but had "+messages);
+        // either main or hello can be first, but world should be last 
+        Assert.assertEquals(messages.get(2), "world");
+    }
+    
+    public Callable<String> sayCallable(final String message, final Duration duration, final String message2) {
+        return new Callable<String>() {
+            public String call() {
+                try {
+                    if (message != null) {
+                        log.info("saying: "+message+ " - "+Tasks.current());
+                        synchronized (messages) {
+                            messages.add(message);
+                            messages.notifyAll();
+                        }
+                    }
+                    if (message2 != null) {
+                        log.info("will say "+message2+" after "+duration);
+                    }
+                    if (duration != null && duration.toMilliseconds() > 0) {
+                        Thread.sleep(duration.toMillisecondsRoundingUp());
+                    }
+                } catch (InterruptedException e) {
+                    cancellations.release();
+                    throw Exceptions.propagate(e);
+                }
+                if (message2 != null) {
+                    log.info("saying: "+message2+ " - "+Tasks.current());
+                    synchronized (messages) {
+                        messages.add(message2);
+                        messages.notifyAll();
+                    }
+                }
+                return message;
+            }            
+        };
+    }
+    
+    public Task<String> sayTask(String message) {
+        return sayTask(message, null, null);
+    }
+    
+    public Task<String> sayTask(String message, Duration duration, String message2) {
+        return Tasks.<String>builder().body(sayCallable(message, duration, message2)).build();
+    }
+    
+    @Test
+    public void testComplex() throws InterruptedException, ExecutionException {
+        Task<List<?>> t = Tasks.sequential(
+                sayTask("1"),
+                sayTask("2"),
+                Tasks.parallel(sayTask("4"), sayTask("3")),
+                sayTask("5")
+            );
+        ec.submit(t);
+        Assert.assertEquals(t.get().size(), 4); 
+        Asserts.assertEqualsIgnoringOrder((List<?>)t.get().get(2), ImmutableSet.of("3", "4"));
+        Assert.assertTrue(messages.equals(Arrays.asList("1", "2", "3", "4", "5")) || messages.equals(Arrays.asList("1", "2", "4", "3", "5")), "messages="+messages);
+    }
+    
+    @Test
+    public void testCancelled() throws InterruptedException, ExecutionException {
+        Task<List<?>> t = Tasks.sequential(
+                sayTask("1"),
+                sayTask("2a", Duration.THIRTY_SECONDS, "2b"),
+                sayTask("3"));
+        ec.submit(t);
+        synchronized (messages) {
+            while (messages.size() <= 1)
+                messages.wait();
+        }
+        Assert.assertEquals(messages, Arrays.asList("1", "2a"));
+        Time.sleep(Duration.millis(50));
+        t.cancel(true);
+        Assert.assertTrue(t.isDone());
+        // 2 should get cancelled, and invoke the cancellation semaphore
+        // 3 should get cancelled and not run at all
+        Assert.assertEquals(messages, Arrays.asList("1", "2a"));
+        
+        // Need to ensure that 2 has been started; race where we might cancel it before its run method
+        // is even begun. Hence doing "2a; pause; 2b" where nothing is interruptable before pause.
+        Assert.assertTrue(cancellations.tryAcquire(10, TimeUnit.SECONDS));
+        
+        Iterator<Task<?>> ci = ((HasTaskChildren)t).getChildren().iterator();
+        Assert.assertEquals(ci.next().get(), "1");
+        Task<?> task2 = ci.next();
+        Assert.assertTrue(task2.isBegun());
+        Assert.assertTrue(task2.isDone());
+        Assert.assertTrue(task2.isCancelled());
+        
+        Task<?> task3 = ci.next();
+        Assert.assertFalse(task3.isBegun());
+        Assert.assertTrue(task2.isDone());
+        Assert.assertTrue(task2.isCancelled());
+        
+        // but we do _not_ get a mutex from task3 as it does not run (is not interrupted)
+        Assert.assertEquals(cancellations.availablePermits(), 0);
+    }
+
+    protected Task<String> monitorableTask(final String id) {
+        return monitorableTask(null, id, null);
+    }
+    protected Task<String> monitorableTask(final Runnable pre, final String id, final Callable<String> post) {
+        Task<String> t = Tasks.<String>builder().body(monitorableJob(pre, id, post)).build();
+        monitorableTasksMap.put(id, t);
+        return t;
+    }
+    protected Callable<String> monitorableJob(final String id) {
+        return monitorableJob(null, id, null);
+    }
+    protected Callable<String> monitorableJob(final Runnable pre, final String id, final Callable<String> post) {
+        monitorableJobSemaphoreMap.put(id, new Semaphore(0));
+        return new Callable<String>() {
+            @Override
+            public String call() throws Exception {
+                if (pre!=null) pre.run();
+                // wait for semaphore
+                if (!monitorableJobSemaphoreMap.get(id).tryAcquire(1, TIMEOUT.toMilliseconds(), TimeUnit.MILLISECONDS))
+                    throw new IllegalStateException("timeout for "+id);
+                synchronized (messages) {
+                    messages.add(id);
+                    messages.notifyAll();
+                }
+                if (post!=null) return post.call();
+                return id;
+            }
+        };
+    }
+    protected void releaseMonitorableJob(final String id) {
+        monitorableJobSemaphoreMap.get(id).release();
+    }
+    protected void waitForMessage(final String id) {
+        CountdownTimer timer = CountdownTimer.newInstanceStarted(TIMEOUT);
+        synchronized (messages) {
+            while (!timer.isExpired()) {
+                if (messages.contains(id)) return;
+                timer.waitOnForExpiryUnchecked(messages);
+            }
+        }
+        Assert.fail("Did not see message "+id);
+    }
+    protected void releaseAndWaitForMonitorableJob(final String id) {
+        releaseMonitorableJob(id);
+        waitForMessage(id);
+    }
+    
+    @Test
+    public void testChildrenRunConcurrentlyWithPrimary() {
+        Task<String> t = Tasks.<String>builder().dynamic(true)
+            .body(monitorableJob("main"))
+            .add(monitorableTask("1")).add(monitorableTask("2")).build();
+        ec.submit(t);
+        releaseAndWaitForMonitorableJob("1");
+        releaseAndWaitForMonitorableJob("main");
+        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
+        releaseMonitorableJob("2");
+        
+        Assert.assertTrue(t.blockUntilEnded(TIMEOUT));
+        Assert.assertEquals(messages, MutableList.of("1", "main", "2"));
+        Assert.assertTrue(stopwatch.elapsed(TimeUnit.MILLISECONDS) < TIMEOUT.toMilliseconds(), "took too long: "+stopwatch);
+        Assert.assertFalse(t.isError());
+    }
+    
+    protected static class FailRunnable implements Runnable {
+        @Override public void run() { throw new RuntimeException("Planned exception for test"); }
+    }
+    protected static class FailCallable implements Callable<String> {
+        @Override public String call() { throw new RuntimeException("Planned exception for test"); }
+    }
+    
+    @Test
+    public void testByDefaultChildrenFailureAbortsSecondaryFailsPrimaryButNotAbortsPrimary() {
+        Task<String> t1 = monitorableTask(null, "1", new FailCallable());
+        Task<String> t = Tasks.<String>builder().dynamic(true)
+            .body(monitorableJob("main"))
+            .add(t1).add(monitorableTask("2")).build();
+        ec.submit(t);
+        releaseAndWaitForMonitorableJob("1");
+        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
+        releaseMonitorableJob("main");
+        
+        Assert.assertTrue(t.blockUntilEnded(TIMEOUT));
+        Assert.assertEquals(messages, MutableList.of("1", "main"));
+        Assert.assertTrue(stopwatch.elapsed(TimeUnit.MILLISECONDS) < TIMEOUT.toMilliseconds(), "took too long: "+stopwatch);
+        Assert.assertTrue(t.isError());
+        Assert.assertTrue(t1.isError());
+    }
+
+    @Test
+    public void testWhenSwallowingChildrenFailureDoesNotAbortSecondaryOrFailPrimary() {
+        Task<String> t1 = monitorableTask(null, "1", new FailCallable());
+        Task<String> t = Tasks.<String>builder().dynamic(true)
+            .body(monitorableJob("main"))
+            .add(t1).add(monitorableTask("2")).swallowChildrenFailures(true).build();
+        ec.submit(t);
+        releaseAndWaitForMonitorableJob("1");
+        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
+        releaseAndWaitForMonitorableJob("2");
+        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
+        releaseMonitorableJob("main");
+        Assert.assertTrue(t.blockUntilEnded(TIMEOUT));
+        Assert.assertEquals(messages, MutableList.of("1", "2", "main"));
+        Assert.assertTrue(stopwatch.elapsed(TimeUnit.MILLISECONDS) < TIMEOUT.toMilliseconds(), "took too long: "+stopwatch);
+        Assert.assertFalse(t.isError());
+        Assert.assertTrue(t1.isError());
+    }
+
+    @Test
+    public void testInessentialChildrenFailureDoesNotAbortSecondaryOrFailPrimary() {
+        Task<String> t1 = monitorableTask(null, "1", new FailCallable());
+        TaskTags.markInessential(t1);
+        Task<String> t = Tasks.<String>builder().dynamic(true)
+            .body(monitorableJob("main"))
+            .add(t1).add(monitorableTask("2")).build();
+        ec.submit(t);
+        releaseAndWaitForMonitorableJob("1");
+        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
+        releaseAndWaitForMonitorableJob("2");
+        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
+        releaseMonitorableJob("main");
+        Assert.assertTrue(t.blockUntilEnded(TIMEOUT));
+        Assert.assertEquals(messages, MutableList.of("1", "2", "main"));
+        Assert.assertTrue(stopwatch.elapsed(TimeUnit.MILLISECONDS) < TIMEOUT.toMilliseconds(), "took too long: "+stopwatch);
+        Assert.assertFalse(t.isError());
+        Assert.assertTrue(t1.isError());
+    }
+
+    @Test
+    public void testTaskBuilderUsingAddVarargChildren() {
+        Task<String> t = Tasks.<String>builder().dynamic(true)
+            .body(monitorableJob("main"))
+            .add(monitorableTask("1"), monitorableTask("2"))
+            .build();
+        ec.submit(t);
+        releaseAndWaitForMonitorableJob("1");
+        releaseAndWaitForMonitorableJob("2");
+        releaseAndWaitForMonitorableJob("main");
+        
+        Assert.assertEquals(messages, MutableList.of("1", "2", "main"));
+    }
+    
+    @Test
+    public void testTaskBuilderUsingAddAllChildren() {
+        Task<String> t = Tasks.<String>builder().dynamic(true)
+            .body(monitorableJob("main"))
+            .addAll(ImmutableList.of(monitorableTask("1"), monitorableTask("2")))
+            .build();
+        ec.submit(t);
+        releaseAndWaitForMonitorableJob("1");
+        releaseAndWaitForMonitorableJob("2");
+        releaseAndWaitForMonitorableJob("main");
+        
+        Assert.assertEquals(messages, MutableList.of("1", "2", "main"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/NonBasicTaskExecutionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/NonBasicTaskExecutionTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/NonBasicTaskExecutionTest.java
new file mode 100644
index 0000000..980a701
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/NonBasicTaskExecutionTest.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.core.util.task;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.apache.brooklyn.core.util.task.ForwardingTask;
+import org.apache.brooklyn.core.util.task.TaskInternal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableMap;
+
+/**
+ * Test the operation of the {@link BasicTask} class.
+ *
+ * TODO clarify test purpose
+ */
+public class NonBasicTaskExecutionTest {
+    private static final Logger log = LoggerFactory.getLogger(NonBasicTaskExecutionTest.class);
+ 
+    private static final int TIMEOUT_MS = 10*1000;
+    
+    public static class ConcreteForwardingTask<T> extends ForwardingTask<T> {
+        private final TaskInternal<T> delegate;
+
+        ConcreteForwardingTask(TaskInternal<T> delegate) {
+            this.delegate = delegate;
+        }
+        
+        @Override
+        protected TaskInternal<T> delegate() {
+            return delegate;
+        }
+    }
+    
+    private BasicExecutionManager em;
+    private Map<Integer,String> data;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        em = new BasicExecutionManager("mycontext");
+        data = Collections.synchronizedMap(new HashMap<Integer,String>());
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (em != null) em.shutdownNow();
+    }
+    
+    @Test
+    public void runSimpleTask() throws Exception {
+        TaskInternal<Object> t = new ConcreteForwardingTask<Object>(new BasicTask<Object>(new Callable<Object>() {
+            @Override public Object call() {
+                return data.put(1, "b");
+            }}));
+        data.put(1, "a");
+        Task<?> t2 = em.submit(MutableMap.of("tag", "A"), t);
+        assertEquals("a", t.get());
+        assertEquals("a", t2.get());
+        assertSame(t, t2, "t="+t+"; t2="+t2);
+        assertEquals("b", data.get(1));
+    }
+    
+    @Test
+    public void runBasicTaskWithWaits() throws Exception {
+        final CountDownLatch signalStarted = new CountDownLatch(1);
+        final CountDownLatch allowCompletion = new CountDownLatch(1);
+        final TaskInternal<Object> t = new ConcreteForwardingTask<Object>(new BasicTask<Object>(new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                Object result = data.put(1, "b");
+                signalStarted.countDown();
+                assertTrue(allowCompletion.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+                return result;
+            }}));
+        data.put(1, "a");
+
+        Task<?> t2 = em.submit(MutableMap.of("tag", "A"), t);
+        assertEquals(t, t2);
+        assertFalse(t.isDone());
+        
+        assertTrue(signalStarted.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertEquals("b", data.get(1));
+        assertFalse(t.isDone());
+        
+        log.debug("runBasicTaskWithWaits, BasicTask status: {}", t.getStatusDetail(false));
+        
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                t.getStatusDetail(false).toLowerCase().contains("waiting");
+            }});
+        // "details="+t.getStatusDetail(false))
+        
+        allowCompletion.countDown();
+        assertEquals("a", t.get());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/ScheduledExecutionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/ScheduledExecutionTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/ScheduledExecutionTest.java
new file mode 100644
index 0000000..3b338da
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/ScheduledExecutionTest.java
@@ -0,0 +1,291 @@
+/*
+ * 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.util.task;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.apache.brooklyn.core.util.task.ScheduledTask;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.RuntimeInterruptedException;
+import brooklyn.util.javalang.JavaClassNames;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Lists;
+
+@SuppressWarnings({"unchecked","rawtypes"})
+public class ScheduledExecutionTest {
+
+    public static final Logger log = LoggerFactory.getLogger(ScheduledExecutionTest.class);
+    
+    @Test
+    public void testScheduledTask() throws Exception {
+        int PERIOD = 20;
+        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
+        final AtomicInteger i = new AtomicInteger(0);
+        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", 2*PERIOD, "period", PERIOD, "maxIterations", 5), new Callable<Task<?>>() {
+            public Task<?> call() throws Exception {
+                return new BasicTask<Integer>(new Callable<Integer>() {
+                    public Integer call() {
+                        log.debug("task running: "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
+                        return i.incrementAndGet();
+                    }});
+            }});
+    
+        log.info("submitting {} {}", t, t.getStatusDetail(false));
+        m.submit(t);
+        log.info("submitted {} {}", t, t.getStatusDetail(false));
+        Integer interimResult = (Integer) t.get();
+        log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)});
+        assertTrue(i.get() > 0, "i="+i);
+        t.blockUntilEnded();
+        Integer finalResult = (Integer) t.get();
+        log.info("ended ({}) {} {}", new Object[] {finalResult, t, t.getStatusDetail(false)});
+        assertEquals(finalResult, (Integer)5);
+        assertEquals(i.get(), 5);
+    }
+
+    /** like testScheduledTask but the loop is terminated by the task itself adjusting the period */
+    @Test
+    public void testScheduledTaskSelfEnding() throws Exception {
+        int PERIOD = 20;
+        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
+        final AtomicInteger i = new AtomicInteger(0);
+        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", 2*PERIOD, "period", PERIOD), new Callable<Task<?>>() {
+            public Task<?> call() throws Exception {
+                return new BasicTask<Integer>(new Callable<Integer>() {
+                    public Integer call() {
+                        ScheduledTask submitter = (ScheduledTask) ((BasicTask)Tasks.current()).getSubmittedByTask();
+                        if (i.get() >= 4) submitter.period = null;
+                        log.info("task running ("+i+"): "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
+                        return i.incrementAndGet();
+                    }});
+            }});
+    
+        log.info("submitting {} {}", t, t.getStatusDetail(false));
+        m.submit(t);
+        log.info("submitted {} {}", t, t.getStatusDetail(false));
+        Integer interimResult = (Integer) t.get();
+        log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)});
+        assertTrue(i.get() > 0);
+        t.blockUntilEnded();
+        Integer finalResult = (Integer) t.get();
+        log.info("ended ({}) {} {}", new Object[] {finalResult, t, t.getStatusDetail(false)});
+        assertEquals(finalResult, (Integer)5);
+        assertEquals(i.get(), 5);
+    }
+
+    @Test
+    public void testScheduledTaskCancelEnding() throws Exception {
+        Duration PERIOD = Duration.millis(20);
+        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
+        final AtomicInteger i = new AtomicInteger();
+        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", PERIOD.times(2), "period", PERIOD), new Callable<Task<?>>() {
+            public Task<?> call() throws Exception {
+                return new BasicTask<Integer>(new Callable<Integer>() {
+                    public Integer call() {
+                        log.info("task running ("+i+"): "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
+                        ScheduledTask submitter = (ScheduledTask) ((BasicTask)Tasks.current()).getSubmittedByTask();
+                        i.incrementAndGet();
+                        if (i.get() >= 5) submitter.cancel();
+                        return i.get();
+                    }});
+            }});
+    
+        log.info(JavaClassNames.niceClassAndMethod()+" - submitting {} {}", t, t.getStatusDetail(false));
+        m.submit(t);
+        log.info("submitted {} {}", t, t.getStatusDetail(false));
+        Integer interimResult = (Integer) t.get();
+        log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)});
+        assertTrue(i.get() > 0);
+        t.blockUntilEnded();
+//      int finalResult = t.get()
+        log.info("ended ({}) {} {}", new Object[] {i, t, t.getStatusDetail(false)});
+//      assertEquals(finalResult, 5)
+        assertEquals(i.get(), 5);
+    }
+
+    @Test(groups="Integration")
+    public void testScheduledTaskCancelOuter() throws Exception {
+        final Duration PERIOD = Duration.millis(20);
+        final Duration CYCLE_DELAY = Duration.ONE_SECOND;
+        // this should be enough to start the next cycle, but not so much that the cycle ends;
+        // and enough that when a task is interrupted it terminates within this period
+        final Duration SMALL_FRACTION_OF_CYCLE_DELAY = PERIOD.add(CYCLE_DELAY.multiply(0.1));
+        
+        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
+        final AtomicInteger i = new AtomicInteger();
+        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", PERIOD.times(2), "period", PERIOD), new Callable<Task<?>>() {
+            public Task<?> call() throws Exception {
+                return new BasicTask<Integer>(new Callable<Integer>() {
+                    public Integer call() {
+                        log.info("task running ("+i+"): "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
+                        Time.sleep(CYCLE_DELAY);
+                        i.incrementAndGet();
+                        return i.get();
+                    }});
+            }});
+    
+        log.info(JavaClassNames.niceClassAndMethod()+" - submitting {} {}", t, t.getStatusDetail(false));
+        m.submit(t);
+        log.info("submitted {} {}", t, t.getStatusDetail(false));
+        Integer interimResult = (Integer) t.get();
+        log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)});
+        assertEquals(i.get(), 1);
+        
+        Time.sleep(SMALL_FRACTION_OF_CYCLE_DELAY);
+        assertEquals(t.get(), 2);
+        
+        Time.sleep(SMALL_FRACTION_OF_CYCLE_DELAY);
+        Stopwatch timer = Stopwatch.createUnstarted();
+        t.cancel(true);
+        t.blockUntilEnded();
+//      int finalResult = t.get()
+        log.info("blocked until ended ({}) {} {}, in {}", new Object[] {i, t, t.getStatusDetail(false), Duration.of(timer)});
+        try {
+            t.get();
+            Assert.fail("Should have failed getting result of cancelled "+t);
+        } catch (Exception e) {
+            /* expected */
+        }
+        assertEquals(i.get(), 2);
+        log.info("ended ({}) {} {}, in {}", new Object[] {i, t, t.getStatusDetail(false), Duration.of(timer)});
+        Assert.assertTrue(Duration.of(timer).isShorterThan(SMALL_FRACTION_OF_CYCLE_DELAY));
+    }
+
+    @Test(groups="Integration")
+    public void testScheduledTaskCancelInterrupts() throws Exception {
+        final Duration PERIOD = Duration.millis(20);
+        final Duration CYCLE_DELAY = Duration.ONE_SECOND;
+        // this should be enough to start the next cycle, but not so much that the cycle ends;
+        // and enough that when a task is interrupted it terminates within this period
+        final Duration SMALL_FRACTION_OF_CYCLE_DELAY = PERIOD.add(CYCLE_DELAY.multiply(0.1));
+        
+        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
+        final Semaphore interruptedSemaphore = new Semaphore(0);
+        final AtomicInteger i = new AtomicInteger();
+        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", PERIOD.times(2), "period", PERIOD), new Callable<Task<?>>() {
+            public Task<?> call() throws Exception {
+                return new BasicTask<Integer>(new Callable<Integer>() {
+                    public Integer call() {
+                        try {
+                            log.info("task running ("+i+"): "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
+                            Time.sleep(CYCLE_DELAY);
+                            i.incrementAndGet();
+                            return i.get();
+                        } catch (RuntimeInterruptedException e) {
+                            interruptedSemaphore.release();
+                            throw Exceptions.propagate(e);
+                        }
+                    }});
+            }});
+    
+        log.info(JavaClassNames.niceClassAndMethod()+" - submitting {} {}", t, t.getStatusDetail(false));
+        m.submit(t);
+        log.info("submitted {} {}", t, t.getStatusDetail(false));
+        Integer interimResult = (Integer) t.get();
+        log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)});
+        assertEquals(i.get(), 1);
+        
+        Time.sleep(SMALL_FRACTION_OF_CYCLE_DELAY);
+        assertEquals(t.get(), 2);
+        
+        Time.sleep(SMALL_FRACTION_OF_CYCLE_DELAY);
+        Stopwatch timer = Stopwatch.createUnstarted();
+        t.cancel(true);
+        t.blockUntilEnded();
+//      int finalResult = t.get()
+        log.info("blocked until ended ({}) {} {}, in {}", new Object[] {i, t, t.getStatusDetail(false), Duration.of(timer)});
+        try {
+            t.get();
+            Assert.fail("Should have failed getting result of cancelled "+t);
+        } catch (Exception e) {
+            /* expected */
+        }
+        assertEquals(i.get(), 2);
+        Assert.assertTrue(interruptedSemaphore.tryAcquire(1, SMALL_FRACTION_OF_CYCLE_DELAY.toMilliseconds(), TimeUnit.MILLISECONDS), "child thread was not interrupted");
+        log.info("ended ({}) {} {}, in {}", new Object[] {i, t, t.getStatusDetail(false), Duration.of(timer)});
+        Assert.assertTrue(Duration.of(timer).isShorterThan(SMALL_FRACTION_OF_CYCLE_DELAY));
+    }
+
+    @Test(groups="Integration")
+    public void testScheduledTaskTakesLongerThanPeriod() throws Exception {
+        final int PERIOD = 1;
+        final int SLEEP_TIME = 100;
+        final int EARLY_RETURN_GRACE = 10;
+        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
+        final List<Long> execTimes = new CopyOnWriteArrayList<Long>();
+        
+        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", PERIOD, "period", PERIOD), new Callable<Task<?>>() {
+            public Task<?> call() throws Exception {
+                return new BasicTask<Void>(new Runnable() {
+                    public void run() {
+                        execTimes.add(System.currentTimeMillis());
+                        try {
+                            Thread.sleep(100);
+                        } catch (InterruptedException e) {
+                            throw Exceptions.propagate(e);
+                        }
+                    }});
+            }});
+    
+        m.submit(t);
+        
+        Asserts.succeedsEventually(new Runnable() {
+            public void run() {
+                assertTrue(execTimes.size() > 3, "size="+execTimes.size());
+            }});
+        
+        List<Long> timeDiffs = Lists.newArrayList();
+        long prevExecTime = -1;
+        for (Long execTime : execTimes) {
+            if (prevExecTime == -1) {
+                prevExecTime = execTime;
+            } else {
+                timeDiffs.add(execTime - prevExecTime);
+                prevExecTime = execTime;
+            }
+        }
+        
+        for (Long timeDiff : timeDiffs) {
+            if (timeDiff < (SLEEP_TIME - EARLY_RETURN_GRACE)) fail("timeDiffs="+timeDiffs+"; execTimes="+execTimes);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/SingleThreadedSchedulerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/SingleThreadedSchedulerTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/SingleThreadedSchedulerTest.java
new file mode 100644
index 0000000..e3420c8
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/SingleThreadedSchedulerTest.java
@@ -0,0 +1,195 @@
+/*
+ * 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.util.task;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.apache.brooklyn.core.util.task.SingleThreadedScheduler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.util.concurrent.Callables;
+
+public class SingleThreadedSchedulerTest {
+
+    private static final Logger log = LoggerFactory.getLogger(SingleThreadedSchedulerTest.class);
+    
+    private BasicExecutionManager em;
+    
+    @BeforeMethod
+    public void setUp() {
+        em = new BasicExecutionManager("mycontextid");
+        em.setTaskSchedulerForTag("category1", SingleThreadedScheduler.class);
+    }
+    
+    @AfterMethod
+    public void tearDown() {
+        if (em != null) em.shutdownNow();
+    }
+    
+    @Test
+    public void testExecutesInOrder() throws Exception {
+        final int NUM_TIMES = 1000;
+        final List<Integer> result = new CopyOnWriteArrayList<Integer>();
+        for (int i = 0; i < NUM_TIMES; i++) {
+            final int counter = i;
+            em.submit(MutableMap.of("tag", "category1"), new Runnable() {
+                public void run() {
+                    result.add(counter);
+                }});
+        }
+        
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                assertEquals(result.size(), NUM_TIMES);
+            }});
+
+        for (int i = 0; i < NUM_TIMES; i++) {
+            assertEquals(result.get(i), (Integer)i);
+        }        
+    }
+    
+    @Test
+    public void testLargeQueueDoesNotConsumeTooManyThreads() throws Exception {
+        final int NUM_TIMES = 3000;
+        final CountDownLatch latch = new CountDownLatch(1);
+        BasicTask<Void> blockingTask = new BasicTask<Void>(newLatchAwaiter(latch));
+        em.submit(MutableMap.of("tag", "category1"), blockingTask);
+        
+        final AtomicInteger counter = new AtomicInteger(0);
+        for (int i = 0; i < NUM_TIMES; i++) {
+            BasicTask<Void> t = new BasicTask<Void>(new Runnable() {
+                public void run() {
+                    counter.incrementAndGet();
+                }});
+            em.submit(MutableMap.of("tag", "category1"), t);
+            if (i % 500 == 0) log.info("Submitted "+i+" jobs...");
+        }
+
+        Thread.sleep(100); // give it more of a chance to create the threads before we let them execute
+        latch.countDown();
+
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                assertEquals(counter.get(), NUM_TIMES);
+            }});
+    }
+    
+    @Test
+    public void testGetResultOfQueuedTaskBeforeItExecutes() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        em.submit(MutableMap.of("tag", "category1"), newLatchAwaiter(latch));
+        
+        BasicTask<Integer> t = new BasicTask<Integer>(Callables.returning(123));
+        Future<Integer> future = em.submit(MutableMap.of("tag", "category1"), t);
+
+        Thread thread = new Thread(new Runnable() {
+            public void run() {
+                try {
+                    Thread.sleep(10);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                }
+                latch.countDown();
+            }});
+        thread.start();
+        assertEquals(future.get(), (Integer)123);
+    }
+    
+    @Test
+    public void testGetResultOfQueuedTaskBeforeItExecutesWithTimeout() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        em.submit(MutableMap.of("tag", "category1"), newLatchAwaiter(latch));
+        
+        BasicTask<Integer> t = new BasicTask<Integer>(Callables.returning(123));
+        Future<Integer> future = em.submit(MutableMap.of("tag", "category1"), t);
+
+        try {
+            assertEquals(future.get(10, TimeUnit.MILLISECONDS), (Integer)123);
+            fail();
+        } catch (TimeoutException e) {
+            // success
+        }
+    }
+    
+    @Test
+    public void testCancelQueuedTaskBeforeItExecutes() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        em.submit(MutableMap.of("tag", "category1"), newLatchAwaiter(latch));
+        
+        final AtomicBoolean executed = new AtomicBoolean();
+        BasicTask<?> t = new BasicTask<Void>(new Runnable() {
+            public void run() {
+                executed.set(true);
+            }});
+        Future<?> future = em.submit(MutableMap.of("tag", "category1"), t);
+
+        future.cancel(true);
+        latch.countDown();
+        Thread.sleep(10);
+        try {
+            future.get();
+        } catch (CancellationException e) {
+            // success
+        }
+        assertFalse(executed.get());
+    }
+    
+    @Test
+    public void testGetResultOfQueuedTaskAfterItExecutes() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        em.submit(MutableMap.of("tag", "category1"), newLatchAwaiter(latch));
+        
+        BasicTask<Integer> t = new BasicTask<Integer>(Callables.returning(123));
+        Future<Integer> future = em.submit(MutableMap.of("tag", "category1"), t);
+
+        latch.countDown();
+        assertEquals(future.get(), (Integer)123);
+    }
+    
+    private Callable<Void> newLatchAwaiter(final CountDownLatch latch) {
+        return new Callable<Void>() {
+            public Void call() throws Exception {
+                latch.await();
+                return null;
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/TaskFinalizationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/TaskFinalizationTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/TaskFinalizationTest.java
new file mode 100644
index 0000000..1ff181b
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/TaskFinalizationTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.util.task;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Stopwatch;
+
+public class TaskFinalizationTest {
+
+    private static final Logger log = LoggerFactory.getLogger(TaskFinalizationTest.class);
+    
+    // integration because it can take a while (and finalizers aren't even guaranteed)
+    @Test(groups="Integration")
+    public void testFinalizerInvoked() throws InterruptedException {
+        BasicTask<?> t = new BasicTask<Void>(new Runnable() { public void run() { /* no op */ }});
+        final Semaphore x = new Semaphore(0);
+        t.setFinalizer(new BasicTask.TaskFinalizer() {
+            public void onTaskFinalization(Task<?> t) {
+                synchronized (x) { 
+                    x.release();
+                }
+            }
+        });
+        t = null;
+        Stopwatch watch = Stopwatch.createStarted();
+        for (int i=0; i<30; i++) {
+            System.gc(); System.gc();
+            if (x.tryAcquire(1, TimeUnit.SECONDS)) {
+                log.info("finalizer ran after "+Time.makeTimeStringRounded(watch));
+                return;
+            }
+        }
+        Assert.fail("finalizer did not run in time");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/TasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/TasksTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/TasksTest.java
new file mode 100644
index 0000000..0800984
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/TasksTest.java
@@ -0,0 +1,184 @@
+/*
+ * 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.util.task;
+
+import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.TaskInternal;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ValueResolver;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.apache.brooklyn.test.entity.TestEntity;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.entity.basic.EntityFunctions;
+import brooklyn.util.guava.Functionals;
+import brooklyn.util.repeat.Repeater;
+import brooklyn.util.time.Duration;
+
+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.util.concurrent.Callables;
+
+
+public class TasksTest extends BrooklynAppUnitTestSupport {
+
+    private ExecutionContext executionContext;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        executionContext = app.getExecutionContext();
+    }
+    
+    @Test
+    public void testResolveNull() throws Exception {
+        assertResolvesValue(null, String.class, null);
+    }
+    
+    @Test
+    public void testResolveValueCastsToType() throws Exception {
+        assertResolvesValue(123, String.class, "123");
+    }
+    
+    @Test
+    public void testResolvesAttributeWhenReady() throws Exception {
+        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
+        assertResolvesValue(attributeWhenReady(app, TestApplication.MY_ATTRIBUTE), String.class, "myval");
+    }
+    
+    @Test
+    public void testResolvesMapWithAttributeWhenReady() throws Exception {
+        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
+        Map<?,?> orig = ImmutableMap.of("mykey", attributeWhenReady(app, TestApplication.MY_ATTRIBUTE));
+        Map<?,?> expected = ImmutableMap.of("mykey", "myval");
+        assertResolvesValue(orig, String.class, expected);
+    }
+    
+    @Test
+    public void testResolvesSetWithAttributeWhenReady() throws Exception {
+        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
+        Set<?> orig = ImmutableSet.of(attributeWhenReady(app, TestApplication.MY_ATTRIBUTE));
+        Set<?> expected = ImmutableSet.of("myval");
+        assertResolvesValue(orig, String.class, expected);
+    }
+    
+    @Test
+    public void testResolvesMapOfMapsWithAttributeWhenReady() throws Exception {
+        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
+        Map<?,?> orig = ImmutableMap.of("mykey", ImmutableMap.of("mysubkey", attributeWhenReady(app, TestApplication.MY_ATTRIBUTE)));
+        Map<?,?> expected = ImmutableMap.of("mykey", ImmutableMap.of("mysubkey", "myval"));
+        assertResolvesValue(orig, String.class, expected);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testResolvesIterableOfMapsWithAttributeWhenReady() throws Exception {
+        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
+        // using Iterables.concat so that orig is of type FluentIterable rather than List etc
+        Iterable<?> orig = Iterables.concat(ImmutableList.of(ImmutableMap.of("mykey", attributeWhenReady(app, TestApplication.MY_ATTRIBUTE))));
+        Iterable<Map<?,?>> expected = ImmutableList.<Map<?,?>>of(ImmutableMap.of("mykey", "myval"));
+        assertResolvesValue(orig, String.class, expected);
+    }
+    
+    private void assertResolvesValue(Object actual, Class<?> type, Object expected) throws Exception {
+        Object result = Tasks.resolveValue(actual, type, executionContext);
+        assertEquals(result, expected);
+    }
+    
+    @Test
+    public void testErrorsResolvingPropagatesOrSwallowedAllCorrectly() throws Exception {
+        app.setConfig(TestEntity.CONF_OBJECT, ValueResolverTest.newThrowTask(Duration.ZERO));
+        Task<Object> t = Tasks.builder().body(Functionals.callable(EntityFunctions.config(TestEntity.CONF_OBJECT), app)).build();
+        ValueResolver<Object> v = Tasks.resolving(t).as(Object.class).context(app.getExecutionContext());
+        
+        ValueResolverTest.assertThrowsOnMaybe(v);
+        ValueResolverTest.assertThrowsOnGet(v);
+        
+        v.swallowExceptions();
+        ValueResolverTest.assertMaybeIsAbsent(v);
+        ValueResolverTest.assertThrowsOnGet(v);
+        
+        v.defaultValue("foo");
+        ValueResolverTest.assertMaybeIsAbsent(v);
+        assertEquals(v.clone().get(), "foo");
+        assertResolvesValue(v, Object.class, "foo");
+    }
+
+    @Test
+    public void testRepeater() throws Exception {
+        Task<?> t;
+        
+        t = Tasks.requiring(Repeater.create().until(Callables.returning(true)).every(Duration.millis(1))).build();
+        app.getExecutionContext().submit(t);
+        t.get(Duration.TEN_SECONDS);
+        
+        t = Tasks.testing(Repeater.create().until(Callables.returning(true)).every(Duration.millis(1))).build();
+        app.getExecutionContext().submit(t);
+        Assert.assertEquals(t.get(Duration.TEN_SECONDS), true);
+        
+        t = Tasks.requiring(Repeater.create().until(Callables.returning(false)).limitIterationsTo(2).every(Duration.millis(1))).build();
+        app.getExecutionContext().submit(t);
+        try {
+            t.get(Duration.TEN_SECONDS);
+            Assert.fail("Should have failed");
+        } catch (Exception e) {
+            // expected
+        }
+
+        t = Tasks.testing(Repeater.create().until(Callables.returning(false)).limitIterationsTo(2).every(Duration.millis(1))).build();
+        app.getExecutionContext().submit(t);
+        Assert.assertEquals(t.get(Duration.TEN_SECONDS), false);
+    }
+
+    @Test
+    public void testRepeaterDescription() throws Exception{
+        final String description = "task description";
+        Repeater repeater = Repeater.create(description)
+            .repeat(Callables.returning(null))
+            .every(Duration.ONE_MILLISECOND)
+            .limitIterationsTo(1)
+            .until(new Callable<Boolean>() {
+                @Override
+                public Boolean call() {
+                    TaskInternal<?> current = (TaskInternal<?>)Tasks.current();
+                    assertEquals(current.getBlockingDetails(), description);
+                    return true;
+                }
+            });
+        Task<Boolean> t = Tasks.testing(repeater).build();
+        app.getExecutionContext().submit(t);
+        assertTrue(t.get(Duration.TEN_SECONDS));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/ValueResolverTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/ValueResolverTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/ValueResolverTest.java
new file mode 100644
index 0000000..9f65bc4
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/ValueResolverTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.util.task;
+
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ValueResolver;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+/**
+ * see also {@link TasksTest} for more tests
+ */
+@Test
+public class ValueResolverTest extends BrooklynAppUnitTestSupport {
+
+    private ExecutionContext executionContext;
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        executionContext = app.getExecutionContext();
+    }
+    
+    public static final Task<String> newSleepTask(final Duration timeout, final String result) {
+        return Tasks.<String>builder().body(new Callable<String>() { 
+            public String call() { 
+                Time.sleep(timeout); 
+                return result; 
+            }}
+        ).build();
+    }
+    
+    public static final Task<String> newThrowTask(final Duration timeout) {
+        return Tasks.<String>builder().body(new Callable<String>() { 
+            public String call() {
+                Time.sleep(timeout); 
+                throw new IllegalStateException("intended, during tests");
+            }}
+        ).build();
+    }
+    
+    public void testTimeoutZero() {
+        Maybe<String> result = Tasks.resolving(newSleepTask(Duration.TEN_SECONDS, "foo")).as(String.class).context(executionContext).timeout(Duration.ZERO).getMaybe();
+        Assert.assertFalse(result.isPresent());
+    }
+    
+    public void testTimeoutBig() {
+        Maybe<String> result = Tasks.resolving(newSleepTask(Duration.ZERO, "foo")).as(String.class).context(executionContext).timeout(Duration.TEN_SECONDS).getMaybe();
+        Assert.assertEquals(result.get(), "foo");
+    }
+
+    public void testNoExecutionContextOnCompleted() {
+        Task<String> t = newSleepTask(Duration.ZERO, "foo");
+        executionContext.submit(t).getUnchecked();
+        Maybe<String> result = Tasks.resolving(t).as(String.class).timeout(Duration.ZERO).getMaybe();
+        Assert.assertEquals(result.get(), "foo");
+    }
+
+    public static Throwable assertThrowsOnMaybe(ValueResolver<?> result) {
+        try {
+            result = result.clone();
+            result.getMaybe();
+            Assert.fail("should have thrown");
+            return null;
+        } catch (Exception e) { return e; }
+    }
+    public static Throwable assertThrowsOnGet(ValueResolver<?> result) {
+        result = result.clone();
+        try {
+            result.get();
+            Assert.fail("should have thrown");
+            return null;
+        } catch (Exception e) { return e; }
+    }
+    public static <T> Maybe<T> assertMaybeIsAbsent(ValueResolver<T> result) {
+        result = result.clone();
+        Maybe<T> maybe = result.getMaybe();
+        Assert.assertFalse(maybe.isPresent());
+        return maybe;
+    }
+    
+    public void testSwallowError() {
+        ValueResolver<String> result = Tasks.resolving(newThrowTask(Duration.ZERO)).as(String.class).context(executionContext).swallowExceptions();
+        assertMaybeIsAbsent(result);
+        assertThrowsOnGet(result);
+    }
+
+
+    public void testDontSwallowError() {
+        ValueResolver<String> result = Tasks.resolving(newThrowTask(Duration.ZERO)).as(String.class).context(executionContext);
+        assertThrowsOnMaybe(result);
+        assertThrowsOnGet(result);
+    }
+
+    public void testDefaultWhenSwallowError() {
+        ValueResolver<String> result = Tasks.resolving(newThrowTask(Duration.ZERO)).as(String.class).context(executionContext).swallowExceptions().defaultValue("foo");
+        assertMaybeIsAbsent(result);
+        Assert.assertEquals(result.get(), "foo");
+    }
+
+    public void testDefaultBeforeDelayAndError() {
+        ValueResolver<String> result = Tasks.resolving(newThrowTask(Duration.TEN_SECONDS)).as(String.class).context(executionContext).timeout(Duration.ZERO).defaultValue("foo");
+        assertMaybeIsAbsent(result);
+        Assert.assertEquals(result.get(), "foo");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/ssh/SshTasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/ssh/SshTasksTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/ssh/SshTasksTest.java
new file mode 100644
index 0000000..94fe3e6
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/ssh/SshTasksTest.java
@@ -0,0 +1,213 @@
+/*
+ * 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.util.task.ssh;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.ssh.BashCommandsIntegrationTest;
+import org.apache.brooklyn.core.util.task.ssh.SshFetchTaskFactory;
+import org.apache.brooklyn.core.util.task.ssh.SshFetchTaskWrapper;
+import org.apache.brooklyn.core.util.task.ssh.SshPutTaskFactory;
+import org.apache.brooklyn.core.util.task.ssh.SshPutTaskWrapper;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasksTest;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+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 brooklyn.entity.basic.BrooklynConfigKeys;
+import brooklyn.entity.basic.Entities;
+
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
+
+/**
+ * Some tests for {@link SshTasks}. Note more tests in {@link BashCommandsIntegrationTest}, 
+ * {@link SshEffectorTasksTest}, and {@link SoftwareEffectorTest}.
+ */
+public class SshTasksTest {
+
+    private static final Logger log = LoggerFactory.getLogger(SshTasksTest.class);
+    
+    ManagementContext mgmt;
+    SshMachineLocation host;
+    File tempDir;
+    
+    boolean failureExpected;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setup() throws Exception {
+        mgmt = new LocalManagementContext();
+        
+        LocalhostMachineProvisioningLocation lhc = mgmt.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
+        host = lhc.obtain();
+        clearExpectedFailure();
+        tempDir = Os.newTempDir(getClass());
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (mgmt != null) Entities.destroyAll(mgmt);
+        mgmt = null;
+        tempDir = Os.deleteRecursively(tempDir).asNullOrThrowing();
+        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;
+    }
+
+
+    protected <T> ProcessTaskWrapper<T> submit(final ProcessTaskFactory<T> tf) {
+        tf.machine(host);
+        ProcessTaskWrapper<T> t = tf.newTask();
+        mgmt.getExecutionManager().submit(t);
+        return t;
+    }
+
+    protected SshPutTaskWrapper submit(final SshPutTaskFactory tf) {
+        SshPutTaskWrapper t = tf.newTask();
+        mgmt.getExecutionManager().submit(t);
+        return t;
+    }
+
+    @Test(groups="Integration")
+    public void testSshEchoHello() {
+        ProcessTaskWrapper<Integer> t = submit(SshTasks.newSshExecTaskFactory(host, "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 testCopyTo() throws IOException {
+        String fn = Urls.mergePaths(tempDir.getPath(), "f1");
+        SshPutTaskWrapper t = submit(SshTasks.newSshPutTaskFactory(host, 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 testCopyToFailBadSubdir() throws IOException {
+        String fn = Urls.mergePaths(tempDir.getPath(), "non-existent-subdir/file");
+        SshPutTaskWrapper t = submit(SshTasks.newSshPutTaskFactory(host, fn).contents("hello world"));
+        //this doesn't fail
+        t.block();        
+        Assert.assertTrue(t.isDone());
+        setExpectingFailure();
+        try {
+            // but this does
+            t.get();
+        } catch (Exception e) {
+            log.info("The error if file cannot be written is: "+e);
+            clearExpectedFailure();
+        }
+        checkExpectedFailure();
+        // and the results indicate failure
+        Assert.assertFalse(t.isSuccessful());
+        Assert.assertNotNull(t.getException());
+        Assert.assertNotEquals(t.getExitCode(), (Integer)0);
+    }
+
+    @Test(groups="Integration")
+    public void testCopyToFailBadSubdirAllow() throws IOException {
+        String fn = Urls.mergePaths(tempDir.getPath(), "non-existent-subdir/file");
+        SshPutTaskWrapper t = submit(SshTasks.newSshPutTaskFactory(host, fn).contents("hello world").allowFailure());
+        //this doesn't fail
+        t.block();        
+        Assert.assertTrue(t.isDone());
+        // and this doesn't fail either
+        Assert.assertEquals(t.get(), null);
+        // but it's not successful
+        Assert.assertNotNull(t.getException());
+        Assert.assertFalse(t.isSuccessful());
+        // exit code probably null, but won't be zero
+        Assert.assertNotEquals(t.getExitCode(), (Integer)0);
+    }
+
+    @Test(groups="Integration")
+    public void testCopyToFailBadSubdirCreate() throws IOException {
+        String fn = Urls.mergePaths(tempDir.getPath(), "non-existent-subdir-to-create/file");
+        SshPutTaskWrapper t = submit(SshTasks.newSshPutTaskFactory(host, fn).contents("hello world").createDirectory());
+        t.block();
+        // directory should be created, and file readable now
+        Assert.assertEquals(FileUtils.readFileToString(new File(fn)), "hello world");
+        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");
+        
+        SshFetchTaskFactory tf = SshTasks.newSshFetchTaskFactory(host, fn);
+        SshFetchTaskWrapper t = tf.newTask();
+        mgmt.getExecutionManager().submit(t);
+
+        t.block();
+        Assert.assertTrue(t.isDone());
+        Assert.assertEquals(t.get(), "hello fetched world");
+        Assert.assertEquals(t.getBytes(), "hello fetched world".getBytes());
+    }
+
+    @Test(groups="Integration")
+    public void testSshWithHeaderProperty() {
+        host.setConfig(BrooklynConfigKeys.SSH_CONFIG_SCRIPT_HEADER, "#!/bin/bash -e\necho foo\n");
+        ProcessTaskWrapper<Integer> t = submit(SshTasks.newSshExecTaskFactory(host, "echo bar"));
+        Assert.assertTrue(t.block().getStdout().trim().matches("foo\\s+bar"), "mismatched output was: "+t.getStdout());
+    }
+
+    @Test(groups="Integration")
+    public void testSshIgnoringHeaderProperty() {
+        host.setConfig(BrooklynConfigKeys.SSH_CONFIG_SCRIPT_HEADER, "#!/bin/bash -e\necho foo\n");
+        ProcessTaskWrapper<Integer> t = submit(SshTasks.newSshExecTaskFactory(host, false, "echo bar"));
+        Assert.assertTrue(t.block().getStdout().trim().matches("bar"), "mismatched output was: "+t.getStdout());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/task/system/SystemTasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/task/system/SystemTasksTest.java b/core/src/test/java/org/apache/brooklyn/core/util/task/system/SystemTasksTest.java
new file mode 100644
index 0000000..b673056
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/task/system/SystemTasksTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.util.task.system;
+
+import java.io.File;
+
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.core.util.task.system.SystemTasks;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.util.os.Os;
+
+/**
+ * Some tests for {@link SystemTasks}. See {@link SshTasks}.
+ */
+public class SystemTasksTest {
+
+    ManagementContext mgmt;
+    File tempDir;
+    
+    boolean failureExpected;
+
+    @BeforeMethod(alwaysRun=true)
+    public void setup() throws Exception {
+        mgmt = new LocalManagementContext();
+        
+        clearExpectedFailure();
+        tempDir = Os.newTempDir(getClass());
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (mgmt != null) Entities.destroyAll(mgmt);
+        mgmt = null;
+        tempDir = Os.deleteRecursively(tempDir).asNullOrThrowing();
+        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;
+    }
+
+
+    protected <T> ProcessTaskWrapper<T> submit(final ProcessTaskFactory<T> tf) {
+        ProcessTaskWrapper<T> t = tf.newTask();
+        mgmt.getExecutionManager().submit(t);
+        return t;
+    }
+
+    @Test(groups="Integration")
+    public void testExecEchoHello() {
+        ProcessTaskWrapper<Integer> t = submit(SystemTasks.exec("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");
+    }
+
+    // FIXME Behaviour of Bash shell changes from 3.x to 4.x so test is disabled
+    @Test(groups="Integration", enabled=false)
+    public void testSubshellExitScriptDoesNotExit() {
+        checkSubshellExitDoesNotExit(taskSubshellExit().runAsScript());
+    }
+
+    @Test(groups="Integration")
+    public void testSubshellExitCommandDoesNotExit() {
+        checkSubshellExitDoesNotExit(taskSubshellExit().runAsCommand());
+    }
+
+    public ProcessTaskFactory<Integer> taskSubshellExit() {
+        return SystemTasks.exec("echo hello", "( exit 1 )", "echo bye code $?");
+    }
+
+    public void checkSubshellExitDoesNotExit(ProcessTaskFactory<Integer> task) {
+        ProcessTaskWrapper<Integer> t = submit(task);
+        t.block();
+        Assert.assertEquals(t.get(), (Integer)0);
+        Assert.assertTrue(t.getStdout().contains("bye code 1"), "stdout is: "+t.getStdout());
+    }
+
+    @Test(groups="Integration")
+    public void testGroupExitScriptDoesNotExit() {
+        checkGroupExitDoesExit(taskGroupExit().runAsScript());
+    }
+
+    @Test(groups="Integration")
+    public void testGroupExitCommandDoesNotExit() {
+        checkGroupExitDoesExit(taskGroupExit().runAsCommand());
+    }
+
+    public ProcessTaskFactory<Integer> taskGroupExit() {
+        return SystemTasks.exec("echo hello", "{ exit 1 ; }", "echo bye code $?");
+    }
+
+    public void checkGroupExitDoesExit(ProcessTaskFactory<Integer> task) {
+        ProcessTaskWrapper<Integer> t = submit(task);
+        t.block();
+        Assert.assertEquals(t.get(), (Integer)1);
+        Assert.assertFalse(t.getStdout().contains("bye"), "stdout is: "+t.getStdout());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/text/DataUriSchemeParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/text/DataUriSchemeParserTest.java b/core/src/test/java/org/apache/brooklyn/core/util/text/DataUriSchemeParserTest.java
new file mode 100644
index 0000000..73794a3
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/text/DataUriSchemeParserTest.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.core.util.text;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import org.apache.brooklyn.core.util.text.DataUriSchemeParser;
+import org.bouncycastle.util.encoders.Base64;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class DataUriSchemeParserTest {
+
+    @Test
+    public void testSimple() {
+        Assert.assertEquals(new DataUriSchemeParser("data:,hello").parse().getDataAsString(), "hello");
+        Assert.assertEquals(DataUriSchemeParser.toString("data:,hello"), "hello");
+    }
+
+    @Test
+    public void testMimeType() throws UnsupportedEncodingException {
+        DataUriSchemeParser p = new DataUriSchemeParser("data:application/json,"+URLEncoder.encode("{ }", "US-ASCII")).parse();
+        Assert.assertEquals(p.getMimeType(), "application/json");
+        Assert.assertEquals(p.getData(), "{ }".getBytes());
+    }
+
+    @Test
+    public void testBase64() {
+        Assert.assertEquals(DataUriSchemeParser.toString(
+                "data:;base64,"+new String(Base64.encode("hello".getBytes()))), 
+            "hello");
+    }
+
+    // TODO test pictures, etc
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/text/TemplateProcessorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/text/TemplateProcessorTest.java b/core/src/test/java/org/apache/brooklyn/core/util/text/TemplateProcessorTest.java
new file mode 100644
index 0000000..05f4fde
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/text/TemplateProcessorTest.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.util.text;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.apache.brooklyn.test.entity.TestEntity;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.event.basic.DependentConfiguration;
+import brooklyn.test.FixedLocaleTest;
+
+import com.google.common.collect.ImmutableMap;
+
+public class TemplateProcessorTest extends BrooklynAppUnitTestSupport {
+    private FixedLocaleTest localeFix = new FixedLocaleTest();
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        super.setUp();
+        localeFix.setUp();
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        super.tearDown();
+        localeFix.tearDown();
+    }
+
+    @Test
+    public void testAdditionalArgs() {
+        String templateContents = "${mykey}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.of("mykey", "myval"));
+        assertEquals(result, "myval");
+    }
+    
+    @Test
+    public void testEntityConfig() {
+        TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+                .configure(TestEntity.CONF_NAME, "myval"));
+        String templateContents = "${config['"+TestEntity.CONF_NAME.getName()+"']}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, entity, ImmutableMap.<String,Object>of());
+        assertEquals(result, "myval");
+    }
+    
+    @Test
+    public void testEntityConfigNumber() {
+        TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+                .configure(TestEntity.CONF_OBJECT, 123456));
+        String templateContents = "${config['"+TestEntity.CONF_OBJECT.getName()+"']}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, entity, ImmutableMap.<String,Object>of());
+        assertEquals(result, "123,456");
+    }
+    
+    @Test
+    public void testEntityConfigNumberUnadorned() {
+        // ?c is needed to avoid commas (i always forget this!)
+        TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+                .configure(TestEntity.CONF_OBJECT, 123456));
+        String templateContents = "${config['"+TestEntity.CONF_OBJECT.getName()+"']?c}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, entity, ImmutableMap.<String,Object>of());
+        assertEquals(result, "123456");
+    }
+    
+    @Test
+    public void testGetSysProp() {
+        System.setProperty("testGetSysProp", "myval");
+        
+        String templateContents = "${javaSysProps['testGetSysProp']}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
+        assertEquals(result, "myval");
+    }
+    
+    @Test
+    public void testEntityGetterMethod() {
+        String templateContents = "${entity.id}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
+        assertEquals(result, app.getId());
+    }
+    
+    @Test
+    public void testManagementContextConfig() {
+        mgmt.getBrooklynProperties().put("globalmykey", "myval");
+        String templateContents = "${mgmt.globalmykey}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
+        assertEquals(result, "myval");
+    }
+    
+    @Test
+    public void testManagementContextDefaultValue() {
+        String templateContents = "${(missing)!\"defval\"}";
+        Object result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
+        assertEquals(result, "defval");
+    }
+    
+    @Test
+    public void testManagementContextDefaultValueInDotMissingValue() {
+        String templateContents = "${(mgmt.missing.more_missing)!\"defval\"}";
+        Object result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
+        assertEquals(result, "defval");
+    }
+    
+    @Test
+    public void testManagementContextConfigWithDot() {
+        mgmt.getBrooklynProperties().put("global.mykey", "myval");
+        String templateContents = "${mgmt['global.mykey']}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
+        assertEquals(result, "myval");
+    }
+    
+    @Test
+    public void testManagementContextErrors() {
+        try {
+            // NB: dot has special meaning so this should fail; must be accessed using bracket notation as above
+            mgmt.getBrooklynProperties().put("global.mykey", "myval");
+            String templateContents = "${mgmt.global.mykey}";
+            TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
+            Assert.fail("Should not have found value with intermediate dot");
+        } catch (Exception e) {
+            Assert.assertTrue(e.toString().contains("global"), "Should have mentioned missing key 'global' in error");
+        }
+    }
+    
+    @Test
+    public void testApplyTemplatedConfigWithAttributeWhenReady() {
+        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
+
+        TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
+                .configure(TestEntity.CONF_NAME, DependentConfiguration.attributeWhenReady(app, TestApplication.MY_ATTRIBUTE)));
+        
+        String templateContents = "${config['"+TestEntity.CONF_NAME.getName()+"']}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, entity, ImmutableMap.<String,Object>of());
+        assertEquals(result, "myval");
+    }
+    
+    @Test
+    public void testDotSeparatedKey() {
+        String templateContents = "${a.b}";
+        String result = TemplateProcessor.processTemplateContents(templateContents, (ManagementContextInternal)null, 
+            ImmutableMap.<String,Object>of("a.b", "myval"));
+        assertEquals(result, "myval");
+    }
+    
+    @Test
+    public void testDotSeparatedKeyCollisionFailure() {
+        String templateContents = "${aaa.bbb}";
+        try {
+            TemplateProcessor.processTemplateContents(templateContents, (ManagementContextInternal)null, 
+                ImmutableMap.<String,Object>of("aaa.bbb", "myval", "aaa", "blocker"));
+            Assert.fail("Should not have found value with intermediate dot where prefix is overridden");
+        } catch (Exception e) {
+            Assert.assertTrue(e.toString().contains("aaa"), "Should have mentioned missing key 'aaa' in error");
+        }
+    }
+
+}


[38/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/EntityTransientCopyInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EntityTransientCopyInternal.java b/core/src/main/java/brooklyn/entity/basic/EntityTransientCopyInternal.java
index 63b49b5..56e73d1 100644
--- a/core/src/main/java/brooklyn/entity/basic/EntityTransientCopyInternal.java
+++ b/core/src/main/java/brooklyn/entity/basic/EntityTransientCopyInternal.java
@@ -38,12 +38,12 @@ import org.apache.brooklyn.api.mementos.EntityMemento;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.management.internal.EntityManagementSupport;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.entity.basic.EntityInternal.FeedSupport;
 import brooklyn.entity.proxying.EntityProxyImpl;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Maybe;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/Lifecycle.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/Lifecycle.java b/core/src/main/java/brooklyn/entity/basic/Lifecycle.java
index 9bb0177..97e3ada 100644
--- a/core/src/main/java/brooklyn/entity/basic/Lifecycle.java
+++ b/core/src/main/java/brooklyn/entity/basic/Lifecycle.java
@@ -24,7 +24,6 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import brooklyn.config.render.RendererHints;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.text.StringFunctions;
 
 import com.google.common.base.CaseFormat;
@@ -33,6 +32,7 @@ import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
 
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 /**
  * An enumeration representing the status of an {@link org.apache.brooklyn.api.entity.Entity}.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/MethodEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/MethodEffector.java b/core/src/main/java/brooklyn/entity/basic/MethodEffector.java
index 121f70f..f5978b7 100644
--- a/core/src/main/java/brooklyn/entity/basic/MethodEffector.java
+++ b/core/src/main/java/brooklyn/entity/basic/MethodEffector.java
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ParameterType;
 import org.apache.brooklyn.core.management.internal.EffectorUtils;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.codehaus.groovy.runtime.MethodClosure;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,7 +36,6 @@ import org.slf4j.LoggerFactory;
 import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.util.GroovyJavaMethods;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
 
 import com.google.common.collect.Lists;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/Sanitizer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/Sanitizer.java b/core/src/main/java/brooklyn/entity/basic/Sanitizer.java
index 88ca756..7e81bb2 100644
--- a/core/src/main/java/brooklyn/entity/basic/Sanitizer.java
+++ b/core/src/main/java/brooklyn/entity/basic/Sanitizer.java
@@ -22,7 +22,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import brooklyn.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import com.google.api.client.util.Lists;
 import com.google.common.base.Predicate;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java b/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
index 2a551b4..bf4bd43 100644
--- a/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
+++ b/core/src/main/java/brooklyn/entity/basic/ServiceStateLogic.java
@@ -37,6 +37,7 @@ import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.EnricherSpec.ExtensibleEnricherSpec;
+import org.apache.brooklyn.core.util.task.ValueResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -57,7 +58,6 @@ import brooklyn.util.collections.QuorumCheck;
 import brooklyn.util.guava.Functionals;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.repeat.Repeater;
-import brooklyn.util.task.ValueResolver;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/effector/AddChildrenEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/effector/AddChildrenEffector.java b/core/src/main/java/brooklyn/entity/effector/AddChildrenEffector.java
index eef3cf9..0119dd1 100644
--- a/core/src/main/java/brooklyn/entity/effector/AddChildrenEffector.java
+++ b/core/src/main/java/brooklyn/entity/effector/AddChildrenEffector.java
@@ -25,13 +25,13 @@ import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.core.management.internal.EntityManagementUtils;
 import org.apache.brooklyn.core.management.internal.EntityManagementUtils.CreationResult;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.effector.Effectors.EffectorBuilder;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.annotations.Beta;
 import com.google.gson.Gson;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/effector/AddEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/effector/AddEffector.java b/core/src/main/java/brooklyn/entity/effector/AddEffector.java
index c0d986d..0db7c40 100644
--- a/core/src/main/java/brooklyn/entity/effector/AddEffector.java
+++ b/core/src/main/java/brooklyn/entity/effector/AddEffector.java
@@ -25,13 +25,13 @@ import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.ParameterType;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntityInitializer;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.effector.Effectors.EffectorBuilder;
 import brooklyn.event.basic.MapConfigKey;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.text.Strings;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/effector/AddSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/effector/AddSensor.java b/core/src/main/java/brooklyn/entity/effector/AddSensor.java
index 8e29baa..2aa95a6 100644
--- a/core/src/main/java/brooklyn/entity/effector/AddSensor.java
+++ b/core/src/main/java/brooklyn/entity/effector/AddSensor.java
@@ -23,12 +23,12 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntityInitializer;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.Boxing;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/effector/EffectorBody.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/effector/EffectorBody.java b/core/src/main/java/brooklyn/entity/effector/EffectorBody.java
index 98c8153..1a60cbe 100644
--- a/core/src/main/java/brooklyn/entity/effector/EffectorBody.java
+++ b/core/src/main/java/brooklyn/entity/effector/EffectorBody.java
@@ -21,14 +21,14 @@ package brooklyn.entity.effector;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.TaskAdaptable;
 import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.DynamicSequentialTask;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
 
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.EntityInternal;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.task.DynamicSequentialTask;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.annotations.Beta;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/effector/EffectorTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/effector/EffectorTasks.java b/core/src/main/java/brooklyn/entity/effector/EffectorTasks.java
index 6094686..f9a702e 100644
--- a/core/src/main/java/brooklyn/entity/effector/EffectorTasks.java
+++ b/core/src/main/java/brooklyn/entity/effector/EffectorTasks.java
@@ -28,6 +28,11 @@ import org.apache.brooklyn.api.entity.ParameterType;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.TaskAdaptable;
 import org.apache.brooklyn.core.management.internal.EffectorUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicSequentialTask;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,12 +44,7 @@ import org.apache.brooklyn.location.basic.Machines;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 import org.apache.brooklyn.location.basic.WinRmMachineLocation;
 
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.javalang.Reflections;
-import brooklyn.util.task.DynamicSequentialTask;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/effector/Effectors.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/effector/Effectors.java b/core/src/main/java/brooklyn/entity/effector/Effectors.java
index ff595e7..c0b6306 100644
--- a/core/src/main/java/brooklyn/entity/effector/Effectors.java
+++ b/core/src/main/java/brooklyn/entity/effector/Effectors.java
@@ -31,6 +31,8 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ParameterType;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,8 +45,6 @@ import brooklyn.entity.effector.EffectorTasks.EffectorBodyTaskFactory;
 import brooklyn.entity.effector.EffectorTasks.EffectorMarkingTaskFactory;
 import brooklyn.entity.effector.EffectorTasks.EffectorTaskFactory;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/group/Cluster.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/Cluster.java b/core/src/main/java/brooklyn/entity/group/Cluster.java
index b618c66..ac066a7 100644
--- a/core/src/main/java/brooklyn/entity/group/Cluster.java
+++ b/core/src/main/java/brooklyn/entity/group/Cluster.java
@@ -19,11 +19,11 @@
 package brooklyn.entity.group;
 
 import org.apache.brooklyn.api.entity.Group;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.entity.trait.Resizable;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * Intended to represent a group of homogeneous entities in a single location.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/DynamicCluster.java b/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
index ab14f49..435308e 100644
--- a/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
+++ b/core/src/main/java/brooklyn/entity/group/DynamicCluster.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.Effector;
@@ -46,7 +47,6 @@ import brooklyn.entity.trait.MemberReplaceable;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicNotificationSensor;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
index 5025026..1cdbd8e 100644
--- a/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
+++ b/core/src/main/java/brooklyn/entity/group/DynamicClusterImpl.java
@@ -38,6 +38,10 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskTags;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,13 +66,9 @@ import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.ReferenceWithError;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.javalang.Reflections;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskTags;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.StringPredicates;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/group/DynamicFabric.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/DynamicFabric.java b/core/src/main/java/brooklyn/entity/group/DynamicFabric.java
index f7decf9..dc23e7c 100644
--- a/core/src/main/java/brooklyn/entity/group/DynamicFabric.java
+++ b/core/src/main/java/brooklyn/entity/group/DynamicFabric.java
@@ -21,6 +21,7 @@ package brooklyn.entity.group;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.AbstractGroup;
@@ -31,7 +32,6 @@ import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.MapConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/group/DynamicMultiGroup.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/DynamicMultiGroup.java b/core/src/main/java/brooklyn/entity/group/DynamicMultiGroup.java
index 3a49634..d5a8c9a 100644
--- a/core/src/main/java/brooklyn/entity/group/DynamicMultiGroup.java
+++ b/core/src/main/java/brooklyn/entity/group/DynamicMultiGroup.java
@@ -25,13 +25,13 @@ import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BasicGroup;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.DynamicGroup;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/group/QuarantineGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/QuarantineGroupImpl.java b/core/src/main/java/brooklyn/entity/group/QuarantineGroupImpl.java
index 9f8c14e..4a6b75e 100644
--- a/core/src/main/java/brooklyn/entity/group/QuarantineGroupImpl.java
+++ b/core/src/main/java/brooklyn/entity/group/QuarantineGroupImpl.java
@@ -23,6 +23,8 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,8 +34,6 @@ import brooklyn.entity.basic.Entities;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.trait.Startable;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/proxying/EntityProxyImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/EntityProxyImpl.java b/core/src/main/java/brooklyn/entity/proxying/EntityProxyImpl.java
index 647ad76..b121179 100644
--- a/core/src/main/java/brooklyn/entity/proxying/EntityProxyImpl.java
+++ b/core/src/main/java/brooklyn/entity/proxying/EntityProxyImpl.java
@@ -36,6 +36,9 @@ import org.apache.brooklyn.api.management.TaskAdaptable;
 import org.apache.brooklyn.core.management.internal.EffectorUtils;
 import org.apache.brooklyn.core.management.internal.EntityManagerInternal;
 import org.apache.brooklyn.core.management.internal.ManagementTransitionMode;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskTags;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -45,9 +48,6 @@ import brooklyn.entity.basic.EntityTransientCopyInternal;
 import brooklyn.entity.basic.EntityTransientCopyInternal.SpecialEntityTransientCopyInternal;
 import brooklyn.entity.effector.EffectorWithBody;
 import brooklyn.entity.rebind.RebindManagerImpl.RebindTracker;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskTags;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
index c2a4bfd..1c1a920 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
@@ -37,6 +37,8 @@ import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -50,9 +52,7 @@ import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.javalang.AggregateClassLoader;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
index 10338b8..464d2a4 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalLocationFactory.java
@@ -27,15 +27,15 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.internal.LocalLocationManager;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
 
 import brooklyn.config.ConfigKey;
 
 import org.apache.brooklyn.location.basic.AbstractLocation;
 import org.apache.brooklyn.location.basic.LocationInternal;
 
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.FlagUtils;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
index aeb371c..7c53404 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
@@ -27,13 +27,13 @@ import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/BasicCatalogItemRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicCatalogItemRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicCatalogItemRebindSupport.java
index 52e87a6..6ee5eb2 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicCatalogItemRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicCatalogItemRebindSupport.java
@@ -21,11 +21,11 @@ package brooklyn.entity.rebind;
 import org.apache.brooklyn.api.entity.rebind.RebindContext;
 import org.apache.brooklyn.api.mementos.CatalogItemMemento;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemDtoAbstract;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.FlagUtils;
 
 public class BasicCatalogItemRebindSupport extends AbstractBrooklynObjectRebindSupport<CatalogItemMemento> {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
index d6b289f..e3e4598 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEnricherRebindSupport.java
@@ -20,10 +20,10 @@ package brooklyn.entity.rebind;
 
 import org.apache.brooklyn.api.entity.rebind.RebindContext;
 import org.apache.brooklyn.api.mementos.EnricherMemento;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
 
 import brooklyn.enricher.basic.AbstractEnricher;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.FlagUtils;
 
 public class BasicEnricherRebindSupport extends AbstractBrooklynObjectRebindSupport<EnricherMemento> {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/BasicFeedRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicFeedRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicFeedRebindSupport.java
index 5507e6b..f3358e2 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicFeedRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicFeedRebindSupport.java
@@ -20,10 +20,10 @@ package brooklyn.entity.rebind;
 
 import org.apache.brooklyn.api.entity.rebind.RebindContext;
 import org.apache.brooklyn.api.mementos.FeedMemento;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
 
 import brooklyn.event.feed.AbstractFeed;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.FlagUtils;
 
 public class BasicFeedRebindSupport extends AbstractBrooklynObjectRebindSupport<FeedMemento> {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
index edf8867..7f1f286 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicLocationRebindSupport.java
@@ -26,6 +26,8 @@ import java.util.NoSuchElementException;
 import org.apache.brooklyn.api.entity.rebind.RebindContext;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mementos.LocationMemento;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,8 +37,6 @@ import brooklyn.entity.rebind.dto.MementosGenerators;
 import org.apache.brooklyn.location.basic.AbstractLocation;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.TypeCoercions;
 
 import com.google.common.collect.Sets;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
index 9b22d65..4623225 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
@@ -20,10 +20,10 @@ package brooklyn.entity.rebind;
 
 import org.apache.brooklyn.api.entity.rebind.RebindContext;
 import org.apache.brooklyn.api.mementos.PolicyMemento;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
 
 import brooklyn.policy.basic.AbstractPolicy;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.FlagUtils;
 
 public class BasicPolicyRebindSupport extends AbstractBrooklynObjectRebindSupport<PolicyMemento> {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
index d204ecc..2c55e7f 100644
--- a/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
+++ b/core/src/main/java/brooklyn/entity/rebind/PeriodicDeltaChangeListener.java
@@ -46,6 +46,8 @@ import org.apache.brooklyn.api.mementos.BrooklynMementoPersister;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
+import org.apache.brooklyn.core.util.task.ScheduledTask;
+import org.apache.brooklyn.core.util.task.Tasks;
 
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.EntityInternal;
@@ -56,8 +58,6 @@ import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
 import brooklyn.util.repeat.Repeater;
-import brooklyn.util.task.ScheduledTask;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.CountdownTimer;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
index 1164fff..67d20ae 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
@@ -73,6 +73,7 @@ import org.apache.brooklyn.core.management.internal.EntityManagerInternal;
 import org.apache.brooklyn.core.management.internal.LocationManagerInternal;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.management.internal.ManagementTransitionMode;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
 
 import brooklyn.config.BrooklynLogging;
 import brooklyn.config.BrooklynLogging.LoggingLevel;
@@ -95,7 +96,6 @@ import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.Reflections;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
index 862c86b..f810a98 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindManagerImpl.java
@@ -46,6 +46,9 @@ import org.apache.brooklyn.api.mementos.TreeNode;
 import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.management.ha.HighAvailabilityManagerImpl;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.ScheduledTask;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -65,9 +68,6 @@ import brooklyn.util.collections.QuorumCheck;
 import brooklyn.util.collections.QuorumCheck.QuorumChecks;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
-import brooklyn.util.task.BasicExecutionContext;
-import brooklyn.util.task.ScheduledTask;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/dto/BasicLocationMemento.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/BasicLocationMemento.java b/core/src/main/java/brooklyn/entity/rebind/dto/BasicLocationMemento.java
index a0578bb..6fbf66a 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/BasicLocationMemento.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/BasicLocationMemento.java
@@ -24,10 +24,10 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.mementos.LocationMemento;
 import org.apache.brooklyn.api.mementos.TreeNode;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.Sanitizer;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.base.Objects.ToStringHelper;
 import com.google.common.collect.Maps;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java b/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
index dbe6e26..5c52788 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
@@ -50,6 +50,8 @@ import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EntityAdjunct;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemDo;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
@@ -64,8 +66,6 @@ import org.apache.brooklyn.location.basic.LocationInternal;
 
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.FlagUtils;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
index b5ca9c1..f146999 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynMementoPersisterToObjectStore.java
@@ -50,6 +50,7 @@ import org.apache.brooklyn.api.mementos.CatalogItemMemento;
 import org.apache.brooklyn.api.mementos.Memento;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.classloading.ClassLoaderFromBrooklynClassLoadingContext;
+import org.apache.brooklyn.core.util.xstream.XmlUtil;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.config.StringConfigMap;
@@ -66,7 +67,6 @@ import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
-import brooklyn.util.xstream.XmlUtil;
 
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java
index 68074e9..3db8106 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/BrooklynPersistenceUtils.java
@@ -45,6 +45,7 @@ import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.management.ha.ManagementPlaneSyncRecordPersisterToObjectStore;
 import org.apache.brooklyn.core.management.internal.LocalLocationManager;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.ResourceUtils;
 
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.config.BrooklynServerPaths;
@@ -56,7 +57,6 @@ import brooklyn.entity.rebind.transformer.CompoundTransformerLoader;
 
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java b/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java
index c1df659..764d55f 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/FileBasedObjectStore.java
@@ -36,6 +36,7 @@ import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
+import org.apache.brooklyn.core.util.internal.ssh.process.ProcessTool;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,7 +45,6 @@ import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.FatalConfigurationRuntimeException;
-import brooklyn.util.internal.ssh.process.ProcessTool;
 import brooklyn.util.io.FileUtil;
 import brooklyn.util.os.Os;
 import brooklyn.util.os.Os.DeletionResult;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/persister/XmlMementoSerializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/persister/XmlMementoSerializer.java b/core/src/main/java/brooklyn/entity/rebind/persister/XmlMementoSerializer.java
index 99ee2e5..6ff75e5 100644
--- a/core/src/main/java/brooklyn/entity/rebind/persister/XmlMementoSerializer.java
+++ b/core/src/main/java/brooklyn/entity/rebind/persister/XmlMementoSerializer.java
@@ -47,6 +47,7 @@ import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.classloading.BrooklynClassLoadingContextSequential;
 import org.apache.brooklyn.core.management.classloading.ClassLoaderFromBrooklynClassLoadingContext;
 import org.apache.brooklyn.core.management.classloading.JavaBrooklynClassLoadingContext;
+import org.apache.brooklyn.core.util.xstream.XmlSerializer;
 
 import brooklyn.entity.basic.BasicParameterType;
 import brooklyn.entity.effector.EffectorAndBody;
@@ -63,7 +64,6 @@ import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.text.Strings;
-import brooklyn.util.xstream.XmlSerializer;
 
 import com.thoughtworks.xstream.converters.Converter;
 import com.thoughtworks.xstream.converters.MarshallingContext;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformer.java b/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformer.java
index 33d9422..030cd53 100644
--- a/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformer.java
+++ b/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformer.java
@@ -26,13 +26,13 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.rebind.BrooklynObjectType;
 import org.apache.brooklyn.api.entity.rebind.RebindExceptionHandler;
 import org.apache.brooklyn.api.mementos.BrooklynMementoRawData;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 
 import brooklyn.entity.rebind.persister.BrooklynMementoPersisterToObjectStore;
 import brooklyn.entity.rebind.transformer.impl.XsltTransformer;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
 
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformerLoader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformerLoader.java b/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformerLoader.java
index 8a2d4bb..b36328c 100644
--- a/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformerLoader.java
+++ b/core/src/main/java/brooklyn/entity/rebind/transformer/CompoundTransformerLoader.java
@@ -22,13 +22,13 @@ import java.util.Collection;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.rebind.transformer.CompoundTransformer.Builder;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.text.TemplateProcessor;
 import brooklyn.util.yaml.Yamls;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/trait/Startable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/trait/Startable.java b/core/src/main/java/brooklyn/entity/trait/Startable.java
index 19c7f9d..dad2152 100644
--- a/core/src/main/java/brooklyn/entity/trait/Startable.java
+++ b/core/src/main/java/brooklyn/entity/trait/Startable.java
@@ -23,6 +23,8 @@ import java.util.Collection;
 import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,8 +35,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.MethodEffector;
 import brooklyn.entity.effector.EffectorBody;
 import brooklyn.entity.effector.Effectors;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.task.Tasks;
 
 /**
  * This interface describes an {@link org.apache.brooklyn.api.entity.Entity} that can be started and stopped.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/trait/StartableMethods.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/trait/StartableMethods.java b/core/src/main/java/brooklyn/entity/trait/StartableMethods.java
index 6188d14..0e14058 100644
--- a/core/src/main/java/brooklyn/entity/trait/StartableMethods.java
+++ b/core/src/main/java/brooklyn/entity/trait/StartableMethods.java
@@ -26,6 +26,9 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskTags;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,10 +36,7 @@ import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityPredicates;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.CompoundRuntimeException;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskTags;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/basic/AttributeMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/basic/AttributeMap.java b/core/src/main/java/brooklyn/event/basic/AttributeMap.java
index aa8dcc1..281adfd 100644
--- a/core/src/main/java/brooklyn/event/basic/AttributeMap.java
+++ b/core/src/main/java/brooklyn/event/basic/AttributeMap.java
@@ -26,12 +26,12 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.BrooklynLogging;
 import brooklyn.entity.basic.AbstractEntity;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/basic/AttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/basic/AttributeSensorAndConfigKey.java b/core/src/main/java/brooklyn/event/basic/AttributeSensorAndConfigKey.java
index fda8063..f9cec48 100644
--- a/core/src/main/java/brooklyn/event/basic/AttributeSensorAndConfigKey.java
+++ b/core/src/main/java/brooklyn/event/basic/AttributeSensorAndConfigKey.java
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,7 +34,6 @@ import brooklyn.entity.basic.BrooklynConfigKeys;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
 
 /**
 * A {@link Sensor} describing an attribute that can be configured with inputs that are used to derive the final value.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/basic/BasicConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/basic/BasicConfigKey.java b/core/src/main/java/brooklyn/event/basic/BasicConfigKey.java
index 1e41aad..f3b9204 100644
--- a/core/src/main/java/brooklyn/event/basic/BasicConfigKey.java
+++ b/core/src/main/java/brooklyn/event/basic/BasicConfigKey.java
@@ -28,6 +28,8 @@ import java.util.concurrent.ExecutionException;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.core.util.internal.ConfigKeySelfExtracting;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,8 +37,6 @@ import brooklyn.config.ConfigInheritance;
 import brooklyn.config.ConfigKey;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.TypeTokens;
-import brooklyn.util.internal.ConfigKeySelfExtracting;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java b/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
index 44d8688..4f990cf 100644
--- a/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
+++ b/core/src/main/java/brooklyn/event/basic/DependentConfiguration.java
@@ -44,6 +44,14 @@ import org.apache.brooklyn.api.management.SubscriptionHandle;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.TaskAdaptable;
 import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.apache.brooklyn.core.util.task.DeferredSupplier;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.ParallelTask;
+import org.apache.brooklyn.core.util.task.TaskInternal;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ValueResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -63,14 +71,6 @@ import brooklyn.util.exceptions.NotManagedException;
 import brooklyn.util.exceptions.RuntimeTimeoutException;
 import brooklyn.util.guava.Functionals;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.BasicExecutionContext;
-import brooklyn.util.task.BasicTask;
-import brooklyn.util.task.DeferredSupplier;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.ParallelTask;
-import brooklyn.util.task.TaskInternal;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ValueResolver;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.CountdownTimer;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/basic/PortAttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/basic/PortAttributeSensorAndConfigKey.java b/core/src/main/java/brooklyn/event/basic/PortAttributeSensorAndConfigKey.java
index fd7100a..ffd8229 100644
--- a/core/src/main/java/brooklyn/event/basic/PortAttributeSensorAndConfigKey.java
+++ b/core/src/main/java/brooklyn/event/basic/PortAttributeSensorAndConfigKey.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.location.PortRange;
 import org.apache.brooklyn.api.location.PortSupplier;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.internal.BrooklynInitialization;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,7 +38,6 @@ import brooklyn.entity.basic.BrooklynConfigKeys;
 
 import org.apache.brooklyn.location.basic.Locations;
 
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 
 import com.google.common.base.Optional;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/basic/TemplatedStringAttributeSensorAndConfigKey.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/basic/TemplatedStringAttributeSensorAndConfigKey.java b/core/src/main/java/brooklyn/event/basic/TemplatedStringAttributeSensorAndConfigKey.java
index 0a57b62..8537f49 100644
--- a/core/src/main/java/brooklyn/event/basic/TemplatedStringAttributeSensorAndConfigKey.java
+++ b/core/src/main/java/brooklyn/event/basic/TemplatedStringAttributeSensorAndConfigKey.java
@@ -21,12 +21,12 @@ package brooklyn.event.basic;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.EntityInternal;
-import brooklyn.util.text.TemplateProcessor;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/feed/AttributePollHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/AttributePollHandler.java b/core/src/main/java/brooklyn/event/feed/AttributePollHandler.java
index fbfe65c..ff4ef6e 100644
--- a/core/src/main/java/brooklyn/event/feed/AttributePollHandler.java
+++ b/core/src/main/java/brooklyn/event/feed/AttributePollHandler.java
@@ -22,6 +22,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,8 +34,6 @@ import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.basic.Lifecycle.Transition;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/feed/Poller.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/Poller.java b/core/src/main/java/brooklyn/event/feed/Poller.java
index 1bd97cd..2f14f22 100644
--- a/core/src/main/java/brooklyn/event/feed/Poller.java
+++ b/core/src/main/java/brooklyn/event/feed/Poller.java
@@ -24,6 +24,9 @@ import java.util.concurrent.Callable;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.DynamicSequentialTask;
+import org.apache.brooklyn.core.util.task.ScheduledTask;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,9 +35,6 @@ import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.task.DynamicSequentialTask;
-import brooklyn.util.task.ScheduledTask;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/feed/http/HttpFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/http/HttpFeed.java b/core/src/main/java/brooklyn/event/feed/http/HttpFeed.java
index 342e430..39f008a 100644
--- a/core/src/main/java/brooklyn/event/feed/http/HttpFeed.java
+++ b/core/src/main/java/brooklyn/event/feed/http/HttpFeed.java
@@ -29,6 +29,9 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
+import org.apache.brooklyn.core.util.http.HttpTool.HttpClientBuilder;
 import org.apache.http.auth.Credentials;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.apache.http.client.HttpClient;
@@ -42,9 +45,6 @@ import brooklyn.event.feed.AbstractFeed;
 import brooklyn.event.feed.AttributePollHandler;
 import brooklyn.event.feed.DelegatingPollHandler;
 import brooklyn.event.feed.Poller;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpTool.HttpClientBuilder;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/feed/http/HttpPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/http/HttpPollConfig.java b/core/src/main/java/brooklyn/event/feed/http/HttpPollConfig.java
index 923995f..b27fede 100644
--- a/core/src/main/java/brooklyn/event/feed/http/HttpPollConfig.java
+++ b/core/src/main/java/brooklyn/event/feed/http/HttpPollConfig.java
@@ -24,12 +24,12 @@ import java.util.Map;
 import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 
 import brooklyn.event.feed.PollConfig;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Predicate;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/feed/http/HttpPollValue.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/http/HttpPollValue.java b/core/src/main/java/brooklyn/event/feed/http/HttpPollValue.java
index 81fe325..1df1f9a 100644
--- a/core/src/main/java/brooklyn/event/feed/http/HttpPollValue.java
+++ b/core/src/main/java/brooklyn/event/feed/http/HttpPollValue.java
@@ -21,7 +21,7 @@ package brooklyn.event.feed.http;
 import java.util.List;
 import java.util.Map;
 
-import brooklyn.util.http.HttpToolResponse;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 
 /** @deprecated since 0.7.0, use {@link HttpToolResponse}.
  * the old {@link HttpPollValue} concrete class has been renamed {@link HttpToolResponse}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/feed/http/HttpPolls.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/http/HttpPolls.java b/core/src/main/java/brooklyn/event/feed/http/HttpPolls.java
index 2e53618..94391ce 100644
--- a/core/src/main/java/brooklyn/event/feed/http/HttpPolls.java
+++ b/core/src/main/java/brooklyn/event/feed/http/HttpPolls.java
@@ -20,11 +20,10 @@ package brooklyn.event.feed.http;
 
 import java.net.URI;
 
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.http.impl.client.DefaultHttpClient;
 
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
-
 import com.google.common.collect.ImmutableMap;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/feed/http/HttpValueFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/http/HttpValueFunctions.java b/core/src/main/java/brooklyn/event/feed/http/HttpValueFunctions.java
index 3e7e6b2..f6ab2b5 100644
--- a/core/src/main/java/brooklyn/event/feed/http/HttpValueFunctions.java
+++ b/core/src/main/java/brooklyn/event/feed/http/HttpValueFunctions.java
@@ -20,8 +20,9 @@ package brooklyn.event.feed.http;
 
 import java.util.List;
 
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
+
 import brooklyn.util.guava.Functionals;
-import brooklyn.util.http.HttpToolResponse;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/feed/shell/ShellFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/shell/ShellFeed.java b/core/src/main/java/brooklyn/event/feed/shell/ShellFeed.java
index 7362666..5c82be7 100644
--- a/core/src/main/java/brooklyn/event/feed/shell/ShellFeed.java
+++ b/core/src/main/java/brooklyn/event/feed/shell/ShellFeed.java
@@ -29,6 +29,9 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.core.util.task.system.internal.SystemProcessTaskFactory.ConcreteSystemProcessTaskFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,9 +45,6 @@ import brooklyn.event.feed.Poller;
 import brooklyn.event.feed.function.FunctionFeed;
 import brooklyn.event.feed.ssh.SshFeed;
 import brooklyn.event.feed.ssh.SshPollValue;
-import brooklyn.util.task.system.ProcessTaskFactory;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-import brooklyn.util.task.system.internal.SystemProcessTaskFactory.ConcreteSystemProcessTaskFactory;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Optional;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/feed/ssh/SshFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/ssh/SshFeed.java b/core/src/main/java/brooklyn/event/feed/ssh/SshFeed.java
index 200e2fb..46c751b 100644
--- a/core/src/main/java/brooklyn/event/feed/ssh/SshFeed.java
+++ b/core/src/main/java/brooklyn/event/feed/ssh/SshFeed.java
@@ -30,6 +30,8 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,11 +41,11 @@ import brooklyn.event.feed.AbstractFeed;
 import brooklyn.event.feed.AttributePollHandler;
 import brooklyn.event.feed.DelegatingPollHandler;
 import brooklyn.event.feed.Poller;
+
 import org.apache.brooklyn.location.basic.Locations;
 import org.apache.brooklyn.location.basic.Machines;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.internal.ssh.SshTool;
+
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterFeed.java b/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterFeed.java
index 040d887..c06c013 100644
--- a/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterFeed.java
+++ b/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterFeed.java
@@ -38,6 +38,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,9 +50,10 @@ import brooklyn.event.basic.Sensors;
 import brooklyn.event.feed.AbstractFeed;
 import brooklyn.event.feed.PollHandler;
 import brooklyn.event.feed.Poller;
+
 import org.apache.brooklyn.location.basic.WinRmMachineLocation;
+
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.VisibleForTesting;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
index ab303a0..afa015f 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@ -41,6 +41,10 @@ import org.apache.brooklyn.api.management.SubscriptionHandle;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.policy.EntityAdjunct;
 import org.apache.brooklyn.core.management.internal.SubscriptionTracker;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,10 +57,6 @@ import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/policy/basic/ConfigMapImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/ConfigMapImpl.java b/core/src/main/java/brooklyn/policy/basic/ConfigMapImpl.java
index 825720a..467eb05 100644
--- a/core/src/main/java/brooklyn/policy/basic/ConfigMapImpl.java
+++ b/core/src/main/java/brooklyn/policy/basic/ConfigMapImpl.java
@@ -25,6 +25,8 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.internal.ConfigKeySelfExtracting;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -38,9 +40,7 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.Sanitizer;
 import brooklyn.event.basic.StructuredConfigKey;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.internal.ConfigKeySelfExtracting;
 
 public class ConfigMapImpl extends AbstractConfigMapImpl {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/BrooklynLanguageExtensions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/BrooklynLanguageExtensions.java b/core/src/main/java/brooklyn/util/BrooklynLanguageExtensions.java
deleted file mode 100644
index 86aac7e..0000000
--- a/core/src/main/java/brooklyn/util/BrooklynLanguageExtensions.java
+++ /dev/null
@@ -1,48 +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 brooklyn.util;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.brooklyn.core.internal.BrooklynInitialization;
-
-import brooklyn.util.internal.TimeExtras;
-
-/** @deprecated since 0.7.0 use {@link BrooklynInitialization} */
-public class BrooklynLanguageExtensions {
-
-    private BrooklynLanguageExtensions() {}
-    
-    private static AtomicBoolean done = new AtomicBoolean(false);
-    
-    public synchronized static void reinit() {
-        done.set(false);
-        init();
-    }
-    
-    /** performs the language extensions required for this project */
-    public synchronized static void init() {
-        if (done.getAndSet(true)) return;
-        TimeExtras.init();
-        BrooklynInitialization.initPortRanges();
-    }
-    
-    static { BrooklynInitialization.initLegacyLanguageExtensions(); }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/BrooklynMavenArtifacts.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/BrooklynMavenArtifacts.java b/core/src/main/java/brooklyn/util/BrooklynMavenArtifacts.java
deleted file mode 100644
index 50a5879..0000000
--- a/core/src/main/java/brooklyn/util/BrooklynMavenArtifacts.java
+++ /dev/null
@@ -1,58 +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 brooklyn.util;
-
-import brooklyn.BrooklynVersion;
-import brooklyn.util.maven.MavenArtifact;
-import brooklyn.util.maven.MavenRetriever;
-import brooklyn.util.text.Strings;
-
-public class BrooklynMavenArtifacts {
-
-    public static MavenArtifact jar(String artifactId) {
-        return artifact(null, artifactId, "jar");
-    }
-    
-    public static MavenArtifact artifact(String subgroupUnderIoBrooklyn, String artifactId, String packaging) {
-        return artifact(subgroupUnderIoBrooklyn, artifactId, packaging, null);
-    }
-
-    public static MavenArtifact artifact(String subgroupUnderIoBrooklyn, String artifactId, String packaging, String classifier) {
-        return new MavenArtifact(
-                Strings.isEmpty(subgroupUnderIoBrooklyn) ? "org.apache.brooklyn" : "org.apache.brooklyn."+subgroupUnderIoBrooklyn,
-                artifactId, packaging, classifier, BrooklynVersion.get());
-    }
-
-    public static String localUrlForJar(String artifactId) {
-        return MavenRetriever.localUrl(jar(artifactId));
-    }
-    
-    public static String localUrl(String subgroupUnderIoBrooklyn, String artifactId, String packaging) {
-        return MavenRetriever.localUrl(artifact(subgroupUnderIoBrooklyn, artifactId, packaging));
-    }
-
-    public static String hostedUrlForJar(String artifactId) {
-        return MavenRetriever.hostedUrl(jar(artifactId));
-    }
-    
-    public static String hostedUrl(String subgroupUnderIoBrooklyn, String artifactId, String packaging) {
-        return MavenRetriever.hostedUrl(artifact(subgroupUnderIoBrooklyn, artifactId, packaging));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/BrooklynNetworkUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/BrooklynNetworkUtils.java b/core/src/main/java/brooklyn/util/BrooklynNetworkUtils.java
deleted file mode 100644
index 0c1d39d..0000000
--- a/core/src/main/java/brooklyn/util/BrooklynNetworkUtils.java
+++ /dev/null
@@ -1,41 +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 brooklyn.util;
-
-import java.net.InetAddress;
-
-import brooklyn.config.BrooklynServiceAttributes;
-import org.apache.brooklyn.location.geo.LocalhostExternalIpLoader;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.net.Networking;
-
-public class BrooklynNetworkUtils {
-
-    /** returns the externally-facing IP address from which this host comes, or 127.0.0.1 if not resolvable */
-    public static String getLocalhostExternalIp() {
-        return LocalhostExternalIpLoader.getLocalhostIpQuicklyOrDefault();
-    }
-
-    /** returns a IP address for localhost paying attention to a system property to prevent lookup in some cases */ 
-    public static InetAddress getLocalhostInetAddress() {
-        return TypeCoercions.coerce(JavaGroovyEquivalents.elvis(BrooklynServiceAttributes.LOCALHOST_IP_ADDRESS.getValue(), 
-                Networking.getLocalHost()), InetAddress.class);
-    }
-
-}


[48/64] incubator-brooklyn git commit: brooklyn-software-messaging: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDriver.java
new file mode 100644
index 0000000..99a7b86
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDriver.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.entity.messaging.activemq;
+
+import brooklyn.entity.java.JavaSoftwareProcessDriver;
+
+public interface ActiveMQDriver extends JavaSoftwareProcessDriver {
+
+    String getBrokerName();
+
+    Integer getOpenWirePort();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQQueue.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQQueue.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQQueue.java
new file mode 100644
index 0000000..e8c8a15
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQQueue.java
@@ -0,0 +1,27 @@
+/*
+ * 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.entity.messaging.activemq;
+
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+
+import org.apache.brooklyn.entity.messaging.Queue;
+
+@ImplementedBy(ActiveMQQueueImpl.class)
+public interface ActiveMQQueue extends ActiveMQDestination, Queue {
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..63d5c1c
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQQueueImpl.java
@@ -0,0 +1,69 @@
+/*
+ * 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.entity.messaging.activemq;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.event.feed.jmx.JmxAttributePollConfig;
+import brooklyn.event.feed.jmx.JmxFeed;
+
+public class ActiveMQQueueImpl extends ActiveMQDestinationImpl implements ActiveMQQueue {
+    public static final Logger log = LoggerFactory.getLogger(ActiveMQQueue.class);
+
+    public ActiveMQQueueImpl() {
+    }
+
+    @Override
+    public void onManagementStarting() {
+        super.onManagementStarting();
+        setAttribute(QUEUE_NAME, getName());
+    }
+
+    public String getQueueName() {
+        return getName();
+    }
+    
+    public void create() {
+        log.debug("{} adding queue {} to broker {}", new Object[] {this, getName(), jmxHelper.getAttribute(brokerMBeanName, "BrokerName")});
+        
+        jmxHelper.operation(brokerMBeanName, "addQueue", getName());
+        
+        connectSensors();
+    }
+
+    public void delete() {
+        jmxHelper.operation(brokerMBeanName, "removeQueue", getName());
+        disconnectSensors();
+    }
+
+    @Override
+    protected void connectSensors() {
+        String queue = String.format("org.apache.activemq:type=Broker,brokerName=%s,destinationType=Queue,destinationName=%s", getBrokerName(), getName());
+        
+        jmxFeed = JmxFeed.builder()
+                .entity(this)
+                .helper(jmxHelper)
+                .pollAttribute(new JmxAttributePollConfig<Integer>(QUEUE_DEPTH_MESSAGES)
+                        .objectName(queue)
+                        .attributeName("QueueSize"))
+                .build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQSpecs.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQSpecs.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQSpecs.java
new file mode 100644
index 0000000..813cba0
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQSpecs.java
@@ -0,0 +1,33 @@
+/*
+ * 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.entity.messaging.activemq;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+
+public class ActiveMQSpecs {
+
+    public static EntitySpec<ActiveMQBroker> brokerSpec() {
+        return EntitySpec.create(ActiveMQBroker.class);
+    }
+    
+    public static EntitySpec<ActiveMQBroker> brokerSpecChef() {
+        return EntitySpec.create(ActiveMQBroker.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQSshDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQSshDriver.java
new file mode 100644
index 0000000..77602e4
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQSshDriver.java
@@ -0,0 +1,145 @@
+/*
+ * 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.entity.messaging.activemq;
+
+import static java.lang.String.format;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Networking;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+
+import com.google.common.collect.ImmutableMap;
+
+public class ActiveMQSshDriver extends JavaSoftwareProcessSshDriver implements ActiveMQDriver {
+
+    public ActiveMQSshDriver(ActiveMQBrokerImpl entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    @Override
+    protected String getLogFileLocation() { 
+        return Os.mergePathsUnix(getRunDir(), "data/activemq.log");
+    }
+
+    @Override
+    public String getBrokerName() { 
+        return entity.getAttribute(ActiveMQBroker.BROKER_NAME);
+    }
+
+    @Override
+    public Integer getOpenWirePort() { 
+        return entity.getAttribute(ActiveMQBroker.OPEN_WIRE_PORT);
+    }
+
+    public String getMirrorUrl() {
+        return entity.getConfig(ActiveMQBroker.MIRROR_URL);
+    }
+
+    protected String getTemplateConfigurationUrl() {
+        return entity.getAttribute(ActiveMQBroker.TEMPLATE_CONFIGURATION_URL);
+    }
+
+    public String getPidFile() {
+        return "data/activemq.pid";
+    }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this);
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("apache-activemq-%s", getVersion()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+
+        List<String> commands = new LinkedList<String>();
+        commands.addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs));
+        commands.add(BashCommands.INSTALL_TAR);
+        commands.add("tar xzfv "+saveAs);
+
+        newScript(INSTALLING)
+                .body.append(commands)
+                .execute();
+    }
+
+    @Override
+    public void customize() {
+        Networking.checkPortsValid(ImmutableMap.of("jmxPort", getJmxPort(), "openWirePort", getOpenWirePort()));
+        newScript(CUSTOMIZING)
+                .body.append(
+                        format("cp -R %s/{bin,conf,data,lib,webapps} .", getExpandedInstallDir()),
+                        // Required in version 5.5.1 (at least), but not in version 5.7.0
+                        "sed -i.bk 's/\\[-z \"$JAVA_HOME\"]/\\[ -z \"$JAVA_HOME\" ]/g' bin/activemq",
+                        // Stop it writing to dev null on start
+                        "sed -i.bk \"s/\\(ACTIVEMQ_HOME..bin.run.jar.*\\)>.dev.null/\\1/\" bin/activemq",
+                        // Required if launching multiple AMQ's, prevent jetty port conflicts
+                        "sed -i.bk 's/8161/"+getEntity().getAttribute(ActiveMQBroker.AMQ_JETTY_PORT)+"/g' conf/jetty.xml"
+                        // TODO disable persistence (this should be a flag -- but it seems to have no effect, despite ):
+                        // "sed -i.bk 's/broker /broker persistent=\"false\" /g' conf/activemq.xml",
+                    )
+                .execute();
+
+        // Copy the configuration file across
+        String destinationConfigFile = Os.mergePathsUnix(getRunDir(), "conf/activemq.xml");
+        copyTemplate(getTemplateConfigurationUrl(), destinationConfigFile);
+    }
+
+    @Override
+    public void launch() {
+        // Using nohup, as recommended at http://activemq.apache.org/run-broker.html
+        newScript(ImmutableMap.of(USE_PID_FILE, false), LAUNCHING)
+                .body.append("nohup ./bin/activemq start > ./data/activemq-extra.log 2>&1 &")
+                .execute();
+    }
+    
+    @Override
+    public boolean isRunning() {
+        return newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), CHECK_RUNNING).execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), STOPPING).execute();
+    }
+
+    @Override
+    public void kill() {
+        newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), KILLING).execute();
+    }
+
+    @Override
+    public Map<String, String> getShellEnvironment() {
+        return MutableMap.<String,String>builder()
+                .putAll(super.getShellEnvironment())
+                .put("ACTIVEMQ_HOME", getRunDir())
+                .put("ACTIVEMQ_PIDFILE", getPidFile())
+                .renameKey("JAVA_OPTS", "ACTIVEMQ_OPTS")
+                .build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQTopic.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQTopic.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQTopic.java
new file mode 100644
index 0000000..536ce09
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQTopic.java
@@ -0,0 +1,27 @@
+/*
+ * 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.entity.messaging.activemq;
+
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+
+import org.apache.brooklyn.entity.messaging.Topic;
+
+@ImplementedBy(ActiveMQTopicImpl.class)
+public interface ActiveMQTopic extends ActiveMQDestination, Topic {
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQTopicImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQTopicImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQTopicImpl.java
new file mode 100644
index 0000000..1724b1f
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQTopicImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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.entity.messaging.activemq;
+
+
+public class ActiveMQTopicImpl extends ActiveMQDestinationImpl implements ActiveMQTopic {
+    public ActiveMQTopicImpl() {
+    }
+
+    @Override
+    public void onManagementStarting() {
+        super.onManagementStarting();
+        setAttribute(TOPIC_NAME, getName());
+    }
+
+    @Override
+    public void create() {
+        jmxHelper.operation(brokerMBeanName, "addTopic", getName());
+        connectSensors();
+    }
+
+    public void delete() {
+        jmxHelper.operation(brokerMBeanName, "removeTopic", getName());
+        disconnectSensors();
+    }
+
+    public void connectSensors() {
+        //TODO add sensors for topics
+    }
+
+    public String getTopicName() {
+        return getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..f04c116
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpExchange.java
@@ -0,0 +1,45 @@
+/*
+ * 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.entity.messaging.amqp;
+
+import org.apache.brooklyn.api.event.Sensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+
+/**
+ * An interface that describes an AMQP exchange.
+ */
+public interface AmqpExchange {
+
+    /* AMQP standard exchange names. */
+    
+    String DIRECT = "amq.direct";
+    String TOPIC = "amq.topic";
+
+    /** The AMQP exchange name {@link Sensor}. */
+    @SetFromFlag("exchange")
+    BasicAttributeSensorAndConfigKey<String> EXCHANGE_NAME = new BasicAttributeSensorAndConfigKey<String>(
+            String.class, "amqp.exchange.name", "AMQP exchange name");
+
+    /**
+     * Return the AMQP exchange name.
+     */
+    public String getExchangeName();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..97cce88
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/amqp/AmqpServer.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.entity.messaging.amqp;
+
+import org.apache.brooklyn.api.entity.Entity;
+
+import brooklyn.entity.basic.Attributes;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+
+/**
+ * Marker interface identifying AMQP servers.
+ */
+public interface AmqpServer extends Entity {
+    
+    /* AMQP protocol version strings. */
+
+    String AMQP_0_8 = "0-8";
+    String AMQP_0_9 = "0-9";
+    String AMQP_0_9_1 = "0-9-1";
+    String AMQP_0_10 = "0-10";
+    String AMQP_1_0 = "1-0";
+
+    PortAttributeSensorAndConfigKey AMQP_PORT = Attributes.AMQP_PORT;
+
+    BasicAttributeSensorAndConfigKey<String> VIRTUAL_HOST_NAME = new BasicAttributeSensorAndConfigKey<String>(
+            String.class, "amqp.virtualHost", "AMQP virtual host name", "localhost");
+
+    BasicAttributeSensorAndConfigKey<String> AMQP_VERSION = new BasicAttributeSensorAndConfigKey<String>(
+            String.class, "amqp.version", "AMQP protocol version");
+
+    String getVirtualHost();
+
+    String getAmqpVersion();
+
+    Integer getAmqpPort();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSBroker.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSBroker.java
new file mode 100644
index 0000000..a83d259
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSBroker.java
@@ -0,0 +1,58 @@
+/*
+ * 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.entity.messaging.jms;
+
+import java.util.Collection;
+import java.util.Map;
+
+import brooklyn.entity.basic.SoftwareProcess;
+import org.apache.brooklyn.entity.messaging.MessageBroker;
+import org.apache.brooklyn.entity.messaging.Queue;
+import org.apache.brooklyn.entity.messaging.Topic;
+
+import com.google.common.annotations.VisibleForTesting;
+
+public interface JMSBroker<Q extends JMSDestination & Queue, T extends JMSDestination & Topic> extends SoftwareProcess, MessageBroker {
+    
+    @VisibleForTesting
+    public Collection<String> getQueueNames();
+    
+    @VisibleForTesting
+    public Collection<String> getTopicNames();
+
+    @VisibleForTesting
+    public Map<String, Q> getQueues();
+    
+    @VisibleForTesting
+    public Map<String, T> getTopics();
+    
+    /** TODO make this an effector */
+    public void addQueue(String name);
+    
+    public void addQueue(String name, Map properties);
+
+    public Q createQueue(Map properties);
+
+    /** TODO make this an effector */
+    public void addTopic(String name);
+    
+    public void addTopic(String name, Map properties);
+
+    public T createTopic(Map properties);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSBrokerImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSBrokerImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSBrokerImpl.java
new file mode 100644
index 0000000..6fa16a0
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSBrokerImpl.java
@@ -0,0 +1,168 @@
+/*
+ * 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.entity.messaging.jms;
+
+import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.Lifecycle;
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import org.apache.brooklyn.entity.messaging.Queue;
+import org.apache.brooklyn.entity.messaging.Topic;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
+public abstract class JMSBrokerImpl<Q extends JMSDestination & Queue, T extends JMSDestination & Topic> extends SoftwareProcessImpl implements JMSBroker<Q,T> {
+    private static final Logger log = LoggerFactory.getLogger(JMSBroker.class);
+    
+    Collection<String> queueNames;
+    Collection<String> topicNames;
+    Map<String, Q> queues = Maps.newLinkedHashMap();
+    Map<String, T> topics = Maps.newLinkedHashMap();
+
+    public JMSBrokerImpl() {
+    }
+
+    @Override
+    public JMSBrokerImpl configure(Map properties) {
+        if (queueNames==null) queueNames = Lists.newArrayList();
+        if (groovyTruth(properties.get("queue"))) queueNames.add((String) properties.remove("queue"));
+        if (groovyTruth(properties.get("queues"))) queueNames.addAll((Collection<String>) properties.remove("queues"));
+
+        if (topicNames==null) topicNames = Lists.newArrayList();
+        if (groovyTruth(properties.get("topic"))) topicNames.add((String) properties.remove("topic"));
+        if (groovyTruth(properties.get("topics"))) topicNames.addAll((Collection<String>) properties.remove("topics"));
+        
+        return (JMSBrokerImpl) super.configure(properties);
+    }
+
+    @Override
+    public Collection<String> getQueueNames() {
+        return queueNames;
+    }
+    
+    @Override
+    public Collection<String> getTopicNames() {
+        return topicNames;
+    }
+
+    @Override
+    public Map<String, Q> getQueues() {
+        return queues;
+    }
+    
+    @Override
+    public Map<String, T> getTopics() {
+        return topics;
+    }
+    
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+        setBrokerUrl();
+    }
+
+    // should be called after sensor-polling is activated etc
+    @Override
+    protected void postStart() {
+        super.postStart();
+        // stupid to do this here, but there appears to be a race where sometimes the
+        // broker throws a BrokerStopped exception, even though the sensor indicates it is up
+        Time.sleep(Duration.FIVE_SECONDS);
+        for (String name : queueNames) {
+            addQueue(name);
+        }
+        for (String name : topicNames) {
+            addTopic(name);
+        }
+    }
+    
+    @Override
+    public abstract void setBrokerUrl();
+
+    @Override
+    public void preStop() {
+        // If can't delete queues, continue trying to stop.
+        // (e.g. in CI have seen activemq "BrokerStoppedException" thrown in queue.destroy()). 
+        try {
+            for (JMSDestination queue : queues.values()) {
+                queue.destroy();
+            }
+        } catch (Exception e) {
+            log.warn("Error deleting queues from broker "+this+"; continuing with stop...", e);
+        }
+        
+        try {
+            for (JMSDestination topic : topics.values()) {
+                topic.destroy();
+            }
+        } catch (Exception e) {
+            log.warn("Error deleting topics from broker "+this+"; continuing with stop...", e);
+        }
+        
+        super.preStop();
+    }
+    
+    @Override
+    public void addQueue(String name) {
+        addQueue(name, MutableMap.of());
+    }
+    
+    public void checkStartingOrRunning() {
+        Lifecycle state = getAttribute(SERVICE_STATE_ACTUAL);
+        if (getAttribute(SERVICE_STATE_ACTUAL) == Lifecycle.RUNNING) return;
+        if (getAttribute(SERVICE_STATE_ACTUAL) == Lifecycle.STARTING) return;
+        // TODO this check may be redundant or even inappropriate
+        throw new IllegalStateException("Cannot run against "+this+" in state "+state);
+    }
+
+    @Override
+    public void addQueue(String name, Map properties) {
+        checkStartingOrRunning();
+        properties.put("name", name);
+        queues.put(name, createQueue(properties));
+    }
+
+    @Override
+    public abstract Q createQueue(Map properties);
+
+    @Override
+    public void addTopic(String name) {
+        addTopic(name, MutableMap.of());
+    }
+    
+    @Override
+    public void addTopic(String name, Map properties) {
+        checkStartingOrRunning();
+        properties.put("name", name);
+        topics.put(name, createTopic(properties));
+    }
+
+    @Override
+    public abstract T createTopic(Map properties);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSDestination.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSDestination.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSDestination.java
new file mode 100644
index 0000000..5591d66
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSDestination.java
@@ -0,0 +1,29 @@
+/*
+ * 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.entity.messaging.jms;
+
+import org.apache.brooklyn.api.entity.Entity;
+
+public interface JMSDestination extends Entity {
+    public String getName();
+    
+    public void delete();
+
+    public void destroy();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSDestinationImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSDestinationImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSDestinationImpl.java
new file mode 100644
index 0000000..dbd100f
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/jms/JMSDestinationImpl.java
@@ -0,0 +1,51 @@
+/*
+ * 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.entity.messaging.jms;
+
+import brooklyn.entity.basic.AbstractEntity;
+
+import com.google.common.base.Preconditions;
+
+public abstract class JMSDestinationImpl extends AbstractEntity implements JMSDestination {
+    public JMSDestinationImpl() {
+    }
+
+    @Override
+    public void onManagementStarting() {
+        super.onManagementStarting();
+        Preconditions.checkNotNull(getName(), "Name must be specified");
+    }
+
+    @Override
+    public String getName() {
+        return getDisplayName();
+    }
+    
+    protected abstract void connectSensors();
+
+    protected abstract void disconnectSensors();
+
+    public abstract void delete();
+
+    public void destroy() {
+        disconnectSensors();
+        delete();
+        super.destroy();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/AbstractfKafkaSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/AbstractfKafkaSshDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/AbstractfKafkaSshDriver.java
new file mode 100644
index 0000000..d101343
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/AbstractfKafkaSshDriver.java
@@ -0,0 +1,133 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import static java.lang.String.format;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Networking;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+
+public abstract class AbstractfKafkaSshDriver extends JavaSoftwareProcessSshDriver {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(KafkaZooKeeperSshDriver.class);
+
+    public AbstractfKafkaSshDriver(EntityLocal entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    protected abstract Map<String, Integer> getPortMap();
+
+    protected abstract ConfigKey<String> getConfigTemplateKey();
+
+    protected abstract String getConfigFileName();
+
+    protected abstract String getLaunchScriptName();
+
+    protected abstract String getTopicsScriptName();
+
+    protected abstract String getProcessIdentifier();
+
+    @Override
+    protected String getLogFileLocation() { return Os.mergePaths(getRunDir(), "console.out"); }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this);
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("kafka_%s", getVersion()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+
+        List<String> commands = new LinkedList<String>();
+        commands.addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs));
+        commands.add(BashCommands.INSTALL_TAR);
+        commands.add("tar xzfv "+saveAs);
+        commands.add("cd "+getExpandedInstallDir());
+
+        newScript(INSTALLING)
+                .body.append(commands)
+                .execute();
+    }
+
+    @Override
+    public void customize() {
+        Networking.checkPortsValid(getPortMap());
+
+        newScript(CUSTOMIZING)
+                .failOnNonZeroResultCode()
+                .body.append(format("cp -R %s/* %s", getExpandedInstallDir(), getRunDir()))
+                .execute();
+
+        String config = entity.getConfig(getConfigTemplateKey());
+        copyTemplate(config, getConfigFileName());
+    }
+
+    @Override
+    public void launch() {
+        newScript(MutableMap.of(USE_PID_FILE, getPidFile()), LAUNCHING)
+                .failOnNonZeroResultCode()
+                .body.append(String.format("nohup ./bin/%s ./%s > console.out 2>&1 &", getLaunchScriptName(), getConfigFileName()))
+                .execute();
+    }
+
+    public String getPidFile() { return Os.mergePathsUnix(getRunDir(), "kafka.pid"); }
+
+    @Override
+    public boolean isRunning() {
+        return newScript(MutableMap.of(USE_PID_FILE, getPidFile()), CHECK_RUNNING).execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(MutableMap.of(USE_PID_FILE, false), STOPPING)
+                .body.append(String.format("ps ax | grep %s | awk '{print $1}' | xargs kill", getProcessIdentifier()))
+                .body.append(String.format("ps ax | grep %s | awk '{print $1}' | xargs kill -9", getProcessIdentifier()))
+                .execute();
+    }
+
+    /**
+     * Use RMI agent to provide JMX.
+     */
+    @Override
+    public Map<String, String> getShellEnvironment() {
+        return MutableMap.<String, String>builder()
+                .putAll(super.getShellEnvironment())
+                .renameKey("JAVA_OPTS", "KAFKA_JMX_OPTS")
+                .build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..ed34c1e
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/Kafka.java
@@ -0,0 +1,45 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+
+/**
+ * Shared Kafka broker and zookeeper properties.
+ */
+public interface Kafka {
+
+    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "2.9.2-0.8.2.1");
+
+    @SetFromFlag("downloadUrl")
+    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
+            Attributes.DOWNLOAD_URL, "http://apache.cbox.biz/kafka/0.8.2.1/kafka_${version}.tgz");
+
+    // TODO: Upgrade to version 0.8.0, which will require refactoring of the sensors to reflect the changes to the JMX beans
+//    @SetFromFlag("downloadUrl")
+//    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
+//            Attributes.DOWNLOAD_URL, "http://mirror.catn.com/pub/apache/kafka/${version}/kafka-${version}-src.tgz");
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..6ae6b33
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBroker.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.entity.messaging.kafka;
+
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.java.UsesJmx;
+import org.apache.brooklyn.entity.messaging.MessageBroker;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+
+import org.apache.brooklyn.location.basic.PortRanges;
+
+import brooklyn.util.time.Duration;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Kafka broker instance.
+ */
+@ImplementedBy(KafkaBrokerImpl.class)
+public interface KafkaBroker extends SoftwareProcess, MessageBroker, UsesJmx, Kafka {
+
+    @SetFromFlag("startTimeout")
+    ConfigKey<Duration> START_TIMEOUT = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.START_TIMEOUT, Duration.FIVE_MINUTES);
+
+    @SetFromFlag("version")
+    ConfigKey<String> SUGGESTED_VERSION = Kafka.SUGGESTED_VERSION;
+
+    @SetFromFlag("kafkaPort")
+    PortAttributeSensorAndConfigKey KAFKA_PORT = new PortAttributeSensorAndConfigKey("kafka.port", "Kafka port", "9092+");
+
+    /** Location of the configuration file template to be copied to the server.*/
+    @SetFromFlag("kafkaServerConfig")
+    ConfigKey<String> KAFKA_BROKER_CONFIG_TEMPLATE = new BasicConfigKey<String>(String.class,
+            "kafka.broker.configTemplate", "Kafka broker configuration template (in freemarker format)",
+            "classpath://org/apache/brooklyn/entity/messaging/kafka/server.properties");
+
+    @SetFromFlag("zookeeper")
+    ConfigKey<ZooKeeperNode> ZOOKEEPER = new BasicConfigKey<ZooKeeperNode>(ZooKeeperNode.class, "kafka.broker.zookeeper", "Kafka zookeeper entity");
+
+    PortAttributeSensorAndConfigKey INTERNAL_JMX_PORT = new PortAttributeSensorAndConfigKey(
+            "internal.jmx.direct.port", "JMX internal port (started by Kafka broker, if using UsesJmx.JMX_AGENT_MODE is not null)", PortRanges.fromString("9999+"));
+
+    AttributeSensor<Integer> BROKER_ID = Sensors.newIntegerSensor("kafka.broker.id", "Kafka unique broker ID");
+
+    AttributeSensor<Long> FETCH_REQUEST_COUNT = Sensors.newLongSensor("kafka.broker.fetch.total", "Fetch request count");
+    AttributeSensor<Long> TOTAL_FETCH_TIME = Sensors.newLongSensor("kafka.broker.fetch.time.total", "Total fetch request processing time (millis)");
+    AttributeSensor<Double> MAX_FETCH_TIME = Sensors.newDoubleSensor("kafka.broker.fetch.time.max", "Max fetch request processing time (millis)");
+
+    AttributeSensor<Long> PRODUCE_REQUEST_COUNT = Sensors.newLongSensor("kafka.broker.produce.total", "Produce request count");
+    AttributeSensor<Long> TOTAL_PRODUCE_TIME = Sensors.newLongSensor("kafka.broker.produce.time.total", "Total produce request processing time (millis)");
+    AttributeSensor<Double> MAX_PRODUCE_TIME = Sensors.newDoubleSensor("kafka.broker.produce.time.max", "Max produce request processing time (millis)");
+
+    AttributeSensor<Long> BYTES_RECEIVED = Sensors.newLongSensor("kafka.broker.bytes.received", "Total bytes received");
+    AttributeSensor<Long> BYTES_SENT = Sensors.newLongSensor("kafka.broker.bytes.sent", "Total bytes sent");
+    
+    Integer getKafkaPort();
+
+    Integer getBrokerId();
+
+    ZooKeeperNode getZookeeper();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerDriver.java
new file mode 100644
index 0000000..357dae8
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerDriver.java
@@ -0,0 +1,27 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import brooklyn.entity.java.JavaSoftwareProcessDriver;
+
+public interface KafkaBrokerDriver extends JavaSoftwareProcessDriver {
+
+    Integer getKafkaPort();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..b8a9076
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerImpl.java
@@ -0,0 +1,170 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import org.apache.brooklyn.entity.messaging.MessageBroker;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
+import brooklyn.event.feed.jmx.JmxAttributePollConfig;
+import brooklyn.event.feed.jmx.JmxFeed;
+import brooklyn.event.feed.jmx.JmxHelper;
+
+import com.google.common.base.Functions;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Kafka broker instance.
+ */
+public class KafkaBrokerImpl extends SoftwareProcessImpl implements MessageBroker, KafkaBroker {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(KafkaBrokerImpl.class);
+    private static final ObjectName SOCKET_SERVER_STATS_MBEAN = JmxHelper.createObjectName("kafka:type=kafka.SocketServerStats");
+
+    private volatile JmxFeed jmxFeed;
+
+    public KafkaBrokerImpl() {
+        super();
+    }
+
+    @Override
+    public void init() {
+        super.init();
+        setAttribute(BROKER_ID, Math.abs(hashCode())); // Must be positive for partitioning to work
+    }
+
+    @Override
+    public Integer getKafkaPort() { return getAttribute(KAFKA_PORT); }
+
+    @Override
+    public Integer getBrokerId() { return getAttribute(BROKER_ID); }
+
+    @Override
+    public ZooKeeperNode getZookeeper() { return getConfig(ZOOKEEPER); }
+
+    @Override
+    public Class<?> getDriverInterface() {
+        return KafkaBrokerDriver.class;
+    }
+
+    @Override
+    public void waitForServiceUp(long duration, TimeUnit units) {
+        super.waitForServiceUp(duration, units);
+
+        if (((KafkaBrokerDriver)getDriver()).isJmxEnabled()) {
+            // Wait for the MBean to exist
+            JmxHelper helper = new JmxHelper(this);
+            try {
+                helper.assertMBeanExistsEventually(SOCKET_SERVER_STATS_MBEAN, units.toMillis(duration));
+            } finally {
+                helper.terminate();
+            }
+        }
+    }
+
+    @Override
+    protected void connectSensors() {
+        connectServiceUpIsRunning();
+        boolean retrieveUsageMetrics = getConfig(RETRIEVE_USAGE_METRICS);
+        
+        if (((KafkaBrokerDriver)getDriver()).isJmxEnabled()) {
+            jmxFeed = JmxFeed.builder()
+                .entity(this)
+                .period(500, TimeUnit.MILLISECONDS)
+                .pollAttribute(new JmxAttributePollConfig<Long>(FETCH_REQUEST_COUNT)
+                        .objectName(SOCKET_SERVER_STATS_MBEAN)
+                        .attributeName("NumFetchRequests")
+                        .onException(Functions.constant(-1l))
+                        .enabled(retrieveUsageMetrics))
+                .pollAttribute(new JmxAttributePollConfig<Long>(TOTAL_FETCH_TIME)
+                        .objectName(SOCKET_SERVER_STATS_MBEAN)
+                        .attributeName("TotalFetchRequestMs")
+                        .onException(Functions.constant(-1l))
+                        .enabled(retrieveUsageMetrics))
+                .pollAttribute(new JmxAttributePollConfig<Double>(MAX_FETCH_TIME)
+                        .objectName(SOCKET_SERVER_STATS_MBEAN)
+                        .attributeName("MaxFetchRequestMs")
+                        .onException(Functions.constant(-1.0d))
+                        .enabled(retrieveUsageMetrics))
+                .pollAttribute(new JmxAttributePollConfig<Long>(PRODUCE_REQUEST_COUNT)
+                        .objectName(SOCKET_SERVER_STATS_MBEAN)
+                        .attributeName("NumProduceRequests")
+                        .onException(Functions.constant(-1l))
+                        .enabled(retrieveUsageMetrics))
+                .pollAttribute(new JmxAttributePollConfig<Long>(TOTAL_PRODUCE_TIME)
+                        .objectName(SOCKET_SERVER_STATS_MBEAN)
+                        .attributeName("TotalProduceRequestMs")
+                        .onException(Functions.constant(-1l))
+                        .enabled(retrieveUsageMetrics))
+                .pollAttribute(new JmxAttributePollConfig<Double>(MAX_PRODUCE_TIME)
+                        .objectName(SOCKET_SERVER_STATS_MBEAN)
+                        .attributeName("MaxProduceRequestMs")
+                        .onException(Functions.constant(-1.0d))
+                        .enabled(retrieveUsageMetrics))
+                .pollAttribute(new JmxAttributePollConfig<Long>(BYTES_RECEIVED)
+                        .objectName(SOCKET_SERVER_STATS_MBEAN)
+                        .attributeName("TotalBytesRead")
+                        .onException(Functions.constant(-1l))
+                        .enabled(retrieveUsageMetrics))
+                .pollAttribute(new JmxAttributePollConfig<Long>(BYTES_SENT)
+                        .objectName(SOCKET_SERVER_STATS_MBEAN)
+                        .attributeName("TotalBytesWritten")
+                        .onException(Functions.constant(-1l))
+                        .enabled(retrieveUsageMetrics))
+                .build();
+        }
+
+        setBrokerUrl();
+    }
+
+    @Override
+    public void disconnectSensors() {
+        super.disconnectSensors();
+        disconnectServiceUpIsRunning();
+        if (jmxFeed != null) jmxFeed.stop();
+    }
+
+    @Override
+    protected ToStringHelper toStringHelper() {
+        return super.toStringHelper()
+                .add("kafkaPort", getKafkaPort());
+    }
+
+    /** Use the {@link #getZookeeper() zookeeper} details if available, otherwise use our own host and port. */
+    @Override
+    public void setBrokerUrl() {
+        ZooKeeperNode zookeeper = getZookeeper();
+        if (zookeeper != null) {
+            setAttribute(BROKER_URL, String.format("zookeeper://%s:%d", zookeeper.getAttribute(HOSTNAME), zookeeper.getZookeeperPort()));
+        } else {
+            setAttribute(BROKER_URL, String.format("kafka://%s:%d", getAttribute(HOSTNAME), getKafkaPort()));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerSshDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerSshDriver.java
new file mode 100644
index 0000000..df9b67d
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaBrokerSshDriver.java
@@ -0,0 +1,97 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.java.UsesJmx;
+import brooklyn.entity.java.UsesJmx.JmxAgentModes;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+
+public class KafkaBrokerSshDriver extends AbstractfKafkaSshDriver implements KafkaBrokerDriver {
+
+    private static final Logger LOG = LoggerFactory.getLogger(KafkaBrokerSshDriver.class);
+
+    public KafkaBrokerSshDriver(KafkaBrokerImpl entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    @Override
+    protected Map<String, Integer> getPortMap() {
+        return MutableMap.of("kafkaPort", getKafkaPort());
+    }
+
+    @Override
+    protected ConfigKey<String> getConfigTemplateKey() {
+        return KafkaBroker.KAFKA_BROKER_CONFIG_TEMPLATE;
+    }
+
+    @Override
+    protected String getConfigFileName() {
+        return "server.properties";
+    }
+
+    @Override
+    protected String getLaunchScriptName() {
+        return "kafka-server-start.sh";
+    }
+
+    @Override
+    public String getTopicsScriptName() {
+        return "kafka-topics.sh";
+    }
+
+    @Override
+    protected String getProcessIdentifier() {
+        return "kafka\\.Kafka";
+    }
+
+    @Override
+    public Integer getKafkaPort() {
+        return getEntity().getAttribute(KafkaBroker.KAFKA_PORT);
+    }
+
+    @Override
+    public Map<String, String> getShellEnvironment() {
+        JmxAgentModes jmxAgentMode = getEntity().getConfig(KafkaBroker.JMX_AGENT_MODE);
+        String jmxPort;
+        if (jmxAgentMode == JmxAgentModes.NONE) {
+            // seems odd to pass RMI port here, as it gets assigned to com.sun.mgmt.jmx.port in kafka-run-class.sh
+            // but RMI server/registry port works, whereas JMX port does not
+            jmxPort = String.valueOf(entity.getAttribute(UsesJmx.JMX_PORT));
+        } else {
+            /*
+             * See ./bin/kafka-server-start.sh  and ./bin/kafka-run-class.sh
+             * Really hard to turn off jmxremote on kafka! And can't use default because
+             * uses 9999, which means could only run one kafka broker per server.
+             */
+            jmxPort = String.valueOf(entity.getAttribute(KafkaBroker.INTERNAL_JMX_PORT));
+        }
+
+        return MutableMap.<String, String> builder()
+                .putAll(super.getShellEnvironment())
+                .put("JMX_PORT", jmxPort)
+                .build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..c512400
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaCluster.java
@@ -0,0 +1,92 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.Group;
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.BrooklynConfigKeys;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.group.Cluster;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.entity.trait.Resizable;
+import brooklyn.entity.trait.Startable;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
+import brooklyn.event.basic.BasicAttributeSensor;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.util.time.Duration;
+
+/**
+ * Provides Kafka cluster functionality through a group of {@link KafkaBroker brokers} controlled
+ * by a single {@link KafkaZookeeper zookeeper} entity.
+ * <p>
+ * You can customise the Kafka zookeeper and brokers by supplying {@link EntitySpec entity specifications}
+ * to be used when creating them. An existing {@link Zookeeper} entity may also be provided instead of the
+ * Kafka zookeeper.
+ * <p>
+ * The contents of this entity are:
+ * <ul>
+ * <li>a {@link brooklyn.entity.group.DynamicCluster} of {@link KafkaBroker}s
+ * <li>a {@link KafkaZookeeper} or {@link Zookeeper}
+ * <li>a {@link org.apache.brooklyn.api.policy.Policy} to resize the broker cluster
+ * </ul>
+ * The {@link Group group} and {@link Resizable} interface methods are delegated to the broker cluster, so calling
+ * {@link Resizable#resize(Integer) resize} will change the number of brokers.
+ */
+@SuppressWarnings({ "unchecked", "rawtypes" })
+@Catalog(name="Kafka", description="Apache Kafka is a distributed publish-subscribe messaging system", iconUrl="classpath://org/apache/brooklyn/entity/messaging/kafka/kafka-google-doorway.jpg")
+@ImplementedBy(KafkaClusterImpl.class)
+public interface KafkaCluster extends Entity, Startable, Resizable, Group  {
+
+    @SetFromFlag("startTimeout")
+    ConfigKey<Duration> START_TIMEOUT = BrooklynConfigKeys.START_TIMEOUT;
+
+    @SetFromFlag("initialSize")
+    ConfigKey<Integer> INITIAL_SIZE = ConfigKeys.newConfigKeyWithDefault(Cluster.INITIAL_SIZE, 1);
+
+    /** Zookeeper for the cluster. If null a default be will created. */
+    @SetFromFlag("zookeeper")
+    BasicAttributeSensorAndConfigKey<ZooKeeperNode> ZOOKEEPER = new BasicAttributeSensorAndConfigKey<ZooKeeperNode>(
+            ZooKeeperNode.class, "kafka.cluster.zookeeper", "The zookeeper for the cluster; if null a default be will created");
+
+    /** Spec for creating the default Kafka zookeeper entity. */
+    @SetFromFlag("zookeeperSpec")
+    BasicAttributeSensorAndConfigKey<EntitySpec<KafkaZooKeeper>> ZOOKEEPER_SPEC = new BasicAttributeSensorAndConfigKey(
+            EntitySpec.class, "kafka.cluster.zookeeperSpec", "Spec for creating the kafka zookeeper");
+
+    /** Spec for Kafka broker entities to be created. */
+    @SetFromFlag("brokerSpec")
+    BasicAttributeSensorAndConfigKey<EntitySpec<KafkaBroker>> BROKER_SPEC = new BasicAttributeSensorAndConfigKey(
+            EntitySpec.class, "kafka.cluster.brokerSpec", "Spec for Kafka broker entiites to be created");
+
+    /** Underlying Kafka broker cluster. */
+    AttributeSensor<DynamicCluster> CLUSTER = new BasicAttributeSensor<DynamicCluster>(
+            DynamicCluster.class, "kafka.cluster.brokerCluster", "Underlying Kafka broker cluster");
+
+    ZooKeeperNode getZooKeeper();
+
+    DynamicCluster getCluster();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..933d8ce
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
@@ -0,0 +1,206 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.enricher.Enrichers;
+import brooklyn.entity.basic.AbstractEntity;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.entity.trait.Startable;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
+import brooklyn.event.feed.ConfigToAttributes;
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.exceptions.CompoundRuntimeException;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/**
+ * Implementation of a Kafka cluster containing a {@link KafkaZookeeper} node and a group of {@link KafkaBroker}s.
+ */
+public class KafkaClusterImpl extends AbstractEntity implements KafkaCluster {
+
+    public static final Logger log = LoggerFactory.getLogger(KafkaClusterImpl.class);
+
+    public KafkaClusterImpl() {
+    }
+
+    @Override
+    public void init() {
+        super.init();
+        
+        setAttribute(SERVICE_UP, false);
+        ConfigToAttributes.apply(this, BROKER_SPEC);
+        ConfigToAttributes.apply(this, ZOOKEEPER);
+        ConfigToAttributes.apply(this, ZOOKEEPER_SPEC);
+
+        log.debug("creating zookeeper child for {}", this);
+        ZooKeeperNode zookeeper = getAttribute(ZOOKEEPER);
+        if (zookeeper == null) {
+            EntitySpec<KafkaZooKeeper> zookeeperSpec = getAttribute(ZOOKEEPER_SPEC);
+            if (zookeeperSpec == null) {
+                log.debug("creating zookeeper using default spec for {}", this);
+                zookeeperSpec = EntitySpec.create(KafkaZooKeeper.class);
+                setAttribute(ZOOKEEPER_SPEC, zookeeperSpec);
+            } else {
+                log.debug("creating zookeeper using custom spec for {}", this);
+            }
+            zookeeper = addChild(zookeeperSpec);
+            if (Entities.isManaged(this)) Entities.manage(zookeeper);
+            setAttribute(ZOOKEEPER, zookeeper);
+        }
+
+        log.debug("creating cluster child for {}", this);
+        EntitySpec<KafkaBroker> brokerSpec = getAttribute(BROKER_SPEC);
+        if (brokerSpec == null) {
+            log.debug("creating default broker spec for {}", this);
+            brokerSpec = EntitySpec.create(KafkaBroker.class);
+            setAttribute(BROKER_SPEC, brokerSpec);
+        }
+        // Relies on initialSize being inherited by DynamicCluster, because key id is identical
+        // We add the zookeeper configuration to the KafkaBroker specification here
+        DynamicCluster cluster = addChild(EntitySpec.create(DynamicCluster.class)
+                .configure("memberSpec", EntitySpec.create(brokerSpec).configure(KafkaBroker.ZOOKEEPER, zookeeper)));
+        if (Entities.isManaged(this)) Entities.manage(cluster);
+        setAttribute(CLUSTER, cluster);
+        
+        connectSensors();
+    }
+
+    @Override
+    public ZooKeeperNode getZooKeeper() {
+        return getAttribute(ZOOKEEPER);
+    }
+
+    @Override
+    public DynamicCluster getCluster() {
+        return getAttribute(CLUSTER);
+    }
+
+    @Override
+    public void start(Collection<? extends Location> locations) {
+        if (isLegacyConstruction()) {
+            init();
+        }
+
+        if (locations.isEmpty()) locations = getLocations();
+        Iterables.getOnlyElement(locations); // Assert just one
+        addLocations(locations);
+
+        List<Entity> childrenToStart = MutableList.<Entity>of(getCluster());
+        // Set the KafkaZookeeper entity as child of cluster, if it does not already have a parent
+        if (getZooKeeper().getParent() == null) {
+            addChild(getZooKeeper());
+        } // And only start zookeeper if we are parent
+        if (Objects.equal(this, getZooKeeper().getParent())) childrenToStart.add(getZooKeeper());
+        Entities.invokeEffector(this, childrenToStart, Startable.START, ImmutableMap.of("locations", locations)).getUnchecked();
+    }
+
+    @Override
+    public void stop() {
+        List<Exception> errors = Lists.newArrayList();
+        if (getZooKeeper() != null && Objects.equal(this, getZooKeeper().getParent())) {
+            try {
+                getZooKeeper().stop();
+            } catch (Exception e) {
+                errors.add(e);
+            }
+        }
+        if (getCurrentSize() > 0) {
+            try {
+                getCluster().stop();
+            } catch (Exception e) {
+                errors.add(e);
+            }
+        }
+
+        clearLocations();
+        setAttribute(SERVICE_UP, false);
+
+        if (errors.size() != 0) {
+            throw new CompoundRuntimeException("Error stopping Kafka cluster", errors);
+        }
+    }
+
+    @Override
+    public void restart() {
+        // TODO prod the entities themselves to restart, instead?
+        Collection<Location> locations = Lists.newArrayList(getLocations());
+
+        stop();
+        start(locations);
+    }
+
+    void connectSensors() {
+        addEnricher(Enrichers.builder()
+                .propagatingAllBut(SERVICE_UP)
+                .from(getCluster())
+                .build());
+        addEnricher(Enrichers.builder()
+                .propagating(SERVICE_UP)
+                .from(getZooKeeper())
+                .build());
+    }
+
+    /*
+     * All Group and Resizable interface methods are delegated to the broker cluster.
+     */
+
+    /** {@inheritDoc} */
+    @Override
+    public Collection<Entity> getMembers() { return getCluster().getMembers(); }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean hasMember(Entity member) { return getCluster().hasMember(member); }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean addMember(Entity member) { return getCluster().addMember(member); }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean removeMember(Entity member) { return getCluster().removeMember(member); }
+
+    /** {@inheritDoc} */
+    @Override
+    public Integer getCurrentSize() { return getCluster().getCurrentSize(); }
+
+    /** {@inheritDoc} */
+    @Override
+    public Integer resize(Integer desiredSize) { return getCluster().resize(desiredSize); }
+
+    @Override
+    public <T extends Entity> T addMemberChild(EntitySpec<T> spec) { return getCluster().addMemberChild(spec); }
+
+    @Override
+    public <T extends Entity> T addMemberChild(T child) { return getCluster().addMemberChild(child); }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..9bdc33c
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
@@ -0,0 +1,58 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.annotation.Effector;
+import brooklyn.entity.annotation.EffectorParam;
+import brooklyn.entity.basic.SoftwareProcess;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.util.time.Duration;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Kafka zookeeper instance.
+ */
+@ImplementedBy(KafkaZooKeeperImpl.class)
+public interface KafkaZooKeeper extends ZooKeeperNode, Kafka {
+
+    @SetFromFlag("startTimeout")
+    ConfigKey<Duration> START_TIMEOUT = SoftwareProcess.START_TIMEOUT;
+
+    /** The Kafka version, not the Zookeeper version. */
+    @SetFromFlag("version")
+    ConfigKey<String> SUGGESTED_VERSION = Kafka.SUGGESTED_VERSION;
+    
+    /** The Kafka version, not the Zookeeper version. */
+    @SetFromFlag("downloadUrl")
+    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = Kafka.DOWNLOAD_URL;
+
+    /** Location of the kafka configuration file template to be copied to the server. */
+    @SetFromFlag("kafkaZookeeperConfig")
+    ConfigKey<String> KAFKA_ZOOKEEPER_CONFIG_TEMPLATE = new BasicConfigKey<String>(String.class,
+            "kafka.zookeeper.configTemplate", "Kafka zookeeper configuration template (in freemarker format)",
+            "classpath://org/apache/brooklyn/entity/messaging/kafka/zookeeper.properties");
+
+    @Effector(description = "Create a topic with a single partition and only one replica")
+    void createTopic(@EffectorParam(name = "topic") String topic);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperDriver.java
new file mode 100644
index 0000000..f08736d
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperDriver.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.entity.messaging.kafka;
+
+import brooklyn.entity.java.JavaSoftwareProcessDriver;
+
+public interface KafkaZooKeeperDriver extends JavaSoftwareProcessDriver {
+
+    Integer getZookeeperPort();
+
+    void createTopic(String topic);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperImpl.java
new file mode 100644
index 0000000..7764450
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperImpl.java
@@ -0,0 +1,47 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import brooklyn.entity.annotation.EffectorParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.brooklyn.entity.zookeeper.AbstractZooKeeperImpl;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Kafka zookeeper instance.
+ */
+public class KafkaZooKeeperImpl extends AbstractZooKeeperImpl implements KafkaZooKeeper {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(KafkaZooKeeperImpl.class);
+
+    public KafkaZooKeeperImpl() {
+    }
+
+    @Override
+    public Class<?> getDriverInterface() {
+        return KafkaZooKeeperDriver.class;
+    }
+
+    @Override
+    public void createTopic(String topic) {
+        ((KafkaZooKeeperDriver)getDriver()).createTopic(topic);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperSshDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperSshDriver.java
new file mode 100644
index 0000000..85ab649
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/KafkaZooKeeperSshDriver.java
@@ -0,0 +1,82 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import java.util.Map;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.Attributes;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+
+import static brooklyn.util.text.StringEscapes.BashStringEscapes.escapeLiteralForDoubleQuotedBash;
+
+public class KafkaZooKeeperSshDriver extends AbstractfKafkaSshDriver implements KafkaZooKeeperDriver {
+
+    public KafkaZooKeeperSshDriver(KafkaZooKeeperImpl entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    @Override
+    protected Map<String, Integer> getPortMap() {
+        return MutableMap.of("zookeeperPort", getZookeeperPort());
+    }
+
+    @Override
+    protected ConfigKey<String> getConfigTemplateKey() {
+        return KafkaZooKeeper.KAFKA_ZOOKEEPER_CONFIG_TEMPLATE;
+    }
+
+    @Override
+    protected String getConfigFileName() {
+        return "zookeeper.properties";
+    }
+
+    @Override
+    protected String getLaunchScriptName() {
+        return "zookeeper-server-start.sh";
+    }
+
+    @Override
+    protected String getTopicsScriptName() {
+        return "kafka-topics.sh";
+    }
+
+    @Override
+    protected String getProcessIdentifier() {
+        return "quorum\\.QuorumPeerMain";
+    }
+
+    @Override
+    public Integer getZookeeperPort() {
+        return getEntity().getAttribute(KafkaZooKeeper.ZOOKEEPER_PORT);
+    }
+
+    @Override
+    public void createTopic(String topic) {
+        String zookeeperUrl = getEntity().getAttribute(Attributes.HOSTNAME) + ":" + getZookeeperPort();
+        newScript(CUSTOMIZING)
+                .failOnNonZeroResultCode()
+                .body.append(String.format("./bin/%s  --create --zookeeper \"%s\" --replication-factor 1 --partitions 1 --topic \"%s\"",
+                                           getTopicsScriptName(),
+                                           escapeLiteralForDoubleQuotedBash(zookeeperUrl),
+                                           escapeLiteralForDoubleQuotedBash(topic)))
+                .execute();
+    }
+}


[58/64] incubator-brooklyn git commit: brooklyn-software-database: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
deleted file mode 100644
index 5ff0175..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
+++ /dev/null
@@ -1,425 +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 brooklyn.entity.database.postgresql;
-
-import static brooklyn.util.ssh.BashCommands.INSTALL_WGET;
-import static brooklyn.util.ssh.BashCommands.alternativesGroup;
-import static brooklyn.util.ssh.BashCommands.chainGroup;
-import static brooklyn.util.ssh.BashCommands.dontRequireTtyForSudo;
-import static brooklyn.util.ssh.BashCommands.executeCommandThenAsUserTeeOutputToFile;
-import static brooklyn.util.ssh.BashCommands.fail;
-import static brooklyn.util.ssh.BashCommands.ifExecutableElse0;
-import static brooklyn.util.ssh.BashCommands.ifExecutableElse1;
-import static brooklyn.util.ssh.BashCommands.installPackage;
-import static brooklyn.util.ssh.BashCommands.sudo;
-import static brooklyn.util.ssh.BashCommands.sudoAsUser;
-import static brooklyn.util.ssh.BashCommands.warn;
-import static java.lang.String.format;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.annotation.Nullable;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.database.DatastoreMixins;
-import brooklyn.entity.software.SshEffectorTasks;
-
-import org.apache.brooklyn.api.location.OsDetails;
-import org.apache.brooklyn.core.util.task.DynamicTasks;
-import org.apache.brooklyn.core.util.task.ssh.SshTasks;
-import org.apache.brooklyn.core.util.task.ssh.SshTasks.OnFailingTask;
-import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.net.Urls;
-import brooklyn.util.os.Os;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.StringFunctions;
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.io.Files;
-
-/**
- * The SSH implementation of the {@link PostgreSqlDriver}.
- */
-public class PostgreSqlSshDriver extends AbstractSoftwareProcessSshDriver implements PostgreSqlDriver {
-
-    public static final Logger log = LoggerFactory.getLogger(PostgreSqlSshDriver.class);
-
-    public PostgreSqlSshDriver(PostgreSqlNodeImpl entity, SshMachineLocation machine) {
-        super(entity, machine);
-
-        entity.setAttribute(Attributes.LOG_FILE_LOCATION, getLogFile());
-    }
-
-    /*
-     * TODO this is much messier than we would like because postgres runs as user postgres,
-     * meaning the dirs must be RW by that user, and accessible (thus all parent paths),
-     * which may rule out putting it in a location used by the default user.
-     * Two irritating things:
-     * * currently we sometimes make up a different onbox base dir;
-     * * currently we put files to /tmp for staging
-     * Could investigate if it really needs to run as user postgres;
-     * could also see whether default user can be added to group postgres,
-     * and the run dir (and all parents) made accessible to group postgres.
-     */
-    @Override
-    public void install() {
-        String version = getEntity().getConfig(SoftwareProcess.SUGGESTED_VERSION);
-        String majorMinorVersion = version.substring(0, version.lastIndexOf("-"));
-        String shortVersion = majorMinorVersion.replace(".", "");
-
-        String altTarget = "/opt/brooklyn/postgres/";
-        String altInstallDir = Urls.mergePaths(altTarget, "install/"+majorMinorVersion);
-        
-        Iterable<String> pgctlLocations = ImmutableList.of(
-            altInstallDir+"/bin",
-            "/usr/lib/postgresql/"+majorMinorVersion+"/bin/",
-            "/opt/local/lib/postgresql"+shortVersion+"/bin/",
-            "/usr/pgsql-"+majorMinorVersion+"/bin",
-            "/usr/local/bin/",
-            "/usr/bin/",
-            "/bin/");
-
-        DynamicTasks.queueIfPossible(SshTasks.dontRequireTtyForSudo(getMachine(),
-            // sudo is absolutely required here, in customize we set user to postgres
-            OnFailingTask.FAIL)).orSubmitAndBlock();
-        DynamicTasks.waitForLast();
-
-        // Check whether we can find a usable pg_ctl, and if not install one
-        MutableList<String> findOrInstall = MutableList.<String>of()
-            .append("which pg_ctl")
-            .appendAll(Iterables.transform(pgctlLocations, StringFunctions.formatter("test -x %s/pg_ctl")))
-            .append(installPackage(ImmutableMap.of(
-                "yum", "postgresql"+shortVersion+" postgresql"+shortVersion+"-server",
-                "apt", "postgresql-"+majorMinorVersion,
-                "port", "postgresql"+shortVersion+" postgresql"+shortVersion+"-server"
-                ), null))
-                // due to impl of installPackage, it will not come to the line below I don't think
-                .append(warn(format("WARNING: failed to find or install postgresql %s binaries", majorMinorVersion)));
-
-        // Link to correct binaries folder (different versions of pg_ctl and psql don't always play well together)
-        MutableList<String> linkFromHere = MutableList.<String>of()
-            .append(ifExecutableElse1("pg_ctl", chainGroup(
-                "PG_EXECUTABLE=`which pg_ctl`",
-                "PG_DIR=`dirname $PG_EXECUTABLE`",
-                "echo 'found pg_ctl in '$PG_DIR' on path so linking PG bin/ to that dir'",
-                "ln -s $PG_DIR bin")))
-                .appendAll(Iterables.transform(pgctlLocations, givenDirIfFileExistsInItLinkToDir("pg_ctl", "bin")))
-                .append(fail(format("WARNING: failed to find postgresql %s binaries for pg_ctl, may already have another version installed; aborting", majorMinorVersion), 9));
-
-        newScript(INSTALLING)
-        .body.append(
-            dontRequireTtyForSudo(),
-            ifExecutableElse0("yum", getYumRepository(version, majorMinorVersion, shortVersion)),
-            ifExecutableElse0("apt-get", getAptRepository()),
-            "rm -f bin", // if left over from previous incomplete/failed install (not sure why that keeps happening!)
-            alternativesGroup(findOrInstall),
-            alternativesGroup(linkFromHere))
-            .failOnNonZeroResultCode()
-            .queue();
-        
-        // check that the proposed install dir is one that user postgres can access
-        if (DynamicTasks.queue(SshEffectorTasks.ssh(sudoAsUser("postgres", "ls "+getInstallDir())).allowingNonZeroExitCode()
-                .summary("check postgres user can access install dir")).asTask().getUnchecked()!=0) {
-            log.info("Postgres install dir "+getInstallDir()+" for "+getEntity()+" is not accessible to user 'postgres'; " + "using "+altInstallDir+" instead");
-            String newRunDir = Urls.mergePaths(altTarget, "apps", getEntity().getApplication().getId(), getEntity().getId());
-            if (DynamicTasks.queue(SshEffectorTasks.ssh("ls "+altInstallDir+"/pg_ctl").allowingNonZeroExitCode()
-                    .summary("check whether "+altInstallDir+" is set up")).asTask().getUnchecked()==0) {
-                // alt target already exists with binary; nothing to do for install
-            } else {
-                DynamicTasks.queue(SshEffectorTasks.ssh(
-                    "mkdir -p "+altInstallDir,
-                    "rm -rf '"+altInstallDir+"'",
-                    "mv "+getInstallDir()+" "+altInstallDir,
-                    "rm -rf '"+getInstallDir()+"'",
-                    "ln -s "+altInstallDir+" "+getInstallDir(),
-                    "mkdir -p " + newRunDir,
-                    "chown -R postgres:postgres "+altTarget).runAsRoot().requiringExitCodeZero()
-                    .summary("move install dir from user to postgres owned space"));
-            }
-            DynamicTasks.waitForLast();
-            setInstallDir(altInstallDir);
-            setRunDir(newRunDir);
-        }
-    }
-
-    private String getYumRepository(String version, String majorMinorVersion, String shortVersion) {
-        // postgres becomes available if you add the repos using an RPM such as
-        // http://yum.postgresql.org/9.3/redhat/rhel-6-i386/pgdg-centos93-9.3-1.noarch.rpm
-        // fedora, rhel, sl, and centos supported for RPM's
-
-        OsDetails osDetails = getMachine().getMachineDetails().getOsDetails();
-        String arch = osDetails.getArch();
-        String osMajorVersion = osDetails.getVersion();
-        String osName = osDetails.getName();
-
-        log.debug("postgres detecting yum information for "+getEntity()+" at "+getMachine()+": "+osName+", "+osMajorVersion+", "+arch);
-
-        if (osName==null) osName = ""; else osName = osName.toLowerCase();
-
-        if (osName.equals("ubuntu")) return "echo skipping yum repo setup as this is not an rpm environment";
-
-        if (osName.equals("rhel")) osName = "redhat";
-        else if (osName.equals("centos")) osName = "centos";
-        else if (osName.equals("sl") || osName.startsWith("scientific")) osName = "sl";
-        else if (osName.equals("fedora")) osName = "fedora";
-        else {
-            log.debug("insufficient OS family information '"+osName+"' for "+getMachine()+" when installing "+getEntity()+" (yum repos); treating as centos");
-            osName = "centos";
-        }
-
-        if (Strings.isBlank(arch)) {
-            log.warn("Insuffient architecture information '"+arch+"' for "+getMachine()+"when installing "+getEntity()+"; treating as x86_64");
-            arch = "x86_64";
-        }
-
-        if (Strings.isBlank(osMajorVersion)) {
-            if (osName.equals("fedora")) osMajorVersion = "20";
-            else osMajorVersion = "6";
-            log.warn("Insuffient OS version information '"+getMachine().getOsDetails().getVersion()+"' for "+getMachine()+"when installing "+getEntity()+" (yum repos); treating as "+osMajorVersion);
-        } else {
-            if (osMajorVersion.indexOf(".")>0) 
-                osMajorVersion = osMajorVersion.substring(0, osMajorVersion.indexOf('.'));
-        }
-
-        return chainGroup(
-                INSTALL_WGET,
-                sudo(format("wget http://yum.postgresql.org/%s/redhat/rhel-%s-%s/pgdg-%s%s-%s.noarch.rpm", majorMinorVersion, osMajorVersion, arch, osName, shortVersion, version)),
-                sudo(format("rpm -Uvh pgdg-%s%s-%s.noarch.rpm", osName, shortVersion, version))
-            );
-    }
-
-    private String getAptRepository() {
-        return chainGroup(
-                INSTALL_WGET,
-                "wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo tee -a apt-key add -",
-                "echo \"deb http://apt.postgresql.org/pub/repos/apt/   $(sudo lsb_release --codename --short)-pgdg main\" | sudo tee -a /etc/apt/sources.list.d/postgresql.list"
-            );
-    }
-
-    private static Function<String, String> givenDirIfFileExistsInItLinkToDir(final String filename, final String linkToMake) {
-        return new Function<String, String>() {
-            public String apply(@Nullable String dir) {
-                return ifExecutableElse1(Urls.mergePaths(dir, filename),
-                    chainGroup("echo 'found "+filename+" in "+dir+" so linking to it in "+linkToMake+"'", "ln -s "+dir+" "+linkToMake));
-            }
-        };
-    }
-
-    @Override
-    public void customize() {
-        // Some OSes start postgres during package installation
-        DynamicTasks.queue(SshEffectorTasks.ssh(sudoAsUser("postgres", "/etc/init.d/postgresql stop")).allowingNonZeroExitCode()).get();
-
-        newScript(CUSTOMIZING)
-        .body.append(
-            sudo("mkdir -p " + getDataDir()),
-            sudo("chown postgres:postgres " + getDataDir()),
-            sudo("chmod 700 " + getDataDir()),
-            sudo("touch " + getLogFile()),
-            sudo("chown postgres:postgres " + getLogFile()),
-            sudo("touch " + getPidFile()),
-            sudo("chown postgres:postgres " + getPidFile()),
-            alternativesGroup(
-                chainGroup(format("test -e %s", getInstallDir() + "/bin/initdb"),
-                    sudoAsUser("postgres", getInstallDir() + "/bin/initdb -D " + getDataDir())),
-                    callPgctl("initdb", true)))
-                    .failOnNonZeroResultCode()
-                    .execute();
-
-        String configUrl = getEntity().getConfig(PostgreSqlNode.CONFIGURATION_FILE_URL);
-        if (Strings.isBlank(configUrl)) {
-            // http://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server
-            // If the same setting is listed multiple times, the last one wins.
-            DynamicTasks.queue(SshEffectorTasks.ssh(
-                executeCommandThenAsUserTeeOutputToFile(
-                    chainGroup(
-                        "echo \"listen_addresses = '*'\"",
-                        "echo \"port = " + getEntity().getPostgreSqlPort() +  "\"",
-                        "echo \"max_connections = " + getEntity().getMaxConnections() +  "\"",
-                        "echo \"shared_buffers = " + getEntity().getSharedMemory() +  "\"",
-                        "echo \"external_pid_file = '" + getPidFile() +  "'\""),
-                        "postgres", getDataDir() + "/postgresql.conf")));
-        } else {
-            String contents = processTemplate(configUrl);
-            DynamicTasks.queue(
-                SshEffectorTasks.put("/tmp/postgresql.conf").contents(contents),
-                SshEffectorTasks.ssh(sudoAsUser("postgres", "cp /tmp/postgresql.conf " + getDataDir() + "/postgresql.conf")));
-        }
-
-        String authConfigUrl = getEntity().getConfig(PostgreSqlNode.AUTHENTICATION_CONFIGURATION_FILE_URL);
-        if (Strings.isBlank(authConfigUrl)) {
-            DynamicTasks.queue(SshEffectorTasks.ssh(
-                // TODO give users control which hosts can connect and the authentication mechanism
-                executeCommandThenAsUserTeeOutputToFile("echo \"host all all 0.0.0.0/0 md5\"", "postgres", getDataDir() + "/pg_hba.conf")));
-        } else {
-            String contents = processTemplate(authConfigUrl);
-            DynamicTasks.queue(
-                SshEffectorTasks.put("/tmp/pg_hba.conf").contents(contents),
-                SshEffectorTasks.ssh(sudoAsUser("postgres", "cp /tmp/pg_hba.conf " + getDataDir() + "/pg_hba.conf")));
-        }
-
-        // Wait for commands to complete before running the creation script
-        DynamicTasks.waitForLast();
-
-        // Capture log file contents if there is an error configuring the database
-        try {
-            executeDatabaseCreationScript();
-        } catch (RuntimeException r) {
-            logTailOfPostgresLog();
-            throw Exceptions.propagate(r);
-        }
-
-        // Try establishing an external connection. If you get a "Connection refused...accepting TCP/IP connections
-        // on port 5432?" error then the port is probably closed. Check that the firewall allows external TCP/IP
-        // connections (netstat -nap). You can open a port with lokkit or by configuring the iptables.
-    }
-
-    protected void executeDatabaseCreationScript() {
-        if (copyDatabaseCreationScript()) {
-            newScript("running postgres creation script")
-            .body.append(
-                "cd " + getInstallDir(),
-                callPgctl("start", true),
-                sudoAsUser("postgres", getInstallDir() + "/bin/psql -p " + entity.getAttribute(PostgreSqlNode.POSTGRESQL_PORT) + " --file " + getRunDir() + "/creation-script.sql"),
-                callPgctl("stop", true))
-                .failOnNonZeroResultCode()
-                .execute();
-        }
-    }
-
-    private boolean installFile(InputStream contents, String destName) {
-        String uid = Identifiers.makeRandomId(8);
-        // TODO currently put in /tmp for staging, since run dir may not be accessible to ssh user
-        getMachine().copyTo(contents, "/tmp/"+destName+"_"+uid);
-        DynamicTasks.queueIfPossible(SshEffectorTasks.ssh(
-            "cd "+getRunDir(), 
-            "mv /tmp/"+destName+"_"+uid+" "+destName,
-            "chown postgres:postgres "+destName,
-            "chmod 644 "+destName)
-            .runAsRoot().requiringExitCodeZero())
-            .orSubmitAndBlock(getEntity()).andWaitForSuccess();
-        return true;
-    }
-    private boolean copyDatabaseCreationScript() {
-        InputStream creationScript = DatastoreMixins.getDatabaseCreationScript(entity);
-        if (creationScript==null)
-            return false;
-        return installFile(creationScript, "creation-script.sql");
-    }
-
-    public String getDataDir() {
-        return getRunDir() + "/data";
-    }
-
-    public String getLogFile() {
-        return getRunDir() + "/postgresql.log";
-    }
-
-    public String getPidFile() {
-        return getRunDir() + "/postgresql.pid";
-    }
-
-    /** @deprecated since 0.7.0 renamed {@link #logTailOfPostgresLog()} */
-    @Deprecated
-    public void copyLogFileContents() { logTailOfPostgresLog(); }
-    public void logTailOfPostgresLog() {
-        try {
-            File file = Os.newTempFile("postgresql-"+getEntity().getId(), "log");
-            int result = getMachine().copyFrom(getLogFile(), file.getAbsolutePath());
-            if (result != 0) throw new IllegalStateException("Could not access log file " + getLogFile());
-            log.info("Saving {} contents as {}", getLogFile(), file);
-            Streams.logStreamTail(log, "postgresql.log", Streams.byteArrayOfString(Files.toString(file, Charsets.UTF_8)), 1024);
-            file.delete();
-        } catch (IOException ioe) {
-            log.debug("Error reading copied log file: {}", ioe);
-        }
-    }
-
-    protected String callPgctl(String command, boolean waitForIt) {
-        return sudoAsUser("postgres", getInstallDir() + "/bin/pg_ctl -D " + getDataDir() +
-            " -l " + getLogFile() + (waitForIt ? " -w " : " ") + command);
-    }
-
-    @Override
-    public void launch() {
-        log.info(String.format("Starting entity %s at %s", this, getLocation()));
-        newScript(MutableMap.of("usePidFile", false), LAUNCHING)
-        .body.append(callPgctl("start", false))
-        .execute();
-    }
-
-    @Override
-    public boolean isRunning() {
-        return newScript(MutableMap.of("usePidFile", getPidFile()), CHECK_RUNNING)
-            .body.append(getStatusCmd())
-            .execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        newScript(MutableMap.of("usePidFile", false), STOPPING)
-        .body.append(callPgctl((entity.getConfig(PostgreSqlNode.DISCONNECT_ON_STOP) ? "-m immediate " : "") + "stop", false))
-        .failOnNonZeroResultCode()
-        .execute();
-        newScript(MutableMap.of("usePidFile", getPidFile(), "processOwner", "postgres"), STOPPING).execute();
-    }
-
-    @Override
-    public PostgreSqlNodeImpl getEntity() {
-        return (PostgreSqlNodeImpl) super.getEntity();
-    }
-
-    @Override
-    public String getStatusCmd() {
-        return callPgctl("status", false);
-    }
-
-    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands) {
-        String filename = "postgresql-commands-"+Identifiers.makeRandomId(8);
-        installFile(Streams.newInputStreamWithContents(commands), filename);
-        return executeScriptFromInstalledFileAsync(filename);
-    }
-
-    public ProcessTaskWrapper<Integer> executeScriptFromInstalledFileAsync(String filenameAlreadyInstalledAtServer) {
-        return DynamicTasks.queue(
-            SshEffectorTasks.ssh(
-                "cd "+getRunDir(),
-                sudoAsUser("postgres", getInstallDir() + "/bin/psql -p " + entity.getAttribute(PostgreSqlNode.POSTGRESQL_PORT) + " --file " + filenameAlreadyInstalledAtServer))
-                .summary("executing datastore script "+filenameAlreadyInstalledAtServer));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepDriver.java b/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepDriver.java
deleted file mode 100644
index 163e37d..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepDriver.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 brooklyn.entity.database.rubyrep;
-
-import brooklyn.entity.basic.SoftwareProcessDriver;
-
-/**
- * The driver interface for {@link RubyRepNode}.
- */
-public interface RubyRepDriver extends SoftwareProcessDriver {
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNode.java b/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNode.java
deleted file mode 100644
index edfbda5..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNode.java
+++ /dev/null
@@ -1,109 +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 brooklyn.entity.database.rubyrep;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.database.DatastoreMixins;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-
-@Catalog(name = "RubyRep Node", description = "RubyRep is a database replication system", iconUrl = "classpath:///rubyrep-logo.jpeg")
-@ImplementedBy(RubyRepNodeImpl.class)
-public interface RubyRepNode extends SoftwareProcess {
-
-    @SetFromFlag("version")
-    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "1.2.0");
-
-    @SetFromFlag("downloadUrl")
-    public static final BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new StringAttributeSensorAndConfigKey(
-            Attributes.DOWNLOAD_URL, "http://files.rubyforge.vm.bytemark.co.uk/rubyrep/rubyrep-${version}.zip");
-
-    @SetFromFlag("configurationScriptUrl")
-    ConfigKey<String> CONFIGURATION_SCRIPT_URL = ConfigKeys.newStringConfigKey(
-            "database.rubyrep.configScriptUrl",
-            "URL where RubyRep configuration can be found - disables other configuration options (except version)");
-
-    @SetFromFlag("templateUrl")
-    ConfigKey<String> TEMPLATE_CONFIGURATION_URL = ConfigKeys.newStringConfigKey(
-            "database.rubyrep.templateConfigurationUrl", "Template file (in freemarker format) for the rubyrep.conf file",
-            "classpath://brooklyn/entity/database/rubyrep/rubyrep.conf");
-
-    @SetFromFlag("tables")
-    ConfigKey<String> TABLE_REGEXP = ConfigKeys.newStringConfigKey(
-            "database.rubyrep.tableRegex", "Regular expression to select tables to sync using RubyRep", ".");
-
-    @SetFromFlag("replicationInterval")
-    ConfigKey<Integer> REPLICATION_INTERVAL = ConfigKeys.newIntegerConfigKey(
-            "database.rubyrep.replicationInterval", "Replication Interval", 30);
-
-    @SetFromFlag("startupTimeout")
-    ConfigKey<Integer> DATABASE_STARTUP_TIMEOUT = ConfigKeys.newIntegerConfigKey(
-            "database.rubyrep.startupTimeout", "Time to wait until databases have started up (in seconds)", 120);
-
-    // Left database
-
-    AttributeSensor<String> LEFT_DATASTORE_URL = Sensors.newSensorWithPrefix("left", DatastoreMixins.DATASTORE_URL);
-
-    @SetFromFlag("leftDatabase")
-    ConfigKey<? extends DatastoreCommon> LEFT_DATABASE = ConfigKeys.newConfigKey(DatastoreCommon.class,
-            "database.rubyrep.leftDatabase", "Brooklyn database entity to use as the left DBMS");
-
-    @SetFromFlag("leftDatabaseName")
-    ConfigKey<String> LEFT_DATABASE_NAME = ConfigKeys.newStringConfigKey(
-            "database.rubyrep.leftDatabaseName", "name of database to use for left db");
-
-    @SetFromFlag("leftUsername")
-    ConfigKey<String> LEFT_USERNAME = ConfigKeys.newStringConfigKey(
-            "database.rubyrep.leftUsername", "username to connect to left db");
-
-    @SetFromFlag("leftPassword")
-    ConfigKey<String> LEFT_PASSWORD = ConfigKeys.newStringConfigKey(
-            "database.rubyrep.leftPassword", "password to connect to left db");
-
-    // Right database
-
-    AttributeSensor<String> RIGHT_DATASTORE_URL = Sensors.newSensorWithPrefix("right", DatastoreMixins.DATASTORE_URL);
-
-    @SetFromFlag("rightDatabase")
-    ConfigKey<? extends DatastoreCommon> RIGHT_DATABASE = ConfigKeys.newConfigKey(DatastoreCommon.class,
-            "database.rubyrep.rightDatabase", "Brooklyn database entity to use as the right DBMS");
-
-    @SetFromFlag("rightDatabaseName")
-    ConfigKey<String> RIGHT_DATABASE_NAME = ConfigKeys.newStringConfigKey(
-            "database.rubyrep.rightDatabaseName", "name of database to use for right db");
-
-    @SetFromFlag("rightUsername")
-    ConfigKey<String> RIGHT_USERNAME = ConfigKeys.newStringConfigKey(
-            "database.rubyrep.rightUsername", "username to connect to right db");
-
-    @SetFromFlag("rightPassword")
-    ConfigKey<String> RIGHT_PASSWORD = ConfigKeys.newStringConfigKey(
-            "database.rubyrep.rightPassword", "password to connect to right db");
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNodeImpl.java b/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNodeImpl.java
deleted file mode 100644
index b12b439..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNodeImpl.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 brooklyn.entity.database.rubyrep;
-
-import java.net.URI;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.event.basic.DependentConfiguration;
-import brooklyn.util.time.Duration;
-
-public class RubyRepNodeImpl extends SoftwareProcessImpl implements RubyRepNode {
-
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-        connectServiceUpIsRunning();
-    }
-
-    @Override
-    public void disconnectSensors() {
-        disconnectServiceUpIsRunning();
-        super.disconnectSensors();
-    }
-
-    /**
-     * Set the database {@link DatastoreCommon#DATASTORE_URL urls} as attributes when they become available on the entities.
-     */
-    @Override
-    protected void preStart() {
-        super.preStart();
-
-        DatastoreCommon leftNode = getConfig(LEFT_DATABASE);
-        if (leftNode != null) {
-            setAttribute(LEFT_DATASTORE_URL, Entities.submit(this, DependentConfiguration.attributeWhenReady(leftNode, DatastoreCommon.DATASTORE_URL)).getUnchecked(getDatabaseStartupDelay()));
-        }
-
-        DatastoreCommon rightNode = getConfig(RIGHT_DATABASE);
-        if (rightNode != null) {
-            setAttribute(RIGHT_DATASTORE_URL, Entities.submit(this, DependentConfiguration.attributeWhenReady(rightNode, DatastoreCommon.DATASTORE_URL)).getUnchecked(getDatabaseStartupDelay()));
-        }
-    }
-
-    @Override
-    public Class<?> getDriverInterface() {
-        return RubyRepDriver.class;
-    }
-
-    public Duration getDatabaseStartupDelay() {
-        return Duration.seconds(getConfig(DATABASE_STARTUP_TIMEOUT));
-    }
-
-    // Accessors used in freemarker template processing
-
-    public int getReplicationInterval() {
-        return getConfig(REPLICATION_INTERVAL);
-    }
-    
-    public String getTableRegex() {
-        return getConfig(TABLE_REGEXP);
-    }
-    
-    public URI getLeftDatabaseUrl() {
-        return URI.create(getAttribute(LEFT_DATASTORE_URL));
-    }
-    
-    public String getLeftDatabaseName() {
-        return getConfig(LEFT_DATABASE_NAME);
-    }
-
-    public String getLeftUsername() {
-        return getConfig(LEFT_USERNAME);
-    }
-
-    public String getLeftPassword() {
-        return getConfig(LEFT_PASSWORD);
-    }
-
-    public URI getRightDatabaseUrl() {
-        return URI.create(getAttribute(RIGHT_DATASTORE_URL));
-    }
-
-    public String getRightDatabaseName() {
-        return getConfig(RIGHT_DATABASE_NAME);
-    }
-
-    public String getRightUsername() {
-        return getConfig(RIGHT_USERNAME);
-    }
-
-    public String getRightPassword() {
-        return getConfig(RIGHT_PASSWORD);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepSshDriver.java b/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepSshDriver.java
deleted file mode 100644
index 8415dd6..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepSshDriver.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 brooklyn.entity.database.rubyrep;
-
-import static java.lang.String.format;
-
-import java.io.Reader;
-import java.net.URISyntaxException;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-
-import org.apache.brooklyn.api.entity.basic.EntityLocal;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.stream.Streams;
-
-import com.google.common.collect.ImmutableList;
-
-public class RubyRepSshDriver extends AbstractSoftwareProcessSshDriver implements RubyRepDriver {
-
-    public static final Logger log = LoggerFactory.getLogger(RubyRepSshDriver.class);
-
-    public RubyRepSshDriver(EntityLocal entity, SshMachineLocation machine) {
-        super(entity, machine);
-
-        entity.setAttribute(Attributes.LOG_FILE_LOCATION, getLogFileLocation());
-    }
-
-    protected String getLogFileLocation() {
-        return Os.mergePaths(getRunDir(), "log", "rubyrep.log");
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("rubyrep-%s", getVersion()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-
-        List<String> commands = ImmutableList.<String>builder()
-                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
-                .add(BashCommands.INSTALL_UNZIP)
-                .add("unzip " + saveAs)
-                .build();
-
-        newScript(INSTALLING)
-                .body.append(commands)
-                .failOnNonZeroResultCode()
-                .execute();
-    }
-
-    @Override
-    public void customize() {
-        newScript(CUSTOMIZING)
-                .body.append(format("cp -R %s %s", getExpandedInstallDir(), getRunDir()))
-                .failOnNonZeroResultCode()
-                .execute();
-        try {
-            customizeConfiguration();
-        } catch (Exception e) {
-            log.error("Failed to configure rubyrep, replication is unlikely to succeed", e);
-        }
-    }
-
-    protected void customizeConfiguration() throws ExecutionException, InterruptedException, URISyntaxException {
-        log.info("Copying creation script " + getEntity().toString());
-
-        // TODO check these semantics are what we really want?
-        String configScriptUrl = entity.getConfig(RubyRepNode.CONFIGURATION_SCRIPT_URL);
-        Reader configContents;
-        if (configScriptUrl != null) {
-            // If set accept as-is
-            configContents = Streams.reader(resource.getResourceFromUrl(configScriptUrl));
-        } else {
-            String configScriptContents = processTemplate(entity.getConfig(RubyRepNode.TEMPLATE_CONFIGURATION_URL));
-            configContents = Streams.newReaderWithContents(configScriptContents);
-        }
-
-        getMachine().copyTo(configContents, getRunDir() + "/rubyrep.conf");
-    }
-
-    @Override
-    public void launch() {
-        newScript(MutableMap.of("usePidFile", true), LAUNCHING)
-                .body.append(format("nohup rubyrep-%s/jruby/bin/jruby rubyrep-%s/bin/rubyrep replicate -c rubyrep.conf > ./console 2>&1 &", getVersion(), getVersion()))
-                .execute();
-    }
-
-    @Override
-    public boolean isRunning() {
-        return newScript(MutableMap.of("usePidFile", true), CHECK_RUNNING).execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        newScript(MutableMap.of("usePidFile", true), STOPPING).execute();
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/org/apache/brooklyn/entity/database/DatabaseNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/DatabaseNode.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/DatabaseNode.java
new file mode 100644
index 0000000..56eb9b7
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/DatabaseNode.java
@@ -0,0 +1,29 @@
+/*
+ * 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.entity.database;
+
+import org.apache.brooklyn.api.event.AttributeSensor;
+
+/** @deprecated since 0.7.0 use DatastoreMixins.DatastoreCommon */ @Deprecated 
+public interface DatabaseNode extends DatastoreMixins.DatastoreCommon {
+
+    /** @deprecated since 0.7.0 use DATASTORE_URL */ @Deprecated 
+    public static final AttributeSensor<String> DB_URL = DATASTORE_URL;
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..fee8f02
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/DatastoreMixins.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.entity.database;
+
+import java.io.InputStream;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.Effector;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.effector.Effectors;
+import brooklyn.event.basic.Sensors;
+import brooklyn.util.stream.KnownSizeInputStream;
+import brooklyn.util.text.Strings;
+
+public class DatastoreMixins {
+
+    private DatastoreMixins() {}
+    
+    
+    public static final AttributeSensor<String> DATASTORE_URL = HasDatastoreUrl.DATASTORE_URL;
+    
+    public static interface HasDatastoreUrl {
+        public static final AttributeSensor<String> DATASTORE_URL = Sensors.newStringSensor("datastore.url",
+            "Primary contact URL for a datastore (e.g. mysql://localhost:3306/)");
+    }
+
+    
+    public static final Effector<String> EXECUTE_SCRIPT = CanExecuteScript.EXECUTE_SCRIPT;
+    
+    public static interface CanExecuteScript {
+        public static final Effector<String> EXECUTE_SCRIPT = Effectors.effector(String.class, "executeScript")
+            .description("executes the given script contents")
+            .parameter(String.class, "commands")
+            .buildAbstract();
+    }
+
+    
+    public static final ConfigKey<String> CREATION_SCRIPT_CONTENTS = CanGiveCreationScript.CREATION_SCRIPT_CONTENTS; 
+    public static final ConfigKey<String> CREATION_SCRIPT_URL = CanGiveCreationScript.CREATION_SCRIPT_URL; 
+
+    public static interface CanGiveCreationScript {
+        @SetFromFlag("creationScriptContents")
+        public static final ConfigKey<String> CREATION_SCRIPT_CONTENTS = ConfigKeys.newStringConfigKey(
+                "datastore.creation.script.contents",
+                "Contents of creation script to initialize the datastore",
+                "");
+        
+        @SetFromFlag("creationScriptUrl")
+        public static final ConfigKey<String> CREATION_SCRIPT_URL = ConfigKeys.newStringConfigKey(
+                "datastore.creation.script.url",
+                "URL of creation script to use to initialize the datastore (ignored if creationScriptContents is specified)",
+                "");
+    }
+
+    /** returns the creation script contents, if it exists, or null if none is defined (error if it cannot be loaded) */
+    @Nullable public static InputStream getDatabaseCreationScript(Entity entity) {
+        String url = entity.getConfig(DatastoreMixins.CREATION_SCRIPT_URL);
+        if (!Strings.isBlank(url))
+            return new ResourceUtils(entity).getResourceFromUrl(url);
+        String contents = entity.getConfig(DatastoreMixins.CREATION_SCRIPT_CONTENTS);
+        if (!Strings.isBlank(contents))
+            return KnownSizeInputStream.of(contents);
+        return null;
+    }
+
+    /** returns the creation script contents, if it exists, or null if none is defined (error if it cannot be loaded) */
+    @Nullable public static String getDatabaseCreationScriptAsString(Entity entity) {
+        String url = entity.getConfig(DatastoreMixins.CREATION_SCRIPT_URL);
+        if (!Strings.isBlank(url))
+            return new ResourceUtils(entity).getResourceAsString(url);
+        String contents = entity.getConfig(DatastoreMixins.CREATION_SCRIPT_CONTENTS);
+        if (!Strings.isBlank(contents))
+            return contents;
+        return null;
+    }
+    
+    /** An entity with the most common datastore config, sensors, and effectors */ 
+    public interface DatastoreCommon extends Entity, DatastoreMixins.HasDatastoreUrl, DatastoreMixins.CanExecuteScript, DatastoreMixins.CanGiveCreationScript {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..264611e
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNode.java
@@ -0,0 +1,92 @@
+/*
+ * 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.entity.database.crate;
+
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import brooklyn.entity.java.UsesJava;
+import brooklyn.entity.java.UsesJavaMXBeans;
+import brooklyn.entity.java.UsesJmx;
+import brooklyn.event.basic.AttributeSensorAndConfigKey;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+
+import org.apache.brooklyn.location.basic.PortRanges;
+
+@ImplementedBy(CrateNodeImpl.class)
+public interface CrateNode extends SoftwareProcess, UsesJava,UsesJmx, UsesJavaMXBeans, DatastoreCommon {
+
+    @SetFromFlag("version")
+    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION,
+            "0.45.7");
+
+    @SetFromFlag("downloadUrl")
+    AttributeSensorAndConfigKey<String, String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey(
+            Attributes.DOWNLOAD_URL,
+            "https://cdn.crate.io/downloads/releases/crate-${version}.tar.gz");
+
+    @SetFromFlag("serverConfig")
+    BasicAttributeSensorAndConfigKey<String> SERVER_CONFIG_URL = new BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey(
+            "crate.serverConfig", "A URL of a YAML file to use to configure the server",
+            "classpath://org/apache/brooklyn/entity/database/crate/crate.yaml");
+
+    @SetFromFlag("port")
+    public static final PortAttributeSensorAndConfigKey CRATE_PORT = new PortAttributeSensorAndConfigKey(
+            "crate.port", "The port for node-to-node communication", PortRanges.fromString("4300+"));
+
+    @SetFromFlag("httpPort")
+    public static final PortAttributeSensorAndConfigKey CRATE_HTTP_PORT = new PortAttributeSensorAndConfigKey(
+            "crate.httpPort", "The port for HTTP traffic", PortRanges.fromString("4200+"));
+
+    AttributeSensor<String> MANAGEMENT_URL = Sensors.newStringSensor(
+            "crate.managementUri", "The address at which the Crate server listens");
+
+    AttributeSensor<String> SERVER_NAME = Sensors.newStringSensor(
+            "crate.server.name", "The name of the server");
+
+    AttributeSensor<Boolean> SERVER_OK = Sensors.newBooleanSensor(
+            "crate.server.ok", "True if the server reports thus");
+
+    AttributeSensor<Integer> SERVER_STATUS = Sensors.newIntegerSensor(
+            "crate.server.status", "The status of the server");
+
+    AttributeSensor<String> SERVER_BUILD_TIMESTAMP = Sensors.newStringSensor(
+            "crate.server.buildTimestamp", "The timestamp of the server build");
+
+    AttributeSensor<String> SERVER_BUILD_HASH = Sensors.newStringSensor(
+            "crate.server.buildHash", "The build hash of the server");
+
+    AttributeSensor<Boolean> SERVER_IS_BUILD_SNAPSHOT = Sensors.newBooleanSensor(
+            "crate.server.isBuildSnapshot", "True if the server reports it is a snapshot build");
+
+    AttributeSensor<String> SERVER_LUCENE_VERSION = Sensors.newStringSensor(
+            "crate.server.luceneVersion", "The Lucene version of the server");
+
+    AttributeSensor<String> SERVER_ES_VERSION = Sensors.newStringSensor(
+            "crate.server.esVersion", "The ES version of the server");
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeDriver.java
new file mode 100644
index 0000000..708e0e8
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeDriver.java
@@ -0,0 +1,24 @@
+/*
+ * 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.entity.database.crate;
+
+import brooklyn.entity.java.JavaSoftwareProcessDriver;
+
+public interface CrateNodeDriver extends JavaSoftwareProcessDriver {
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..df65398
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java
@@ -0,0 +1,99 @@
+/*
+ * 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.entity.database.crate;
+
+import brooklyn.config.render.RendererHints;
+import brooklyn.enricher.Enrichers;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.entity.java.JavaAppUtils;
+import brooklyn.event.feed.http.HttpFeed;
+import brooklyn.event.feed.http.HttpPollConfig;
+import brooklyn.event.feed.http.HttpValueFunctions;
+import brooklyn.event.feed.jmx.JmxFeed;
+import brooklyn.util.guava.Functionals;
+
+public class CrateNodeImpl extends SoftwareProcessImpl implements CrateNode{
+
+    private JmxFeed jmxFeed;
+    private HttpFeed httpFeed;
+
+    static {
+        JavaAppUtils.init();
+        RendererHints.register(MANAGEMENT_URL, RendererHints.namedActionWithUrl());
+    }
+
+    @Override
+    public Class getDriverInterface() {
+        return CrateNodeDriver.class;
+    }
+
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+        connectServiceUpIsRunning();
+        jmxFeed = JavaAppUtils.connectMXBeanSensors(this);
+        setAttribute(DATASTORE_URL, "crate://" + getAttribute(HOSTNAME) + ":" + getPort());
+        String url = "http://" + getAttribute(HOSTNAME) + ":" + getHttpPort();
+        setAttribute(MANAGEMENT_URL, url);
+
+        httpFeed = HttpFeed.builder()
+                .entity(this)
+                .baseUri(url)
+                .poll(new HttpPollConfig<String>(SERVER_NAME)
+                        .onSuccess(HttpValueFunctions.jsonContents("name", String.class)))
+                .poll(new HttpPollConfig<Integer>(SERVER_STATUS)
+                        .onSuccess(HttpValueFunctions.jsonContents("status", Integer.class)))
+                .poll(new HttpPollConfig<Boolean>(SERVER_OK)
+                        .onSuccess(HttpValueFunctions.jsonContents("ok", Boolean.class)))
+                .poll(new HttpPollConfig<String>(SERVER_BUILD_TIMESTAMP)
+                        .onSuccess(HttpValueFunctions.jsonContents(new String[]{"version", "build_timestamp"}, String.class)))
+                .poll(new HttpPollConfig<String>(SERVER_BUILD_HASH)
+                        .onSuccess(HttpValueFunctions.jsonContents(new String[]{"version", "build_hash"}, String.class)))
+                .poll(new HttpPollConfig<Boolean>(SERVER_IS_BUILD_SNAPSHOT)
+                        .onSuccess(HttpValueFunctions.jsonContents(new String[] {"version", "build_snapshot"}, Boolean.class)))
+                .poll(new HttpPollConfig<String>(SERVER_LUCENE_VERSION)
+                        .onSuccess(HttpValueFunctions.jsonContents(new String[] {"version", "lucene_version"}, String.class)))
+                .poll(new HttpPollConfig<String>(SERVER_ES_VERSION)
+                        .onSuccess(HttpValueFunctions.jsonContents(new String[] {"version", "es_version"}, String.class)))
+                .build();
+
+        addEnricher(Enrichers.builder().updatingMap(Attributes.SERVICE_NOT_UP_INDICATORS)
+                .from(SERVER_OK)
+                .computing(Functionals.ifNotEquals(true).value("Crate server reports it is not ok."))
+                .build());
+    }
+
+    @Override
+    protected void disconnectSensors() {
+        disconnectServiceUpIsRunning();
+        if (jmxFeed != null) jmxFeed.stop();
+        if (httpFeed != null) httpFeed.stop();
+        super.disconnectSensors();
+    }
+
+    public Integer getPort() {
+        return getAttribute(CRATE_PORT);
+    }
+
+    public Integer getHttpPort() {
+        return getAttribute(CRATE_HTTP_PORT);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeSshDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeSshDriver.java
new file mode 100644
index 0000000..2eafc81
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeSshDriver.java
@@ -0,0 +1,118 @@
+/*
+ * 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.entity.database.crate;
+
+import static java.lang.String.format;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.entity.basic.EntityLocal;
+
+import com.google.common.collect.ImmutableList;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+
+public class CrateNodeSshDriver extends JavaSoftwareProcessSshDriver {
+
+    public CrateNodeSshDriver(EntityLocal entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this);
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(),
+                resolver.getUnpackedDirectoryName(format("crate-%s", getVersion()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+
+        List<String> commands = ImmutableList.<String>builder()
+                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
+                .add("tar xvfz "+saveAs)
+                .build();
+
+        newScript(INSTALLING)
+                .failOnNonZeroResultCode()
+                .body.append(commands).execute();
+    }
+
+    @Override
+    public void customize() {
+        newScript(CUSTOMIZING)
+                .body.append("mkdir -p " + getDataLocation())
+                .execute();
+        copyTemplate(entity.getConfig(CrateNode.SERVER_CONFIG_URL), getConfigFileLocation());
+    }
+
+    @Override
+    public void launch() {
+        StringBuilder command = new StringBuilder(getExpandedInstallDir())
+                .append("/bin/crate ")
+                .append(" -d")
+                .append(" -p ").append(getPidFileLocation())
+                .append(" -Des.config=").append(getConfigFileLocation());
+        newScript(LAUNCHING)
+                .failOnNonZeroResultCode()
+                .body.append(command).execute();
+
+    }
+
+    @Override
+    public boolean isRunning() {
+        return newScript (MutableMap.of("usePidFile", getPidFileLocation()), CHECK_RUNNING)
+                .execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        // See https://crate.io/docs/stable/cli.html#signal-handling.
+        newScript(STOPPING)
+                .body.append("kill -USR2 `cat " + getPidFileLocation() + "`")
+                .execute();
+    }
+
+    protected String getConfigFileLocation() {
+        return Urls.mergePaths(getRunDir(), "config.yaml");
+    }
+
+    @Override
+    public String getLogFileLocation() {
+        return Urls.mergePaths(getRunDir(), "crate.log");
+    }
+
+    protected String getPidFileLocation () {
+        return Urls.mergePaths(getRunDir(), "pid.txt");
+    }
+
+    // public for use in template too.
+    public String getDataLocation() {
+        return Urls.mergePaths(getRunDir(), "data");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbDriver.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbDriver.java
new file mode 100644
index 0000000..5c841a7
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbDriver.java
@@ -0,0 +1,31 @@
+/*
+ * 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.entity.database.mariadb;
+
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+
+import brooklyn.entity.basic.SoftwareProcessDriver;
+
+/**
+ * The {@link SoftwareProcessDriver} for MariaDB.
+ */
+public interface MariaDbDriver extends SoftwareProcessDriver {
+    public String getStatusCmd();
+    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..34b068e
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNode.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.entity.database.mariadb;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.entity.trait.HasShortName;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import org.apache.brooklyn.entity.database.DatabaseNode;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
+import brooklyn.event.basic.MapConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+
+import org.apache.brooklyn.location.basic.PortRanges;
+
+@Catalog(name="MariaDB Node", description="MariaDB is an open source relational database management system (RDBMS)", iconUrl="classpath:///mariadb-logo-180x119.png")
+@ImplementedBy(MariaDbNodeImpl.class)
+public interface MariaDbNode extends SoftwareProcess, DatastoreCommon, HasShortName, DatabaseNode {
+
+    @SetFromFlag("version")
+    public static final ConfigKey<String> SUGGESTED_VERSION =
+        ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "5.5.40");
+
+    // https://downloads.mariadb.org/interstitial/mariadb-5.5.33a/kvm-bintar-hardy-amd64/mariadb-5.5.33a-linux-x86_64.tar.gz/from/http://mirrors.coreix.net/mariadb
+    // above redirects to download the artifactd from the URLs below.
+    // Use `curl -sL -w "%{http_code} %{url_effective}\n" "http://..." -o target.tar.gz` to find out redirect URL.
+    //     64-bit: http://mirrors.coreix.net/mariadb/mariadb-5.5.40/bintar-linux-x86_64/mariadb-5.5.40-linux-x86_64.tar.gz
+    //     32-bit: http://mirrors.coreix.net/mariadb/mariadb-5.5.40/bintar-linux-x86/mariadb-5.5.40-linux-i686.tar.gz
+
+    @SetFromFlag("downloadUrl")
+    public static final BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new StringAttributeSensorAndConfigKey(
+          Attributes.DOWNLOAD_URL, "${driver.mirrorUrl}/mariadb-${version}/${driver.downloadParentDir}/mariadb-${version}-${driver.osTag}.tar.gz");
+
+    /** download mirror, if desired */
+    @SetFromFlag("mirrorUrl")
+    public static final ConfigKey<String> MIRROR_URL = ConfigKeys.newStringConfigKey("mariadb.install.mirror.url", "URL of mirror",
+        "http://mirrors.coreix.net/mariadb/"
+     );
+
+    @SetFromFlag("port")
+    public static final PortAttributeSensorAndConfigKey MARIADB_PORT =
+        new PortAttributeSensorAndConfigKey("mariadb.port", "MariaDB port", PortRanges.fromString("3306, 13306+"));
+
+    @SetFromFlag("dataDir")
+    public static final ConfigKey<String> DATA_DIR = ConfigKeys.newStringConfigKey(
+        "mariadb.datadir", "Directory for writing data files", null);
+
+    @SetFromFlag("serverConf")
+    public static final MapConfigKey<Object> MARIADB_SERVER_CONF = new MapConfigKey<Object>(
+        Object.class, "mariadb.server.conf", "Configuration options for MariaDB server");
+
+    public static final ConfigKey<Object> MARIADB_SERVER_CONF_LOWER_CASE_TABLE_NAMES =
+        MARIADB_SERVER_CONF.subKey("lower_case_table_names", "See MariaDB (or MySQL!) guide. Set 1 to ignore case in table names (useful for OS portability)");
+
+    @SetFromFlag("password")
+    public static final StringAttributeSensorAndConfigKey PASSWORD = new StringAttributeSensorAndConfigKey(
+        "mariadb.password", "Database admin password (or randomly generated if not set)", null);
+
+    @SetFromFlag("socketUid")
+    public static final StringAttributeSensorAndConfigKey SOCKET_UID = new StringAttributeSensorAndConfigKey(
+        "mariadb.socketUid", "Socket uid, for use in file /tmp/mysql.sock.<uid>.3306 (or randomly generated if not set)", null);
+
+    /** @deprecated since 0.7.0 use DATASTORE_URL */ @Deprecated
+    public static final AttributeSensor<String> MARIADB_URL = DATASTORE_URL;
+
+    @SetFromFlag("configurationTemplateUrl")
+    static final BasicAttributeSensorAndConfigKey<String> TEMPLATE_CONFIGURATION_URL = new StringAttributeSensorAndConfigKey(
+        "mariadb.template.configuration.url", "Template file (in freemarker format) for the my.cnf file",
+        "classpath://org/apache/brooklyn/entity/database/mariadb/my.cnf");
+
+    public static final AttributeSensor<Double> QUERIES_PER_SECOND_FROM_MARIADB =
+        Sensors.newDoubleSensor("mariadb.queries.perSec.fromMariadb");
+
+    public String executeScript(String commands);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..238ce49
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
@@ -0,0 +1,139 @@
+/*
+ * 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.entity.database.mariadb;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.entity.effector.EffectorBody;
+import brooklyn.event.feed.ssh.SshFeed;
+import brooklyn.event.feed.ssh.SshPollConfig;
+import brooklyn.event.feed.ssh.SshPollValue;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.location.basic.Locations;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Function;
+
+public class MariaDbNodeImpl extends SoftwareProcessImpl implements MariaDbNode {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MariaDbNodeImpl.class);
+
+    private SshFeed feed;
+
+    @Override
+    public Class<?> getDriverInterface() {
+        return MariaDbDriver.class;
+    }
+
+    @Override
+    public MariaDbDriver getDriver() {
+        return (MariaDbDriver) super.getDriver();
+    }
+
+    @Override
+    public void init() {
+        super.init();
+        getMutableEntityType().addEffector(EXECUTE_SCRIPT, new EffectorBody<String>() {
+            @Override
+            public String call(ConfigBag parameters) {
+                return executeScript((String)parameters.getStringKey("commands"));
+            }
+        });
+    }
+    
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+        setAttribute(DATASTORE_URL, String.format("mysql://%s:%s/", getAttribute(HOSTNAME), getAttribute(MARIADB_PORT)));
+
+        /*        
+         * TODO status gives us things like:
+         *   Uptime: 2427  Threads: 1  Questions: 581  Slow queries: 0  Opens: 53  Flush tables: 1  Open tables: 35  Queries per second avg: 0.239
+         * So can extract lots of sensors from that.
+         */
+        Maybe<SshMachineLocation> machine = Locations.findUniqueSshMachineLocation(getLocations());
+
+        if (machine.isPresent()) {
+            String cmd = getDriver().getStatusCmd();
+            feed = SshFeed.builder()
+                    .entity(this)
+                    .period(Duration.FIVE_SECONDS)
+                    .machine(machine.get())
+                    .poll(new SshPollConfig<Boolean>(SERVICE_UP)
+                            .command(cmd)
+                            .setOnSuccess(true)
+                            .setOnFailureOrException(false))
+                    .poll(new SshPollConfig<Double>(QUERIES_PER_SECOND_FROM_MARIADB)
+                            .command(cmd)
+                            .onSuccess(new Function<SshPollValue, Double>() {
+                                public Double apply(SshPollValue input) {
+                                    String q = Strings.getFirstWordAfter(input.getStdout(), "Queries per second avg:");
+                                    return (q == null) ? null : Double.parseDouble(q);
+                                }})
+                            .setOnFailureOrException(null) )
+                    .build();
+        } else {
+            LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; setting serviceUp immediately", getLocations());
+            setAttribute(SERVICE_UP, true);
+        }
+    }
+
+    @Override
+    protected void disconnectSensors() {
+        if (feed != null) feed.stop();
+        super.disconnectSensors();
+    }
+
+    public int getPort() {
+        return getAttribute(MARIADB_PORT);
+    }
+
+    public String getSocketUid() {
+        String result = getAttribute(MariaDbNode.SOCKET_UID);
+        if (Strings.isBlank(result))
+            setAttribute(MariaDbNode.SOCKET_UID, (result = Identifiers.makeRandomId(6)));
+        return result;
+    }
+
+    public String getPassword() {
+        String result = getAttribute(MariaDbNode.PASSWORD);
+        if (Strings.isBlank(result))
+            setAttribute(MariaDbNode.PASSWORD, (result = Identifiers.makeRandomId(6)));
+        return result;
+    }
+
+    @Override
+    public String getShortName() {
+        return "MariaDB";
+    }
+
+    @Override
+    public String executeScript(String commands) {
+        return getDriver().executeScriptAsync(commands).block().getStdout();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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
new file mode 100644
index 0000000..4f3a59b
--- /dev/null
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
@@ -0,0 +1,259 @@
+/*
+ * 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.entity.database.mariadb;
+
+import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
+import static brooklyn.util.ssh.BashCommands.commandsToDownloadUrlsAs;
+import static brooklyn.util.ssh.BashCommands.installPackage;
+import static brooklyn.util.ssh.BashCommands.ok;
+import static java.lang.String.format;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.entity.database.DatastoreMixins;
+import brooklyn.entity.software.SshEffectorTasks;
+
+import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.CountdownTimer;
+import brooklyn.util.time.Duration;
+
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * The SSH implementation of the {@link MariaDbDriver}.
+ */
+public class MariaDbSshDriver extends AbstractSoftwareProcessSshDriver implements MariaDbDriver {
+
+    public static final Logger log = LoggerFactory.getLogger(MariaDbSshDriver.class);
+
+    public MariaDbSshDriver(MariaDbNodeImpl entity, SshMachineLocation machine) {
+        super(entity, machine);
+
+        entity.setAttribute(Attributes.LOG_FILE_LOCATION, getLogFile());
+    }
+
+    public String getOsTag() {
+        OsDetails os = getLocation().getOsDetails();
+        // NOTE: cannot rely on OsDetails.isLinux() to return true for all linux flavours, so
+        // explicitly test for unsupported OSes, otherwise assume generic linux.
+        if (os == null) return "linux-i686";
+        if (os.isWindows() || os.isMac())
+            throw new UnsupportedOperationException("only support linux versions just now; OS details: " + os);
+        return (os.is64bit() ? "linux-x86_64" : "linux-i686");
+    }
+
+    public String getDownloadParentDir() {
+        // NOTE: cannot rely on OsDetails.isLinux() to return true for all linux flavours, so
+        // explicitly test for unsupported OSes, otherwise assume generic linux.
+        OsDetails os = getLocation().getOsDetails();
+        if (os == null) return "bintar-linux-x86";
+        if (os.isWindows() || os.isMac())
+            throw new UnsupportedOperationException("only support linux versions just now; OS details: " + os);
+        return (os.is64bit() ? "bintar-linux-x86_64" : "bintar-linux-x86");
+    }
+
+    public String getMirrorUrl() {
+        return entity.getConfig(MariaDbNode.MIRROR_URL);
+    }
+
+    public String getBaseDir() { return getExpandedInstallDir(); }
+
+    public String getDataDir() {
+        String result = entity.getConfig(MariaDbNode.DATA_DIR);
+        return (result == null) ? "." : result;
+    }
+
+    public String getLogFile() {
+        return Urls.mergePaths(getRunDir(), "console.log");
+    }
+
+    public String getConfigFile() {
+        return "my.cnf";
+    }
+
+    public String getInstallFilename() {
+        return String.format("mariadb-%s-%s.tar.gz", getVersion(), getOsTag());
+    }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this, ImmutableMap.of("filename", getInstallFilename()));
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("mariadb-%s-%s", getVersion(), getOsTag()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+
+        List<String> commands = new LinkedList<String>();
+        commands.add(BashCommands.INSTALL_TAR);
+        commands.add(BashCommands.INSTALL_CURL);
+
+        commands.add("echo installing extra packages");
+        commands.add(installPackage(ImmutableMap.of("yum", "libgcc_s.so.1"), null));
+        commands.add(installPackage(ImmutableMap.of("yum", "libaio.so.1 libncurses.so.5", "apt", "libaio1 libaio-dev"), null));
+
+        // these deps are needed on some OS versions but others don't need them so ignore failures (ok(...))
+        commands.add(ok(installPackage(ImmutableMap.of("yum", "libaio", "apt", "ia32-libs"), null)));
+        commands.add("echo finished installing extra packages");
+
+        commands.addAll(commandsToDownloadUrlsAs(urls, saveAs));
+        commands.add(format("tar xfvz %s", saveAs));
+
+        newScript(INSTALLING).body.append(commands).execute();
+    }
+
+    public MariaDbNodeImpl getEntity() { return (MariaDbNodeImpl) super.getEntity(); }
+    public int getPort() { return getEntity().getPort(); }
+    public String getSocketUid() { return getEntity().getSocketUid(); }
+    public String getPassword() { return getEntity().getPassword(); }
+
+    @Override
+    public void customize() {
+        copyDatabaseConfigScript();
+
+        newScript(CUSTOMIZING)
+            .updateTaskAndFailOnNonZeroResultCode()
+            .body.append(
+                "chmod 600 "+getConfigFile(),
+                getBaseDir()+"/scripts/mysql_install_db "+
+                    "--basedir="+getBaseDir()+" --datadir="+getDataDir()+" "+
+                    "--defaults-file="+getConfigFile())
+            .execute();
+
+        // launch, then we will configure it
+        launch();
+
+        CountdownTimer timer = Duration.seconds(20).countdownTimer();
+        boolean hasCreationScript = copyDatabaseCreationScript();
+        timer.waitForExpiryUnchecked();
+
+        DynamicTasks.queue(
+            SshEffectorTasks.ssh(
+                "cd "+getRunDir(),
+                getBaseDir()+"/bin/mysqladmin --defaults-file="+getConfigFile()+" --password= password "+getPassword()
+            ).summary("setting password"));
+
+        if (hasCreationScript)
+            executeScriptFromInstalledFileAsync("creation-script.sql");
+
+        // not sure necessary to stop then subsequently launch, but seems safest
+        // (if skipping, use a flag in launch to indicate we've just launched it)
+        stop();
+    }
+
+    private void copyDatabaseConfigScript() {
+        newScript(CUSTOMIZING).execute();  //create the directory
+
+        String configScriptContents = processTemplate(entity.getAttribute(MariaDbNode.TEMPLATE_CONFIGURATION_URL));
+        Reader configContents = new StringReader(configScriptContents);
+
+        getMachine().copyTo(configContents, Urls.mergePaths(getRunDir(), getConfigFile()));
+    }
+
+    private boolean copyDatabaseCreationScript() {
+        InputStream creationScript = DatastoreMixins.getDatabaseCreationScript(entity);
+        if (creationScript==null) return false;
+        getMachine().copyTo(creationScript, getRunDir() + "/creation-script.sql");
+        return true;
+    }
+
+    public String getMariaDbServerOptionsString() {
+        Map<String, Object> options = entity.getConfig(MariaDbNode.MARIADB_SERVER_CONF);
+        StringBuilder result = new StringBuilder();
+        if (groovyTruth(options)) {
+            for (Map.Entry<String, Object> entry : options.entrySet()) {
+                result.append(entry.getKey());
+                String value = entry.getValue().toString();
+                if (!Strings.isEmpty(value)) {
+                    result.append(" = ").append(value);
+                }
+                result.append('\n');
+            }
+        }
+        return result.toString();
+    }
+
+    @Override
+    public void launch() {
+        newScript(MutableMap.of("usePidFile", true), LAUNCHING)
+            .updateTaskAndFailOnNonZeroResultCode()
+            .body.append(format("nohup %s/bin/mysqld --defaults-file=%s --user=`whoami` > %s 2>&1 < /dev/null &", getBaseDir(), getConfigFile(), getLogFile()))
+            .execute();
+    }
+
+    @Override
+    public boolean isRunning() {
+        return newScript(MutableMap.of("usePidFile", false), CHECK_RUNNING)
+            .body.append(getStatusCmd())
+            .execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(MutableMap.of("usePidFile", true), STOPPING).execute();
+    }
+
+    @Override
+    public void kill() {
+        newScript(MutableMap.of("usePidFile", true), KILLING).execute();
+    }
+
+    @Override
+    public String getStatusCmd() {
+        return format("%s/bin/mysqladmin --defaults-file=%s status", getExpandedInstallDir(), Urls.mergePaths(getRunDir(), getConfigFile()));
+    }
+
+    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands) {
+        String filename = "mariadb-commands-"+Identifiers.makeRandomId(8);
+        DynamicTasks.queue(SshEffectorTasks.put(Urls.mergePaths(getRunDir(), filename)).contents(commands).summary("copying datastore script to execute "+filename));
+        return executeScriptFromInstalledFileAsync(filename);
+    }
+
+    public ProcessTaskWrapper<Integer> executeScriptFromInstalledFileAsync(String filenameAlreadyInstalledAtServer) {
+        return DynamicTasks.queue(
+                SshEffectorTasks.ssh(
+                                "cd "+getRunDir(),
+                                getBaseDir()+"/bin/mysql --defaults-file="+getConfigFile()+" < "+filenameAlreadyInstalledAtServer)
+                        .summary("executing datastore script "+filenameAlreadyInstalledAtServer));
+    }
+
+}


[33/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjTool.java b/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjTool.java
deleted file mode 100644
index e069aa9..0000000
--- a/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjTool.java
+++ /dev/null
@@ -1,1091 +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 brooklyn.util.internal.ssh.sshj;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Throwables.getCausalChain;
-import static com.google.common.collect.Iterables.any;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
-
-import net.schmizz.sshj.connection.ConnectionException;
-import net.schmizz.sshj.connection.channel.direct.PTYMode;
-import net.schmizz.sshj.connection.channel.direct.Session;
-import net.schmizz.sshj.connection.channel.direct.Session.Command;
-import net.schmizz.sshj.connection.channel.direct.Session.Shell;
-import net.schmizz.sshj.connection.channel.direct.SessionChannel;
-import net.schmizz.sshj.sftp.FileAttributes;
-import net.schmizz.sshj.sftp.SFTPClient;
-import net.schmizz.sshj.transport.TransportException;
-import net.schmizz.sshj.xfer.InMemorySourceFile;
-
-import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
-import org.apache.commons.io.input.ProxyInputStream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.exceptions.RuntimeTimeoutException;
-import brooklyn.util.internal.ssh.BackoffLimitedRetryHandler;
-import brooklyn.util.internal.ssh.ShellTool;
-import brooklyn.util.internal.ssh.SshAbstractTool;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.io.FileUtil;
-import brooklyn.util.repeat.Repeater;
-import brooklyn.util.stream.KnownSizeInputStream;
-import brooklyn.util.stream.StreamGobbler;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
-import com.google.common.base.Predicate;
-import com.google.common.base.Stopwatch;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.io.CountingOutputStream;
-import com.google.common.net.HostAndPort;
-import com.google.common.primitives.Ints;
-
-/**
- * For ssh and scp-style commands, using the sshj library.
- */
-public class SshjTool extends SshAbstractTool implements SshTool {
-
-    /*
-     * TODO synchronization of connect/disconnect needs revisited!
-     * Saw SshjToolIntegrationTest.testExecBigConcurrentCommand fail with:
-     *     Caused by: java.lang.AssertionError
-     *         at net.schmizz.sshj.SSHClient.auth(SSHClient.java:204)
-     * i.e. another thread had called disconnect just before the failing thread
-     * did SSHClient.auth.
-     * Having multiple threads call connect/disconnect is going to be brittle. With
-     * our retries we can get away with it usually, but it's not good!
-     *
-     * TODO need to upgrade sshj version from 0.8.1 to 0.9, but jclouds 1.7.2 still 
-     * relies on 0.8.1. In 0.9, it fixes the https://github.com/shikhar/sshj/issues/89
-     * so does not throw AssertionError.
-     */
-
-    private static final Logger LOG = LoggerFactory.getLogger(SshjTool.class);
-
-    protected final int sshTries;
-    protected final long sshTriesTimeout;
-    protected final BackoffLimitedRetryHandler backoffLimitedRetryHandler;
-
-    /** Terminal type name for {@code allocatePTY} option. */
-    final static String TERM = "vt100"; // "dumb"
-    
-    private class CloseFtpChannelOnCloseInputStream extends ProxyInputStream {
-        private final SFTPClient sftp;
-
-        private CloseFtpChannelOnCloseInputStream(InputStream proxy, SFTPClient sftp) {
-            super(proxy);
-            this.sftp = sftp;
-        }
-
-        @Override
-        public void close() throws IOException {
-            super.close();
-            closeWhispering(sftp, this);
-        }
-    }
-
-    private final SshjClientConnection sshClientConnection;
-
-    public static SshjToolBuilder builder() {
-        return new SshjToolBuilder();
-    }
-    
-    public static class SshjToolBuilder extends Builder<SshjTool, SshjToolBuilder> {
-    }
-    
-    public static class Builder<T extends SshjTool, B extends Builder<T,B>> extends AbstractSshToolBuilder<T,B> {
-        protected long connectTimeout;
-        protected long sessionTimeout;
-        protected int sshTries = 4;  //allow 4 tries by default, much safer
-        protected long sshTriesTimeout = 2*60*1000;  //allow 2 minutes by default (so if too slow trying sshTries times, abort anyway)
-        protected long sshRetryDelay = 50L;
-        
-        @Override
-        public B from(Map<String,?> props) {
-            super.from(props);
-            sshTries = getOptionalVal(props, PROP_SSH_TRIES);
-            sshTriesTimeout = getOptionalVal(props, PROP_SSH_TRIES_TIMEOUT);
-            sshRetryDelay = getOptionalVal(props, PROP_SSH_RETRY_DELAY);
-            connectTimeout = getOptionalVal(props, PROP_CONNECT_TIMEOUT);
-            sessionTimeout = getOptionalVal(props, PROP_SESSION_TIMEOUT);
-            return self();
-        }
-        public B connectTimeout(int val) {
-            this.connectTimeout = val; return self();
-        }
-        public B sessionTimeout(int val) {
-            this.sessionTimeout = val; return self();
-        }
-        public B sshRetries(int val) {
-            this.sshTries = val; return self();
-        }
-        public B sshRetriesTimeout(int val) {
-            this.sshTriesTimeout = val; return self();
-        }
-        public B sshRetryDelay(long val) {
-            this.sshRetryDelay = val; return self();
-        }
-        @Override
-        @SuppressWarnings("unchecked")
-        public T build() {
-            return (T) new SshjTool(this);
-        }
-    }
-
-    public SshjTool(Map<String,?> map) {
-        this(builder().from(map));
-    }
-    
-    protected SshjTool(Builder<?,?> builder) {
-        super(builder);
-        
-        sshTries = builder.sshTries;
-        sshTriesTimeout = builder.sshTriesTimeout;
-        backoffLimitedRetryHandler = new BackoffLimitedRetryHandler(sshTries, builder.sshRetryDelay);
-
-        sshClientConnection = SshjClientConnection.builder()
-                .hostAndPort(HostAndPort.fromParts(host, port))
-                .username(user)
-                .password(password)
-                .privateKeyPassphrase(privateKeyPassphrase)
-                .privateKeyData(privateKeyData)
-                .privateKeyFile(privateKeyFile)
-                .strictHostKeyChecking(strictHostKeyChecking)
-                .connectTimeout(builder.connectTimeout)
-                .sessionTimeout(builder.sessionTimeout)
-                .build();
-        
-        if (LOG.isTraceEnabled()) LOG.trace("Created SshTool {} ({})", this, System.identityHashCode(this));
-    }
-    
-    @Override
-    public void connect() {
-        try {
-            if (LOG.isTraceEnabled()) LOG.trace("Connecting SshjTool {} ({})", this, System.identityHashCode(this));
-            acquire(sshClientConnection);
-        } catch (Exception e) {
-            if (LOG.isDebugEnabled()) LOG.debug(toString()+" failed to connect (rethrowing)", e);
-            throw propagate(e, "failed to connect");
-        }
-    }
-
-    @Override
-    @Deprecated // see super
-    public void connect(int maxAttempts) {
-        connect(); // FIXME Should callers instead configure sshTries? But that would apply to all ssh attempts
-    }
-
-    @Override
-    public void disconnect() {
-        if (LOG.isTraceEnabled()) LOG.trace("Disconnecting SshjTool {} ({})", this, System.identityHashCode(this));
-        try {
-            Stopwatch perfStopwatch = Stopwatch.createStarted();
-            sshClientConnection.clear();
-            if (LOG.isTraceEnabled()) LOG.trace("SSH Performance: {} disconnect took {}", sshClientConnection.getHostAndPort(), Time.makeTimeStringRounded(perfStopwatch));
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    @Override
-    public boolean isConnected() {
-        return sshClientConnection.isConnected() && sshClientConnection.isAuthenticated();
-    }
-    
-    @Override
-    public int copyToServer(java.util.Map<String,?> props, byte[] contents, String pathAndFileOnRemoteServer) {
-        return copyToServer(props, newInputStreamSupplier(contents), contents.length, pathAndFileOnRemoteServer);
-    }
-    
-    @Override
-    public int copyToServer(Map<String,?> props, InputStream contents, String pathAndFileOnRemoteServer) {
-        /* sshj needs to:
-         *   1) to know the length of the InputStream to copy the file to perform copy; and
-         *   2) re-read the input stream on retry if the first attempt fails.
-         * For now, write it to a file, unless caller supplies a KnownSizeInputStream
-         * 
-         * (We could have a switch where we hold it in memory if less than some max size,
-         * but most the routines should supply a string or byte array or similar,
-         * so we probably don't come here too often.)
-         */
-        if (contents instanceof KnownSizeInputStream) {
-            return copyToServer(props, Suppliers.ofInstance(contents), ((KnownSizeInputStream)contents).length(), pathAndFileOnRemoteServer);
-        } else {
-            File tempFile = writeTempFile(contents);
-            try {
-                return copyToServer(props, tempFile, pathAndFileOnRemoteServer);
-            } finally {
-                tempFile.delete();
-            }
-        }
-    }
-    
-    @Override
-    public int copyToServer(Map<String,?> props, File localFile, String pathAndFileOnRemoteServer) {
-        return copyToServer(props, newInputStreamSupplier(localFile), (int)localFile.length(), pathAndFileOnRemoteServer);
-    }
-    
-    private int copyToServer(Map<String,?> props, Supplier<InputStream> contentsSupplier, long length, String pathAndFileOnRemoteServer) {
-        acquire(new PutFileAction(props, pathAndFileOnRemoteServer, contentsSupplier, length));
-        return 0; // TODO Can we assume put will have thrown exception if failed? Rather than exit code != 0?
-    }
-
-
-    @Override
-    public int copyFromServer(Map<String,?> props, String pathAndFileOnRemoteServer, File localFile) {
-        InputStream contents = acquire(new GetFileAction(pathAndFileOnRemoteServer));
-        try {
-            FileUtil.copyTo(contents, localFile);
-            return 0; // TODO Can we assume put will have thrown exception if failed? Rather than exit code != 0?
-        } finally {
-            Streams.closeQuietly(contents);
-        }
-    }
-
-    /**
-     * This creates a script containing the user's commands, copies it to the remote server, and
-     * executes the script. The script is then deleted.
-     * <p>
-     * Executing commands directly is fraught with dangers! Here are other options, and their problems:
-     * <ul>
-     *   <li>Use execCommands, rather than shell.
-     *       The user's environment will not be setup normally (e.g. ~/.bash_profile will not have been sourced)
-     *       so things like wget may not be on the PATH.
-     *   <li>Send the stream of commands to the shell.
-     *       But characters being sent can be lost.
-     *       Try the following (e.g. in an OS X terminal):
-     *        - sleep 5
-     *        - <paste a command that is 1000s of characters long>
-     *       Only the first 1024 characters appear. The rest are lost.
-     *       If sending a stream of commands, you need to be careful not send the next (big) command while the
-     *       previous one is still executing.
-     *   <li>Send a stream to the shell, but spot when the previous command has completed.
-     *       e.g. by looking for the prompt (but what if the commands being executed change the prompt?)
-     *       e.g. by putting every second command as "echo <uid>", and waiting for the stdout.
-     *       This gets fiddly...
-     * </ul>
-     * 
-     * So on balance, the script-based approach seems most reliable, even if there is an overhead
-     * of separate message(s) for copying the file!
-     * 
-     * Another consideration is long-running scripts. On some clouds when executing a script that takes 
-     * several minutes, we have seen it fail with -1 (e.g. 1 in 20 times). This suggests the ssh connection
-     * is being dropped. To avoid this problem, we can execute the script asynchronously, writing to files
-     * the stdout/stderr/pid/exitStatus. We then periodically poll to retrieve the contents of these files.
-     * Use {@link #PROP_EXEC_ASYNC} to force this mode of execution.
-     */
-    @Override
-    public int execScript(final Map<String,?> props, final List<String> commands, final Map<String,?> env) {
-        Boolean execAsync = getOptionalVal(props, PROP_EXEC_ASYNC);
-        if (Boolean.TRUE.equals(execAsync) && BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC)) {
-            return execScriptAsyncAndPoll(props, commands, env);
-        } else {
-            if (Boolean.TRUE.equals(execAsync)) {
-                if (LOG.isDebugEnabled()) LOG.debug("Ignoring ssh exec-async configuration, because feature is disabled");
-            }
-            return new ToolAbstractExecScript(props) {
-                public int run() {
-                    String scriptContents = toScript(props, commands, env);
-                    if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} as script: {}", host, scriptContents);
-                    copyToServer(ImmutableMap.of("permissions", "0700"), scriptContents.getBytes(), scriptPath);
-                    return asInt(acquire(new ShellAction(buildRunScriptCommand(), out, err, execTimeout)), -1);
-                }
-            }.run();
-        }
-    }
-
-    /**
-     * Executes the script in the background (`nohup ... &`), and then executes other ssh commands to poll for the
-     * stdout, stderr and exit code of that original process (which will each have been written to separate files).
-     * 
-     * The polling is a "long poll". That is, it executes a long-running ssh command to retrieve the stdout, etc.
-     * If that long-poll command fails, then we just execute another one to pick up from where it left off.
-     * This means we do not need to execute many ssh commands (which are expensive), but can still return promptly
-     * when the command completes.
-     * 
-     * Much of this was motivated by https://issues.apache.org/jira/browse/BROOKLYN-106, which is no longer
-     * an issue. The retries (e.g. in the upload-script) are arguably overkill given that {@link #acquire(SshAction)}
-     * will already retry. However, leaving this in place as it could prove useful when working with flakey
-     * networks in the future.
-     * 
-     * TODO There are (probably) issues with this method when using {@link ShellTool#PROP_RUN_AS_ROOT}.
-     * I (Aled) saw the .pid file having an owner of root:root, and a failure message in stderr of:
-     *   -bash: line 3: /tmp/brooklyn-20150113-161203056-XMEo-move_install_dir_from_user_to_.pid: Permission denied
-     */
-    protected int execScriptAsyncAndPoll(final Map<String,?> props, final List<String> commands, final Map<String,?> env) {
-        return new ToolAbstractAsyncExecScript(props) {
-            private int maxConsecutiveSshFailures = 3;
-            private Duration maxDelayBetweenPolls = Duration.seconds(20);
-            private Duration pollTimeout = getOptionalVal(props, PROP_EXEC_ASYNC_POLLING_TIMEOUT, Duration.FIVE_MINUTES);
-            private int iteration = 0;
-            private int consecutiveSshFailures = 0;
-            private int stdoutCount = 0;
-            private int stderrCount = 0;
-            private Stopwatch timer;
-            
-            public int run() {
-                timer = Stopwatch.createStarted();
-                final String scriptContents = toScript(props, commands, env);
-                if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} as async script: {}", host, scriptContents);
-                
-                // Upload script; try repeatedly because have seen timeout intermittently on vcloud-director (BROOKLYN-106 related).
-                boolean uploadSuccess = Repeater.create("async script upload on "+SshjTool.this.toString()+" (for "+getSummary()+")")
-                        .backoffTo(maxDelayBetweenPolls)
-                        .limitIterationsTo(3)
-                        .rethrowException()
-                        .until(new Callable<Boolean>() {
-                            @Override
-                            public Boolean call() throws Exception {
-                                iteration++;
-                                if (LOG.isDebugEnabled()) {
-                                    String msg = "Uploading (iteration="+iteration+") for async script on "+SshjTool.this.toString()+" (for "+getSummary()+")";
-                                    if (iteration == 1) {
-                                        LOG.trace(msg);
-                                    } else {
-                                        LOG.debug(msg);
-                                    }
-                                }
-                                copyToServer(ImmutableMap.of("permissions", "0700"), scriptContents.getBytes(), scriptPath);
-                                return true;
-                            }})
-                        .run();
-                
-                if (!uploadSuccess) {
-                    // Unexpected! Should have either returned true or have rethrown the exception; should never get false.
-                    String msg = "Unexpected state: repeated failure for async script upload on "+SshjTool.this.toString()+" ("+getSummary()+")";
-                    LOG.warn(msg+"; rethrowing");
-                    throw new IllegalStateException(msg);
-                }
-                
-                // Execute script asynchronously
-                int execResult = asInt(acquire(new ShellAction(buildRunScriptCommand(), out, err, execTimeout)), -1);
-                if (execResult != 0) return execResult;
-
-                // Long polling to get the status
-                try {
-                    final AtomicReference<Integer> result = new AtomicReference<Integer>();
-                    boolean success = Repeater.create("async script long-poll on "+SshjTool.this.toString()+" (for "+getSummary()+")")
-                            .backoffTo(maxDelayBetweenPolls)
-                            .limitTimeTo(execTimeout)
-                            .until(new Callable<Boolean>() {
-                                @Override
-                                public Boolean call() throws Exception {
-                                    iteration++;
-                                    if (LOG.isDebugEnabled()) LOG.debug("Doing long-poll (iteration="+iteration+") for async script to complete on "+SshjTool.this.toString()+" (for "+getSummary()+")");
-                                    Integer exitstatus = longPoll();
-                                    result.set(exitstatus);
-                                    return exitstatus != null;
-                                }})
-                            .run();
-                    
-                    if (!success) {
-                        // Timed out
-                        String msg = "Timeout for async script to complete on "+SshjTool.this.toString()+" ("+getSummary()+")";
-                        LOG.warn(msg+"; rethrowing");
-                        throw new TimeoutException(msg);
-                    }
-                    
-                    return result.get();
-                    
-                } catch (Exception e) {
-                    LOG.debug("Problem polling for async script on "+SshjTool.this.toString()+" (for "+getSummary()+"); rethrowing after deleting temporary files", e);
-                    throw Exceptions.propagate(e);
-                } finally {
-                    // Delete the temporary files created (and the `tail -c` commands that might have been left behind by long-polls).
-                    // Using pollTimeout so doesn't wait forever, but waits for a reasonable (configurable) length of time.
-                    // TODO also execute this if the `buildRunScriptCommand` fails, as that might have left files behind?
-                    try {
-                        int execDeleteResult = asInt(acquire(new ShellAction(deleteTemporaryFilesCommand(), out, err, pollTimeout)), -1);
-                        if (execDeleteResult != 0) {
-                            LOG.debug("Problem deleting temporary files of async script on "+SshjTool.this.toString()+" (for "+getSummary()+"): exit status "+execDeleteResult);
-                        }
-                    } catch (Exception e) {
-                        Exceptions.propagateIfFatal(e);
-                        LOG.debug("Problem deleting temporary files of async script on "+SshjTool.this.toString()+" (for "+getSummary()+"); continuing", e);
-                    }
-                }
-            }
-            
-            Integer longPoll() throws IOException {
-                // Long-polling to get stdout, stderr + exit status of async task.
-                // If our long-poll disconnects, we will just re-execute.
-                // We wrap the stdout/stderr so that we can get the size count. 
-                // If we disconnect, we will pick up from that char of the stream.
-                // TODO Additional stdout/stderr written by buildLongPollCommand() could interfere, 
-                //      causing us to miss some characters.
-                Duration nextPollTimeout = Duration.min(pollTimeout, Duration.millis(execTimeout.toMilliseconds()-timer.elapsed(TimeUnit.MILLISECONDS)));
-                CountingOutputStream countingOut = (out == null) ? null : new CountingOutputStream(out);
-                CountingOutputStream countingErr = (err == null) ? null : new CountingOutputStream(err);
-                List<String> pollCommand = buildLongPollCommand(stdoutCount, stderrCount, nextPollTimeout);
-                Duration sshJoinTimeout = nextPollTimeout.add(Duration.TEN_SECONDS);
-                ShellAction action = new ShellAction(pollCommand, countingOut, countingErr, sshJoinTimeout);
-                
-                int longPollResult;
-                try {
-                    longPollResult = asInt(acquire(action, 3, nextPollTimeout), -1);
-                } catch (RuntimeTimeoutException e) {
-                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll timed out on "+SshjTool.this.toString()+" (for "+getSummary()+"): "+e);
-                    return null;
-                }
-                stdoutCount += (countingOut == null) ? 0 : countingOut.getCount();
-                stderrCount += (countingErr == null) ? 0 : countingErr.getCount();
-                
-                if (longPollResult == 0) {
-                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll succeeded (exit status 0) on "+SshjTool.this.toString()+" (for "+getSummary()+")");
-                    return longPollResult; // success
-                    
-                } else if (longPollResult == -1) {
-                    // probably a connection failure; try again
-                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll received exit status -1; will retry on "+SshjTool.this.toString()+" (for "+getSummary()+")");
-                    return null;
-
-                } else if (longPollResult == 125) {
-                    // 125 is the special code for timeout in long-poll (see buildLongPollCommand).
-                    // However, there is a tiny chance that the underlying command might have returned that exact exit code!
-                    // Don't treat a timeout as a "consecutiveSshFailure".
-                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll received exit status "+longPollResult+"; most likely timeout; retrieving actual status on "+SshjTool.this.toString()+" (for "+getSummary()+")");
-                    return retrieveStatusCommand();
-
-                } else {
-                    // want to double-check whether this is the exit-code from the async process, or
-                    // some unexpected failure in our long-poll command.
-                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll received exit status "+longPollResult+"; retrieving actual status on "+SshjTool.this.toString()+" (for "+getSummary()+")");
-                    Integer result = retrieveStatusCommand();
-                    if (result != null) {
-                        return result;
-                    }
-                }
-                    
-                consecutiveSshFailures++;
-                if (consecutiveSshFailures > maxConsecutiveSshFailures) {
-                    LOG.warn("Aborting on "+consecutiveSshFailures+" consecutive ssh connection errors (return -1) when polling for async script to complete on "+SshjTool.this.toString()+" ("+getSummary()+")");
-                    return -1;
-                } else {
-                    LOG.info("Retrying after ssh connection error when polling for async script to complete on "+SshjTool.this.toString()+" ("+getSummary()+")");
-                    return null;
-                }
-            }
-            
-            Integer retrieveStatusCommand() throws IOException {
-                // want to double-check whether this is the exit-code from the async process, or
-                // some unexpected failure in our long-poll command.
-                ByteArrayOutputStream statusOut = new ByteArrayOutputStream();
-                ByteArrayOutputStream statusErr = new ByteArrayOutputStream();
-                int statusResult = asInt(acquire(new ShellAction(buildRetrieveStatusCommand(), statusOut, statusErr, execTimeout)), -1);
-                
-                if (statusResult == 0) {
-                    // The status we retrieved really is valid; return it.
-                    // TODO How to ensure no additional output in stdout/stderr when parsing below?
-                    String statusOutStr = new String(statusOut.toByteArray()).trim();
-                    if (Strings.isEmpty(statusOutStr)) {
-                        // suggests not yet completed; will retry with long-poll
-                        if (LOG.isDebugEnabled()) LOG.debug("Long-poll retrieved status directly; command successful but no result available on "+SshjTool.this.toString()+" (for "+getSummary()+")");
-                        return null;
-                    } else {
-                        if (LOG.isDebugEnabled()) LOG.debug("Long-poll retrieved status directly; returning '"+statusOutStr+"' on "+SshjTool.this.toString()+" (for "+getSummary()+")");
-                        int result = Integer.parseInt(statusOutStr);
-                        return result;
-                    }
-
-                } else if (statusResult == -1) {
-                    // probably a connection failure; try again with long-poll
-                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll retrieving status directly received exit status -1; will retry on "+SshjTool.this.toString()+" (for "+getSummary()+")");
-                    return null;
-                    
-                } else {
-                    if (out != null) {
-                        out.write(toUTF8ByteArray("retrieving status failed with exit code "+statusResult+" (stdout follow)"));
-                        out.write(statusOut.toByteArray());
-                    }
-                    if (err != null) {
-                        err.write(toUTF8ByteArray("retrieving status failed with exit code "+statusResult+" (stderr follow)"));
-                        err.write(statusErr.toByteArray());
-                    }
-                    
-                    if (LOG.isDebugEnabled()) LOG.debug("Long-poll retrieving status failed; returning "+statusResult+" on "+SshjTool.this.toString()+" (for "+getSummary()+")");
-                    return statusResult;
-                }
-            }
-        }.run();
-    }
-    
-    public int execShellDirect(Map<String,?> props, List<String> commands, Map<String,?> env) {
-        OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
-        OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
-        Duration execTimeout = getOptionalVal(props, PROP_EXEC_TIMEOUT);
-        
-        List<String> cmdSequence = toCommandSequence(commands, env);
-        List<String> allcmds = ImmutableList.<String>builder()
-                .add(getOptionalVal(props, PROP_DIRECT_HEADER))
-                .addAll(cmdSequence)
-                .add("exit $?")
-                .build();
-        
-        if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {}: {}", host, allcmds);
-        
-        Integer result = acquire(new ShellAction(allcmds, out, err, execTimeout));
-        if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} completed: return status {}", host, result);
-        return asInt(result, -1);
-    }
-
-    @Override
-    public int execCommands(Map<String,?> props, List<String> commands, Map<String,?> env) {
-        if (Boolean.FALSE.equals(props.get("blocks"))) {
-            throw new IllegalArgumentException("Cannot exec non-blocking: command="+commands);
-        }
-        
-        // If async is set, then do it as execScript
-        Boolean execAsync = getOptionalVal(props, PROP_EXEC_ASYNC);
-        if (Boolean.TRUE.equals(execAsync) && BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC)) {
-            return execScriptAsyncAndPoll(props, commands, env);
-        }
-
-        OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
-        OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
-        String separator = getOptionalVal(props, PROP_SEPARATOR);
-        Duration execTimeout = getOptionalVal(props, PROP_EXEC_TIMEOUT);
-
-        List<String> allcmds = toCommandSequence(commands, env);
-        String singlecmd = Joiner.on(separator).join(allcmds);
-
-        if (Boolean.TRUE.equals(getOptionalVal(props, PROP_RUN_AS_ROOT))) {
-            LOG.warn("Cannot run as root when executing as command; run as a script instead (will run as normal user): "+singlecmd);
-        }
-        
-        if (LOG.isTraceEnabled()) LOG.trace("Running command at {}: {}", host, singlecmd);
-        
-        Command result = acquire(new ExecAction(singlecmd, out, err, execTimeout));
-        if (LOG.isTraceEnabled()) LOG.trace("Running command at {} completed: exit code {}", host, result.getExitStatus());
-        // can be null if no exit status is received (observed on kill `ps aux | grep thing-to-grep-for | awk {print $2}`
-        if (result.getExitStatus()==null) LOG.warn("Null exit status running at {}: {}", host, singlecmd);
-        
-        return asInt(result.getExitStatus(), -1);
-    }
-
-    protected void checkConnected() {
-        if (!isConnected()) {
-            throw new IllegalStateException(String.format("(%s) ssh not connected!", toString()));
-        }
-    }
-
-    protected void backoffForAttempt(int retryAttempt, String message) {
-        backoffLimitedRetryHandler.imposeBackoffExponentialDelay(retryAttempt, message);
-    }
-
-    protected <T, C extends SshAction<T>> T acquire(C action) {
-        return acquire(action, sshTries, sshTriesTimeout == 0 ? Duration.PRACTICALLY_FOREVER : Duration.millis(sshTriesTimeout));
-    }
-    
-    protected <T, C extends SshAction<T>> T acquire(C action, int sshTries, Duration sshTriesTimeout) {
-        Stopwatch stopwatch = Stopwatch.createStarted();
-        
-        for (int i = 0; i < sshTries; i++) {
-            try {
-                action.clear();
-                if (LOG.isTraceEnabled()) LOG.trace(">> ({}) acquiring {}", toString(), action);
-                Stopwatch perfStopwatch = Stopwatch.createStarted();
-                
-                T returnVal;
-                try {
-                    returnVal = action.create();
-                } catch (AssertionError e) {
-                    /*
-                     * TODO In net.schmizz.sshj.SSHClient.auth(SSHClient.java:204) throws AssertionError
-                     * if not connected. This can happen if another thread has called disconnect
-                     * concurrently. This is changed in sshj v0.9.0 to instead throw an IllegalStateException.
-                     * 
-                     * For now, we'll retry. See "TODO" at top of class about synchronization.
-                     */
-                    throw new IllegalStateException("Problem in "+toString()+" for "+action, e);
-                }
-                
-                if (LOG.isTraceEnabled()) LOG.trace("<< ({}) acquired {}", toString(), returnVal);
-                if (LOG.isTraceEnabled()) LOG.trace("SSH Performance: {} {} took {}", new Object[] {
-                        sshClientConnection.getHostAndPort(), 
-                        action.getClass().getSimpleName() != null ? action.getClass().getSimpleName() : action, 
-                        Time.makeTimeStringRounded(perfStopwatch)});
-                return returnVal;
-            } catch (Exception e) {
-                // uninformative net.schmizz.sshj.connection.ConnectionException: 
-                //    Request failed (reason=UNKNOWN) may mean remote Subsytem is disabled (e.g. for FTP)
-                // if key is missing, get a UserAuth error
-                String errorMessage = String.format("(%s) error acquiring %s", toString(), action);
-                String fullMessage = String.format("%s (attempt %s/%s, in time %s/%s)", 
-                        errorMessage, (i+1), sshTries, Time.makeTimeStringRounded(stopwatch.elapsed(TimeUnit.MILLISECONDS)), 
-                        (sshTriesTimeout.equals(Duration.PRACTICALLY_FOREVER) ? "unlimited" : Time.makeTimeStringRounded(sshTriesTimeout)));
-                try {
-                    disconnect();
-                } catch (Exception e2) {
-                    LOG.debug("<< ("+toString()+") error closing connection: "+e+" / "+e2, e);
-                }
-                if (i + 1 == sshTries) {
-                    LOG.debug("<< {} (rethrowing, out of retries): {}", fullMessage, e.getMessage());
-                    throw propagate(e, fullMessage + "; out of retries");
-                } else if (sshTriesTimeout.isShorterThan(stopwatch)) {
-                    LOG.debug("<< {} (rethrowing, out of time - max {}): {}", new Object[] { fullMessage, Time.makeTimeStringRounded(sshTriesTimeout), e.getMessage() });
-                    throw new RuntimeTimeoutException(fullMessage + "; out of time", e);
-                } else {
-                    if (LOG.isDebugEnabled()) LOG.debug("<< {}: {}", fullMessage, e.getMessage());
-                    backoffForAttempt(i + 1, errorMessage + ": " + e.getMessage());
-                    if (action != sshClientConnection)
-                        connect();
-                    continue;
-                }
-            }
-        }
-        assert false : "should not reach here";
-        return null;
-    }
-
-    private final SshAction<SFTPClient> sftpConnection = new SshAction<SFTPClient>() {
-
-        private SFTPClient sftp;
-
-        @Override
-        public void clear() {
-            closeWhispering(sftp, this);
-            sftp = null;
-        }
-
-        @Override
-        public SFTPClient create() throws IOException {
-            checkConnected();
-            sftp = sshClientConnection.ssh.newSFTPClient();
-            return sftp;
-        }
-
-        @Override
-        public String toString() {
-            return "SFTPClient()";
-        }
-    };
-
-    private class GetFileAction implements SshAction<InputStream> {
-        private final String path;
-        private SFTPClient sftp;
-
-        GetFileAction(String path) {
-            this.path = checkNotNull(path, "path");
-        }
-
-        @Override
-        public void clear() throws IOException {
-            closeWhispering(sftp, this);
-            sftp = null;
-        }
-
-        @Override
-        public InputStream create() throws Exception {
-            sftp = acquire(sftpConnection);
-            return new CloseFtpChannelOnCloseInputStream(
-                    sftp.getSFTPEngine().open(path).getInputStream(), sftp);
-        }
-
-        @Override
-        public String toString() {
-            return "Payload(path=[" + path + "])";
-        }
-    }
-
-    private class PutFileAction implements SshAction<Void> {
-        // TODO support backup as a property?
-        
-        private SFTPClient sftp;
-        private final String path;
-        private final int permissionsMask;
-        private final long lastModificationDate;
-        private final long lastAccessDate;
-        private final int uid;
-        private final Supplier<InputStream> contentsSupplier;
-        private final Integer length;
-        
-        PutFileAction(Map<String,?> props, String path, Supplier<InputStream> contentsSupplier, long length) {
-            String permissions = getOptionalVal(props, PROP_PERMISSIONS);
-            long lastModificationDateVal = getOptionalVal(props, PROP_LAST_MODIFICATION_DATE);
-            long lastAccessDateVal = getOptionalVal(props, PROP_LAST_ACCESS_DATE);
-            if (lastAccessDateVal <= 0 ^ lastModificationDateVal <= 0) {
-                lastAccessDateVal = Math.max(lastAccessDateVal, lastModificationDateVal);
-                lastModificationDateVal = Math.max(lastAccessDateVal, lastModificationDateVal);
-            }
-            this.permissionsMask = Integer.parseInt(permissions, 8);
-            this.lastAccessDate = lastAccessDateVal;
-            this.lastModificationDate = lastModificationDateVal;
-            this.uid = getOptionalVal(props, PROP_OWNER_UID);
-            this.path = checkNotNull(path, "path");
-            this.contentsSupplier = checkNotNull(contentsSupplier, "contents");
-            this.length = Ints.checkedCast(checkNotNull((long)length, "size"));
-        }
-
-        @Override
-        public void clear() {
-            closeWhispering(sftp, this);
-            sftp = null;
-        }
-
-        @Override
-        public Void create() throws Exception {
-            final AtomicReference<InputStream> inputStreamRef = new AtomicReference<InputStream>();
-            sftp = acquire(sftpConnection);
-            try {
-                sftp.put(new InMemorySourceFile() {
-                    @Override public String getName() {
-                        return path;
-                    }
-                    @Override public long getLength() {
-                        return length;
-                    }
-                    @Override public InputStream getInputStream() throws IOException {
-                        InputStream contents = contentsSupplier.get();
-                        inputStreamRef.set(contents);
-                        return contents;
-                    }
-                }, path);
-                sftp.chmod(path, permissionsMask);
-                if (uid != -1) {
-                    sftp.chown(path, uid);
-                }
-                if (lastAccessDate > 0) {
-                    sftp.setattr(path, new FileAttributes.Builder()
-                            .withAtimeMtime(lastAccessDate, lastModificationDate)
-                            .build());
-                }
-            } finally {
-                closeWhispering(inputStreamRef.get(), this);
-            }
-            return null;
-        }
-
-        @Override
-        public String toString() {
-            return "Put(path=[" + path + " "+length+"])";
-        }
-    }
-
-    // TODO simpler not to use predicates
-    @VisibleForTesting
-    Predicate<String> causalChainHasMessageContaining(final Exception from) {
-        return new Predicate<String>() {
-            @Override
-            public boolean apply(final String input) {
-                return any(getCausalChain(from), new Predicate<Throwable>() {
-                    @Override
-                    public boolean apply(Throwable throwable) {
-                        return (throwable.toString().contains(input))
-                                || (throwable.getMessage() != null && throwable.getMessage().contains(input));
-                    }
-                });
-            }
-        };
-    }
-    
-    protected SshAction<Session> newSessionAction() {
-
-        return new SshAction<Session>() {
-
-            private Session session = null;
-
-            @Override
-            public void clear() throws TransportException, ConnectionException {
-                closeWhispering(session, this);
-                session = null;
-            }
-
-            @Override
-            public Session create() throws Exception {
-                checkConnected();
-                session = sshClientConnection.ssh.startSession();
-                if (allocatePTY) {
-                    session.allocatePTY(TERM, 80, 24, 0, 0, Collections.<PTYMode, Integer> emptyMap());
-                }
-                return session;
-            }
-
-            @Override
-            public String toString() {
-                return "Session()";
-            }
-        };
-
-    }
-
-    class ExecAction implements SshAction<Command> {
-        private final String command;
-        private final OutputStream out;
-        private final OutputStream err;
-        private final Duration timeout;
-        
-        private Session session;
-        private Shell shell;
-        private StreamGobbler outgobbler;
-        private StreamGobbler errgobbler;
-        
-        ExecAction(String command, OutputStream out, OutputStream err, Duration timeout) {
-            this.command = checkNotNull(command, "command");
-            this.out = out;
-            this.err = err;
-            Duration sessionTimeout = (sshClientConnection.getSessionTimeout() == 0) 
-                    ? Duration.PRACTICALLY_FOREVER 
-                    : Duration.millis(sshClientConnection.getSessionTimeout());
-            this.timeout = (timeout == null) ? sessionTimeout : Duration.min(timeout, sessionTimeout);
-        }
-
-        @Override
-        public void clear() throws TransportException, ConnectionException {
-            closeWhispering(session, this);
-            closeWhispering(shell, this);
-            closeWhispering(outgobbler, this);
-            closeWhispering(errgobbler, this);
-            session = null;
-            shell = null;
-        }
-
-        @Override
-        public Command create() throws Exception {
-            try {
-                session = acquire(newSessionAction());
-                
-                Command output = session.exec(checkNotNull(command, "command"));
-                
-                if (out != null) {
-                    outgobbler = new StreamGobbler(output.getInputStream(), out, (Logger)null);
-                    outgobbler.start();
-                }
-                if (err != null) {
-                    errgobbler = new StreamGobbler(output.getErrorStream(), err, (Logger)null);
-                    errgobbler.start();
-                }
-                try {
-                    output.join((int)Math.min(timeout.toMilliseconds(), Integer.MAX_VALUE), TimeUnit.MILLISECONDS);
-                    return output;
-                    
-                } finally {
-                    // wait for all stdout/stderr to have been re-directed
-                    try {
-                        // Don't use forever (i.e. 0) because BROOKLYN-106: ssh hangs
-                        long joinTimeout = 10*1000;
-                        if (outgobbler != null) outgobbler.join(joinTimeout);
-                        if (errgobbler != null) errgobbler.join(joinTimeout);
-                    } catch (InterruptedException e) {
-                        LOG.warn("Interrupted gobbling streams from ssh: "+command, e);
-                        Thread.currentThread().interrupt();
-                    }
-                }
-                
-            } finally {
-                clear();
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "Exec(command=[" + command + "])";
-        }
-    }
-
-    class ShellAction implements SshAction<Integer> {
-        @VisibleForTesting
-        final List<String> commands;
-        @VisibleForTesting
-        final OutputStream out;
-        @VisibleForTesting
-        final OutputStream err;
-        
-        private Session session;
-        private Shell shell;
-        private StreamGobbler outgobbler;
-        private StreamGobbler errgobbler;
-        private Duration timeout;
-
-        ShellAction(List<String> commands, OutputStream out, OutputStream err, Duration timeout) {
-            this.commands = checkNotNull(commands, "commands");
-            this.out = out;
-            this.err = err;
-            Duration sessionTimeout = (sshClientConnection.getSessionTimeout() == 0) 
-                    ? Duration.PRACTICALLY_FOREVER 
-                    : Duration.millis(sshClientConnection.getSessionTimeout());
-            this.timeout = (timeout == null) ? sessionTimeout : Duration.min(timeout, sessionTimeout);
-        }
-
-        @Override
-        public void clear() throws TransportException, ConnectionException {
-            closeWhispering(session, this);
-            closeWhispering(shell, this);
-            closeWhispering(outgobbler, this);
-            closeWhispering(errgobbler, this);
-            session = null;
-            shell = null;
-        }
-
-        @Override
-        public Integer create() throws Exception {
-            try {
-                session = acquire(newSessionAction());
-                
-                shell = session.startShell();
-                
-                if (out != null) {
-                    InputStream outstream = shell.getInputStream();
-                    outgobbler = new StreamGobbler(outstream, out, (Logger)null);
-                    outgobbler.start();
-                }
-                if (err != null) {
-                    InputStream errstream = shell.getErrorStream();
-                    errgobbler = new StreamGobbler(errstream, err, (Logger)null);
-                    errgobbler.start();
-                }
-                
-                OutputStream output = shell.getOutputStream();
-
-                for (CharSequence cmd : commands) {
-                    try {
-                        output.write(toUTF8ByteArray(cmd+"\n"));
-                        output.flush();
-                    } catch (ConnectionException e) {
-                        if (!shell.isOpen()) {
-                            // shell is closed; presumably the user command did `exit`
-                            if (LOG.isDebugEnabled()) LOG.debug("Shell closed to {} when executing {}", SshjTool.this.toString(), commands);
-                            break;
-                        } else {
-                            throw e;
-                        }
-                    }
-                }
-                // workaround attempt for SSHJ deadlock - https://github.com/shikhar/sshj/issues/105
-                synchronized (shell.getOutputStream()) {
-                    shell.sendEOF();
-                }
-                closeWhispering(output, this);
-                
-                boolean timedOut = false;
-                try {
-                    long timeoutMillis = Math.min(timeout.toMilliseconds(), Integer.MAX_VALUE);
-                    long timeoutEnd = System.currentTimeMillis() + timeoutMillis;
-                    Exception last = null;
-                    do {
-                        if (!shell.isOpen() && ((SessionChannel)session).getExitStatus()!=null)
-                            // shell closed, and exit status returned
-                            break;
-                        boolean endBecauseReturned =
-                            // if either condition is satisfied, then wait 1s in hopes the other does, then return
-                            (!shell.isOpen() || ((SessionChannel)session).getExitStatus()!=null);
-                        try {
-                            shell.join(1000, TimeUnit.MILLISECONDS);
-                        } catch (ConnectionException e) {
-                            last = e;
-                        }
-                        if (endBecauseReturned) {
-                            // shell is still open, ie some process is running
-                            // but we have a result code, so main shell is finished
-                            // we waited one second extra to allow any background process 
-                            // which is nohupped to really be in the background (#162)
-                            // now let's bail out
-                            break;
-                        }
-                    } while (System.currentTimeMillis() < timeoutEnd);
-                    if (shell.isOpen() && ((SessionChannel)session).getExitStatus()==null) {
-                        LOG.debug("Timeout ({}) in SSH shell to {}", timeout, this);
-                        // we timed out, or other problem -- reproduce the error.
-                        // The shell.join should always have thrown ConnectionExceptoin (looking at code of
-                        // AbstractChannel), but javadoc of Channel doesn't explicity say that so play it safe.
-                        timedOut = true;
-                        throw (last != null) ? last : new TimeoutException("Timeout after "+timeout+" executing "+this);
-                    }
-                    return ((SessionChannel)session).getExitStatus();
-                } finally {
-                    // wait for all stdout/stderr to have been re-directed
-                    closeWhispering(shell, this);
-                    shell = null;
-                    try {
-                        // Don't use forever (i.e. 0) because BROOKLYN-106: ssh hangs
-                        long joinTimeout = (timedOut) ? 1000 : 10*1000;
-                        if (outgobbler != null) {
-                            outgobbler.join(joinTimeout);
-                            outgobbler.close();
-                        }
-                        if (errgobbler != null) {
-                            errgobbler.join(joinTimeout);
-                            errgobbler.close();
-                        }
-                    } catch (InterruptedException e) {
-                        LOG.warn("Interrupted gobbling streams from ssh: "+commands, e);
-                        Thread.currentThread().interrupt();
-                    }
-                }
-                
-            } finally {
-                clear();
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "Shell(command=[" + commands + "])";
-        }
-    }
-
-    private byte[] toUTF8ByteArray(String string) {
-        return org.bouncycastle.util.Strings.toUTF8ByteArray(string);
-    }
-    
-    private Supplier<InputStream> newInputStreamSupplier(final byte[] contents) {
-        return new Supplier<InputStream>() {
-            @Override public InputStream get() {
-                return new ByteArrayInputStream(contents);
-            }
-        };
-    }
-
-    private Supplier<InputStream> newInputStreamSupplier(final File file) {
-        return new Supplier<InputStream>() {
-            @Override public InputStream get() {
-                try {
-                    return new FileInputStream(file);
-                } catch (FileNotFoundException e) {
-                    throw Exceptions.propagate(e);
-                }
-            }
-        };
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/javalang/ReflectionScanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/javalang/ReflectionScanner.java b/core/src/main/java/brooklyn/util/javalang/ReflectionScanner.java
deleted file mode 100644
index 66a5a72..0000000
--- a/core/src/main/java/brooklyn/util/javalang/ReflectionScanner.java
+++ /dev/null
@@ -1,135 +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 brooklyn.util.javalang;
-
-import java.lang.annotation.Annotation;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-
-import org.reflections.ReflectionUtils;
-import org.reflections.Reflections;
-import org.reflections.Store;
-import org.reflections.scanners.Scanner;
-import org.reflections.scanners.SubTypesScanner;
-import org.reflections.scanners.TypeAnnotationsScanner;
-import org.reflections.util.ClasspathHelper;
-import org.reflections.util.ConfigurationBuilder;
-import org.reflections.util.FilterBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-/** Facade on {@link Reflections} which logs warnings for unloadable classes but does not fail */
-public class ReflectionScanner {
-
-    private static final Logger log = LoggerFactory.getLogger(ReflectionScanner.class);
-    
-    protected final ClassLoader[] classLoaders;
-    protected final Reflections reflections;
-
-    /** scanner which will look in the given urls 
-     * (or if those are null attempt to infer from the first entry in the classloaders,
-     * although currently that seems to only pick up directories, not JAR's),
-     * optionally filtering for the given prefix;
-     * any or all arguments can be null to accept all (and use default classpath for classloading).
-     **/
-    public ReflectionScanner(
-            final Iterable<URL> urlsToScan, 
-            final String optionalPrefix,
-            final ClassLoader ...classLoaders) {
-        reflections = new Reflections(new ConfigurationBuilder() {
-            {
-                final Predicate<String> filter = 
-                        Strings.isNonEmpty(optionalPrefix) ? new FilterBuilder.Include(FilterBuilder.prefix(optionalPrefix)) : null;
-
-                if (urlsToScan!=null)
-                    setUrls(ImmutableSet.copyOf(urlsToScan));
-                else if (classLoaders.length>0 && classLoaders[0]!=null)
-                    setUrls(
-                            ClasspathHelper.forPackage(Strings.isNonEmpty(optionalPrefix) ? optionalPrefix : "",
-                                    asClassLoaderVarArgs(classLoaders[0])));
-                
-                if (filter!=null) filterInputsBy(filter);
-
-                Scanner typeScanner = new TypeAnnotationsScanner();
-                if (filter!=null) typeScanner = typeScanner.filterResultsBy(filter);
-                Scanner subTypeScanner = new SubTypesScanner();
-                if (filter!=null) subTypeScanner = subTypeScanner.filterResultsBy(filter);
-                setScanners(typeScanner, subTypeScanner);
-                
-                for (ClassLoader cl: classLoaders)
-                    if (cl!=null) addClassLoader(cl);
-            }
-        });
-        this.classLoaders = Iterables.toArray(Iterables.filter(Arrays.asList(classLoaders), Predicates.notNull()), ClassLoader.class);
-    }
-
-    private static ClassLoader[] asClassLoaderVarArgs(final ClassLoader classLoaderToSearch) {
-        return classLoaderToSearch==null ? new ClassLoader[0] : new ClassLoader[] { classLoaderToSearch };
-    }
-
-    public Store getStore() {
-        return reflections.getStore();
-    }
-    
-    /** overrides delegate so as to log rather than throw exception if a class cannot be loaded */
-    public <T> Set<Class<? extends T>> getSubTypesOf(final Class<T> type) {
-        Set<String> subTypes = getStore().getSubTypesOf(type.getName());
-        return ImmutableSet.copyOf(this.<T>forNames(subTypes, "sub-type of "+type));
-    }
-    
-    /** overrides delegate so as to log rather than throw exception if a class cannot be loaded */
-    public Set<Class<?>> getTypesAnnotatedWith(Class<? extends Annotation> annotation) {
-        Set<String> annotatedWith = getStore().getTypesAnnotatedWith(annotation.getName());
-        return ImmutableSet.copyOf(this.forNames(annotatedWith, "annotated "+annotation.getName()));
-    }
-
-    @SuppressWarnings("unchecked")
-    protected <T> List<Class<? extends T>> forNames(Set<String> classNames, final String context) {
-        List<Class<? extends T>> result = new ArrayList<Class<? extends T>>();
-        for (String className : classNames) {
-            //noinspection unchecked
-            try {
-                Class<? extends T> clazz = (Class<? extends T>) loadClass(className);
-                if (clazz != null) {
-                    result.add(clazz);
-                } else {
-                    log.warn("Unable to instantiate '"+className+"' ("+context+")");
-                }
-            } catch (Throwable e) {
-                log.warn("Unable to instantiate '"+className+"' ("+context+"): "+e);
-            }
-        }
-        return result;
-    }
-    
-    protected Class<?> loadClass(String className) {
-        return ReflectionUtils.forName(className, classLoaders);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/javalang/UrlClassLoader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/javalang/UrlClassLoader.java b/core/src/main/java/brooklyn/util/javalang/UrlClassLoader.java
deleted file mode 100644
index d847174..0000000
--- a/core/src/main/java/brooklyn/util/javalang/UrlClassLoader.java
+++ /dev/null
@@ -1,69 +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 brooklyn.util.javalang;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.Arrays;
-
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.exceptions.Exceptions;
-
-/** like URLClassLoader (and delegates to it) but:
- * * has a nice toString
- * * supports var args constructor
- * * supports file://~/xxx semantics (remaps it to user.home); 
- *      ideally we'd also support mvn, classpath, osgi, etc
- */
-public class UrlClassLoader extends URLClassLoader {
-
-    private URL[] urls;
-
-    public UrlClassLoader(URL ...urls) {
-        super(tidy(urls));
-        this.urls = urls;
-    }
-
-    public UrlClassLoader(String ...urls) {
-        this(asUrls(urls));
-    }
-    
-    private static URL[] asUrls(String[] urls) {
-        URL[] urlo = new URL[urls.length];
-        try {
-        for (int i=0; i<urls.length; i++)
-            urlo[i] = new URL(urls[i]);
-        } catch (MalformedURLException e) {
-            throw Exceptions.propagate(e);
-        }
-        return urlo;
-    }
-
-    private static URL[] tidy(URL[] urls) {
-        for (int i=0; i<urls.length; i++)
-            urls[i] = ResourceUtils.tidy(urls[i]);
-        return urls;
-    }
-
-    @Override
-    public String toString() {
-        return "UrlClassLoader"+Arrays.asList(urls);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/mutex/MutexSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/mutex/MutexSupport.java b/core/src/main/java/brooklyn/util/mutex/MutexSupport.java
deleted file mode 100644
index c0794cf..0000000
--- a/core/src/main/java/brooklyn/util/mutex/MutexSupport.java
+++ /dev/null
@@ -1,120 +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 brooklyn.util.mutex;
-
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.task.Tasks;
-
-import com.google.common.collect.ImmutableMap;
-
-public class MutexSupport implements WithMutexes {
-
-    private static final Logger log = LoggerFactory.getLogger(MutexSupport.class);
-    private final Map<String,SemaphoreWithOwners> semaphores = new LinkedHashMap<String,SemaphoreWithOwners>();
-
-    protected synchronized SemaphoreWithOwners getSemaphore(String mutexId) {
-        return getSemaphore(mutexId, false);
-    }
-    // NB: the map could be "lock-striped" (hashed on mutexId) to avoid the central lock 
-    protected synchronized SemaphoreWithOwners getSemaphore(String mutexId, boolean requestBeforeReturning) {
-        SemaphoreWithOwners s = semaphores.get(mutexId);
-        if (s==null) {
-            s = new SemaphoreWithOwners(mutexId);
-            semaphores.put(mutexId, s);
-        }
-        if (requestBeforeReturning) s.indicateCallingThreadWillRequest();
-        return s;
-    }
-    /** forces deletion of the given mutex if it is unused; 
-     * normally not required as is done automatically on close
-     * (but possibly needed where there are cancelations and risk of memory leaks) */
-    public synchronized void cleanupMutex(String mutexId) {
-        SemaphoreWithOwners s = semaphores.get(mutexId);
-        if (!s.isInUse()) semaphores.remove(mutexId);
-    }
-    public synchronized void cleanup() {
-        Iterator<SemaphoreWithOwners> si = semaphores.values().iterator();
-        while (si.hasNext()) {
-            SemaphoreWithOwners s = si.next();
-            if (!s.isInUse()) si.remove();
-        }
-    }
-
-    @Override
-    public synchronized boolean hasMutex(String mutexId) {
-        SemaphoreWithOwners s = semaphores.get(mutexId);
-        if (s!=null) return s.isCallingThreadAnOwner();
-        return false;
-    }
-    
-    @Override
-    public void acquireMutex(String mutexId, String description) throws InterruptedException {
-        SemaphoreWithOwners s = getSemaphore(mutexId, true);
-        if (description!=null) Tasks.setBlockingDetails(description+" - waiting for "+mutexId);
-        if (log.isDebugEnabled())
-            log.debug("Acquiring mutex: "+mutexId+"@"+this+" - "+description);
-        s.acquire(); 
-        if (description!=null) Tasks.setBlockingDetails(null);
-        s.setDescription(description);
-        if (log.isDebugEnabled())
-            log.debug("Acquired mutex: "+mutexId+"@"+this+" - "+description);
-    }
-
-    @Override
-    public boolean tryAcquireMutex(String mutexId, String description) {
-        SemaphoreWithOwners s = getSemaphore(mutexId, true);
-        if (s.tryAcquire()) {
-            if (log.isDebugEnabled())
-                log.debug("Acquired mutex (opportunistic): "+mutexId+"@"+this+" - "+description);
-            s.setDescription(description);
-            return true;
-        }
-        return false;
-    }
-
-    @Override
-    public synchronized void releaseMutex(String mutexId) {
-        SemaphoreWithOwners s;
-        if (log.isDebugEnabled())
-            log.debug("Releasing mutex: "+mutexId+"@"+this);
-        synchronized (this) { s = semaphores.get(mutexId); }
-        if (s==null) throw new IllegalStateException("No mutex known for '"+mutexId+"'");
-        s.release();
-        cleanupMutex(mutexId);
-    }
-    
-    @Override
-    public synchronized String toString() {
-        return super.toString()+"["+semaphores.size()+" semaphores: "+semaphores.values()+"]";
-    }
-    
-    /** Returns the semaphores in use at the time the method is called, for inspection purposes (and testing).
-     * The semaphores used by this class may change over time so callers are strongly discouraged
-     * from manipulating the semaphore objects themselves. 
-     */
-    public synchronized Map<String,SemaphoreWithOwners> getAllSemaphores() {
-        return ImmutableMap.<String,SemaphoreWithOwners>copyOf(semaphores);
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/mutex/SemaphoreForTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/mutex/SemaphoreForTasks.java b/core/src/main/java/brooklyn/util/mutex/SemaphoreForTasks.java
deleted file mode 100644
index 5bdfdfa..0000000
--- a/core/src/main/java/brooklyn/util/mutex/SemaphoreForTasks.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 brooklyn.util.mutex;
-
-import java.util.List;
-import java.util.Set;
-
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.apache.brooklyn.api.management.Task;
-
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableSet;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-
-/** A subclass of {@link SemaphoreWithOwners} 
- * which additionally sets Task blocking information. 
- * <p>
- * TODO As tasks are distributed this should support distribution across the management context. */
-public class SemaphoreForTasks extends SemaphoreWithOwners {
-    
-    private static final long serialVersionUID = 7898283056223005952L;
-    
-    /** unused at present, but wanted on the API for when this may be federated */
-    @SuppressWarnings("unused")
-    private final ManagementContext mgmt;
-    
-    final private MutableList<Task<?>> owningTasks = new MutableList<Task<?>>();
-    final private MutableSet<Task<?>> requestingTasks = new MutableSet<Task<?>>();
-
-    public SemaphoreForTasks(String name, ManagementContext mgmt) {
-        super(name);
-        this.mgmt = Preconditions.checkNotNull(mgmt);
-    }
-    
-    public SemaphoreForTasks(String name, int permits, boolean fair, ManagementContext mgmt) {
-        super(name, permits, fair);
-        this.mgmt = Preconditions.checkNotNull(mgmt);
-    }
-    
-    public synchronized Set<Task<?>> getRequestingTasks() {
-        return ImmutableSet.copyOf(requestingTasks);
-    }
-    
-    public synchronized List<Task<?>> getOwningTasks() {
-        return ImmutableList.copyOf(owningTasks);
-    }
-
-    @Override
-    protected synchronized void onRequesting() {
-        if (!owningTasks.isEmpty() || !requestingTasks.isEmpty()) {
-            Tasks.setBlockingTask( !requestingTasks.isEmpty() ? Iterables.getLast(requestingTasks) : Iterables.getFirst(owningTasks, null) );
-            Tasks.setBlockingDetails("Waiting on semaphore "+getName()+" ("+getDescription()+"); "
-                + "queued at "+Time.makeDateString()+" when "+getRequestingThreads().size()+" ahead in queue");
-        }
-        requestingTasks.addIfNotNull(Tasks.current());
-        super.onRequesting();
-    }
-    
-    @Override
-    protected synchronized void onRequestFinished() {
-        super.onRequestFinished();
-        requestingTasks.removeIfNotNull(Tasks.current());
-        
-        Tasks.resetBlockingDetails();
-        Tasks.resetBlockingTask();
-    }
-    
-    @Override
-    protected synchronized void onAcquired(int permits) {
-        super.onAcquired(permits);
-        for (int i=0; i<permits; i++)
-            owningTasks.appendIfNotNull(Tasks.current());
-    }
-    
-    @Override
-    protected synchronized void onReleased(int permits) {
-        super.onReleased(permits);
-        for (int i=0; i<permits; i++)
-            owningTasks.removeIfNotNull(Tasks.current());
-    }
-    
-    @Override
-    public synchronized String toString() {
-        return super.toString()+"["
-            + "owningTasks="+owningTasks
-            + "; requestingTasks="+requestingTasks+"]";
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/mutex/SemaphoreWithOwners.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/mutex/SemaphoreWithOwners.java b/core/src/main/java/brooklyn/util/mutex/SemaphoreWithOwners.java
deleted file mode 100644
index 6f3132c..0000000
--- a/core/src/main/java/brooklyn/util/mutex/SemaphoreWithOwners.java
+++ /dev/null
@@ -1,231 +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 brooklyn.util.mutex;
-
-import java.util.ArrayList;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-import brooklyn.util.exceptions.Exceptions;
-
-import com.google.common.collect.ImmutableList;
-
-/** a subclass of {@link Semaphore} 
- * which tracks who created and released the semaphores,
- * and which requires the same thread to release as created it. */
-public class SemaphoreWithOwners extends Semaphore {
-    public SemaphoreWithOwners(String name) {
-        this(name, 1, true);
-    }
-    public SemaphoreWithOwners(String name, int permits, boolean fair) {
-        super(permits, fair);
-        this.name = name;
-    }
-    private static final long serialVersionUID = -5303474637353009454L;
-    final private List<Thread> owningThreads = new ArrayList<Thread>();
-    final private Set<Thread> requestingThreads = new LinkedHashSet<Thread>();
-    
-    @Override
-    public void acquire() throws InterruptedException {
-        try {
-            onRequesting();
-            super.acquire();
-            onAcquired(1);
-        } finally {
-            onRequestFinished();
-        }
-    }
-    @Override
-    public void acquire(int permits) throws InterruptedException {
-        try {
-            onRequesting();
-            super.acquire(permits);
-            onAcquired(permits);
-        } finally {
-            onRequestFinished();
-        }
-    }
-    @Override
-    public void acquireUninterruptibly() {
-        try {
-            onRequesting();
-            super.acquireUninterruptibly();
-            onAcquired(1);
-        } finally {
-            onRequestFinished();
-        }
-    }
-    @Override
-    public void acquireUninterruptibly(int permits) {
-        try {
-            onRequesting();
-            super.acquireUninterruptibly(permits);
-            onAcquired(permits);
-        } finally {
-            onRequestFinished();
-        }
-    }
-
-    public void acquireUnchecked() {
-        try {
-            acquire();
-        } catch (InterruptedException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    public void acquireUnchecked(int numPermits) {
-        try {
-            acquire(numPermits);
-        } catch (InterruptedException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    
-    @Override
-    public boolean tryAcquire() {
-        try {
-            onRequesting();
-            if (super.tryAcquire()) {
-                onAcquired(1);
-                return true;
-            }
-            return false;
-        } finally {
-            onRequestFinished();
-        }
-    }
-    @Override
-    public boolean tryAcquire(int permits) {
-        try {
-            onRequesting();
-            if (super.tryAcquire(permits)) {
-                onAcquired(permits);
-                return true;
-            }
-            return false;
-        } finally {
-            onRequestFinished();
-        }
-    }
-    @Override
-    public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException {
-        try {
-            onRequesting();
-            if (super.tryAcquire(permits, timeout, unit)) {
-                onAcquired(permits);
-                return true;
-            }
-            return false;
-        } finally {
-            onRequestFinished();
-        }
-    }
-    @Override
-    public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException {
-        try {
-            onRequesting();
-            if (super.tryAcquire(timeout, unit)) {
-                onAcquired(1);
-                return true;
-            }
-            return false;
-        } finally {
-            onRequestFinished();
-        }
-    }
-
-    /** invoked when a caller successfully acquires a mutex, before {@link #onRequestFinished()} */
-    protected synchronized void onAcquired(int permits) {
-        for (int i=0; i<permits; i++) owningThreads.add(Thread.currentThread());
-    }
-    /** invoked when a caller is about to request a semaphore (before it might block);
-     * guaranteed to call {@link #onRequestFinished()} after the blocking,
-     * with a call to {@link #onAcquired(int)} beforehand if the acquisition was successful */
-    protected synchronized void onRequesting() {
-        requestingThreads.add(Thread.currentThread());
-    }
-    /** invoked when a caller has completed requesting a mutex, whether successful, aborted, or interrupted */
-    protected synchronized void onRequestFinished() {
-        requestingThreads.remove(Thread.currentThread());
-    }
-
-    @Override
-    public void release() {
-        super.release();
-        onReleased(1);
-    }
-    @Override
-    public void release(int permits) {
-        super.release(permits);
-        onReleased(permits);
-    }
-
-    /** invoked when a caller has released permits */
-    protected synchronized void onReleased(int permits) {
-        boolean result = true;
-        for (int i=0; i<permits; i++) result = owningThreads.remove(Thread.currentThread()) & result;
-        if (!result) throw new IllegalStateException("Thread "+Thread.currentThread()+" which released "+this+" did not own it.");  
-    }
-
-    /** true iff there are any owners or any requesters (callers blocked trying to acquire) */
-    public synchronized boolean isInUse() {
-        return !owningThreads.isEmpty() || !requestingThreads.isEmpty();
-    }
-
-    /** true iff the calling thread is one of the owners */ 
-    public synchronized boolean isCallingThreadAnOwner() {
-        return owningThreads.contains(Thread.currentThread());
-    }
-
-    private final String name;
-    /** constructor-time supplied name */
-    public String getName() { return name; }
-
-    private String description;
-    public void setDescription(String description) { this.description = description; }
-    /** caller supplied description */
-    public String getDescription() { return description; }
-
-    /** unmodifiable view of threads owning the permits; threads with multiple permits listed multiply */
-    public synchronized List<Thread> getOwningThreads() {
-        return ImmutableList.<Thread>copyOf(owningThreads);
-    }
-    /** unmodifiable view of threads requesting access (blocked or briefly trying to acquire);
-     * this is guaranteed to be cleared _after_ getOwners 
-     * (synchronizing on this class while reading both fields will give canonical access) */
-    public synchronized List<Thread> getRequestingThreads() {
-        return ImmutableList.<Thread>copyOf(requestingThreads);
-    }
-    
-    @Override
-    public synchronized String toString() {
-        return super.toString()+"["+name+"; description="+description+"; owning="+owningThreads+"; requesting="+requestingThreads+"]";
-    }
-    
-    /** Indicate that the calling thread is going to acquire or tryAcquire, 
-     * in order to set up the semaphore's isInUse() value appropriately for certain checks.
-     * It *must* do so after invoking this method. */ 
-    public void indicateCallingThreadWillRequest() {
-        requestingThreads.add(Thread.currentThread());
-    }
-    
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/mutex/WithMutexes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/mutex/WithMutexes.java b/core/src/main/java/brooklyn/util/mutex/WithMutexes.java
deleted file mode 100644
index e772df8..0000000
--- a/core/src/main/java/brooklyn/util/mutex/WithMutexes.java
+++ /dev/null
@@ -1,45 +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 brooklyn.util.mutex;
-
-/** interface which allows multiple callers to co-operate using named mutexes, inspectably,
- * and containing implementation as inner class
- * <p>
- * MutexSupport is a common implementation of this.
- * mixin code frequently delegates to this, 
- * as shown in the test case's WithMutexesTest.SampleWithMutexesDelegatingMixin class 
- **/
-public interface WithMutexes {
-
-    /** returns true if the calling thread has the mutex with the given ID */
-    public boolean hasMutex(String mutexId);
-    
-    /** acquires a mutex, if available, otherwise blocks on its becoming available;
-     * caller must release after use */
-    public void acquireMutex(String mutexId, String description) throws InterruptedException;
-
-    /** acquires a mutex and returns true, if available; otherwise immediately returns false;
-     * caller must release after use if this returns true */
-    public boolean tryAcquireMutex(String mutexId, String description);
-
-    /** releases a mutex, triggering another thread to use it or cleaning it up if no one else is waiting;
-     * this should only be called by the mutex owner (thread) */
-    public void releaseMutex(String mutexId);
-    
-}


[47/64] incubator-brooklyn git commit: brooklyn-software-messaging: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..3e4a92a
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBroker.java
@@ -0,0 +1,79 @@
+/*
+ * 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.entity.messaging.qpid;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import 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 brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Qpid broker instance, using AMQP 0-10.
+ */
+@Catalog(name="Qpid Broker", description="Apache Qpid is an open-source messaging system, implementing the Advanced Message Queuing Protocol (AMQP)", iconUrl="classpath:///qpid-logo.jpeg")
+@ImplementedBy(QpidBrokerImpl.class)
+public interface QpidBroker extends SoftwareProcess, MessageBroker, UsesJmx, AmqpServer, JMSBroker<QpidQueue, QpidTopic> {
+
+    /* Qpid runtime file locations for convenience. */
+
+    public static final String CONFIG_XML = "etc/config.xml";
+    public static final String VIRTUALHOSTS_XML = "etc/virtualhosts.xml";
+    public static final String PASSWD = "etc/passwd";
+
+    @SetFromFlag("version")
+    public static final ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "0.20");
+    
+    @SetFromFlag("downloadUrl")
+    public static final BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
+            Attributes.DOWNLOAD_URL, "http://download.nextag.com/apache/qpid/${version}/qpid-java-broker-${version}.tar.gz");
+
+    @SetFromFlag("amqpPort")
+    public static final PortAttributeSensorAndConfigKey AMQP_PORT = AmqpServer.AMQP_PORT;
+
+    @SetFromFlag("virtualHost")
+    public static final BasicAttributeSensorAndConfigKey<String> VIRTUAL_HOST_NAME = AmqpServer.VIRTUAL_HOST_NAME;
+
+    @SetFromFlag("amqpVersion")
+    public static final BasicAttributeSensorAndConfigKey<String> AMQP_VERSION = new BasicAttributeSensorAndConfigKey<String>(
+            AmqpServer.AMQP_VERSION, AmqpServer.AMQP_0_10);
+    
+    @SetFromFlag("httpManagementPort")
+    public static final PortAttributeSensorAndConfigKey HTTP_MANAGEMENT_PORT = new PortAttributeSensorAndConfigKey("qpid.http-management.port", "Qpid HTTP management plugin port");
+
+    @SetFromFlag("jmxUser")
+    public static final BasicAttributeSensorAndConfigKey<String> JMX_USER = new BasicAttributeSensorAndConfigKey<String>(
+            UsesJmx.JMX_USER, "admin");
+    
+    @SetFromFlag("jmxPassword")
+    public static final BasicAttributeSensorAndConfigKey<String> JMX_PASSWORD = new BasicAttributeSensorAndConfigKey<String>(
+            UsesJmx.JMX_PASSWORD, "admin");
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..66ff73d
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidBrokerImpl.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.entity.messaging.qpid;
+
+import static java.lang.String.format;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.java.JmxSupport;
+import org.apache.brooklyn.entity.messaging.jms.JMSBrokerImpl;
+import brooklyn.event.feed.jmx.JmxAttributePollConfig;
+import brooklyn.event.feed.jmx.JmxFeed;
+import brooklyn.event.feed.jmx.JmxHelper;
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Qpid broker instance, using AMQP 0-10.
+ */
+public class QpidBrokerImpl extends JMSBrokerImpl<QpidQueue, QpidTopic> implements QpidBroker {
+    private static final Logger log = LoggerFactory.getLogger(QpidBrokerImpl.class);
+
+    private volatile JmxFeed jmxFeed;
+
+    public QpidBrokerImpl() {
+        super();
+    }
+
+    public String getVirtualHost() { return getAttribute(VIRTUAL_HOST_NAME); }
+    public String getAmqpVersion() { return getAttribute(AMQP_VERSION); }
+    public Integer getAmqpPort() { return getAttribute(AMQP_PORT); }
+
+    public void setBrokerUrl() {
+        String urlFormat = "amqp://guest:guest@/%s?brokerlist='tcp://%s:%d'";
+        setAttribute(BROKER_URL, format(urlFormat, getAttribute(VIRTUAL_HOST_NAME), getAttribute(HOSTNAME), getAttribute(AMQP_PORT)));
+    }
+    
+    @Override
+    public void init() {
+        super.init();
+        new JmxSupport(this, null).recommendJmxRmiCustomAgent();
+    }
+
+    public void waitForServiceUp(long duration, TimeUnit units) {
+        super.waitForServiceUp(duration, units);
+
+        // Also wait for the MBean to exist (as used when creating queue/topic)
+        JmxHelper helper = new JmxHelper(this);
+        try {
+            String virtualHost = getConfig(QpidBroker.VIRTUAL_HOST_NAME);
+            ObjectName virtualHostManager = new ObjectName(format("org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=\"%s\"", virtualHost));
+            helper.connect();
+            helper.assertMBeanExistsEventually(virtualHostManager, units.toMillis(duration));
+        } catch (MalformedObjectNameException e) {
+            throw Exceptions.propagate(e);
+        } catch (IOException e) {
+            throw Exceptions.propagate(e);
+        } finally {
+            if (helper != null) helper.terminate();
+        }
+    }
+    
+    public QpidQueue createQueue(Map properties) {
+        QpidQueue result = addChild(EntitySpec.create(QpidQueue.class).configure(properties));
+        Entities.manage(result);
+        result.create();
+        return result;
+    }
+
+    public QpidTopic createTopic(Map properties) {
+        QpidTopic result = addChild(EntitySpec.create(QpidTopic.class).configure(properties));
+        Entities.manage(result);
+        result.create();
+        return result;
+    }
+
+    @Override
+    public Class getDriverInterface() {
+        return QpidDriver.class;
+    }
+
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+        String serverInfoMBeanName = "org.apache.qpid:type=ServerInformation,name=ServerInformation";
+
+        jmxFeed = JmxFeed.builder()
+                .entity(this)
+                .period(500, TimeUnit.MILLISECONDS)
+                .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP)
+                        .objectName(serverInfoMBeanName)
+                        .attributeName("ProductVersion")
+                        .onSuccess(new Function<Object,Boolean>() {
+                                private boolean hasWarnedOfVersionMismatch;
+                                @Override public Boolean apply(Object input) {
+                                    if (input == null) return false;
+                                    if (!hasWarnedOfVersionMismatch && !getConfig(QpidBroker.SUGGESTED_VERSION).equals(input)) {
+                                        log.warn("Qpid version mismatch: ProductVersion is {}, requested version is {}", input, getConfig(QpidBroker.SUGGESTED_VERSION));
+                                        hasWarnedOfVersionMismatch = true;
+                                    }
+                                    return true;
+                                }})
+                        .onException(Functions.constant(false))
+                        .suppressDuplicates(true))
+                .build();
+    }
+
+    @Override
+    public void disconnectSensors() {
+        super.disconnectSensors();
+        if (jmxFeed != null) jmxFeed.stop();
+    }
+
+    @Override
+    protected ToStringHelper toStringHelper() {
+        return super.toStringHelper().add("amqpPort", getAmqpPort());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDestination.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDestination.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDestination.java
new file mode 100644
index 0000000..a73d079
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDestination.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.entity.messaging.qpid;
+
+import org.apache.brooklyn.entity.messaging.amqp.AmqpExchange;
+import org.apache.brooklyn.entity.messaging.jms.JMSDestination;
+
+public interface QpidDestination extends JMSDestination, AmqpExchange {
+    
+    public void create();
+    
+    /**
+     * Return the AMQP name for the queue.
+     */
+    public String getQueueName();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..718ce88
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDestinationImpl.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.entity.messaging.qpid;
+
+import static java.lang.String.format;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.java.UsesJmx;
+import org.apache.brooklyn.entity.messaging.amqp.AmqpServer;
+import org.apache.brooklyn.entity.messaging.jms.JMSDestinationImpl;
+import brooklyn.event.feed.jmx.JmxFeed;
+import brooklyn.event.feed.jmx.JmxHelper;
+import brooklyn.util.exceptions.Exceptions;
+
+public abstract class QpidDestinationImpl extends JMSDestinationImpl implements QpidDestination {
+    public static final Logger log = LoggerFactory.getLogger(QpidDestination.class);
+    
+    @SetFromFlag
+    String virtualHost;
+
+    protected ObjectName virtualHostManager;
+    protected ObjectName exchange;
+    protected transient JmxHelper jmxHelper;
+    protected volatile JmxFeed jmxFeed;
+
+    public QpidDestinationImpl() {
+    }
+
+    @Override
+    public QpidBroker getParent() {
+        return (QpidBroker) super.getParent();
+    }
+    
+    @Override
+    public void onManagementStarting() {
+        super.onManagementStarting();
+        
+        // TODO Would be nice to share the JmxHelper for all destinations, so just one connection.
+        // But tricky for if brooklyn were distributed
+        try {
+            if (virtualHost == null) virtualHost = getConfig(QpidBroker.VIRTUAL_HOST_NAME);
+            setAttribute(QpidBroker.VIRTUAL_HOST_NAME, virtualHost);
+            virtualHostManager = new ObjectName(format("org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=\"%s\"", virtualHost));
+            jmxHelper = new JmxHelper((EntityLocal)getParent());
+        } catch (MalformedObjectNameException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    @Override
+    protected void disconnectSensors() {
+        if (jmxFeed != null) jmxFeed.stop();
+    }
+
+    @Override
+    public void create() {
+        jmxHelper.operation(virtualHostManager, "createNewQueue", getName(), getParent().getAttribute(UsesJmx.JMX_USER), true);
+        jmxHelper.operation(exchange, "createNewBinding", getName(), getName());
+        connectSensors();
+    }
+    
+    @Override
+    public void delete() {
+        jmxHelper.operation(exchange, "removeBinding", getName(), getName());
+        jmxHelper.operation(virtualHostManager, "deleteQueue", getName());
+        disconnectSensors();
+    }
+
+    @Override
+    public String getQueueName() {
+
+        if (AmqpServer.AMQP_0_10.equals(getParent().getAmqpVersion())) {
+            return String.format("'%s'/'%s'; { assert: never }", getExchangeName(), getName());
+        } else {
+            return getName();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDriver.java
new file mode 100644
index 0000000..46aeb09
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidDriver.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.entity.messaging.qpid;
+
+import brooklyn.entity.java.JavaSoftwareProcessDriver;
+
+public interface QpidDriver extends JavaSoftwareProcessDriver {
+
+    Integer getAmqpPort();
+
+    String getAmqpVersion();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidQueue.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidQueue.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidQueue.java
new file mode 100644
index 0000000..b2710eb
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidQueue.java
@@ -0,0 +1,29 @@
+/*
+ * 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.entity.messaging.qpid;
+
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+
+import org.apache.brooklyn.entity.messaging.Queue;
+
+@ImplementedBy(QpidQueueImpl.class)
+public interface QpidQueue extends QpidDestination, Queue {
+    @Override
+    public String getExchangeName();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..cec93a9
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidQueueImpl.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.entity.messaging.qpid;
+
+import static java.lang.String.format;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.entity.messaging.amqp.AmqpExchange;
+import brooklyn.event.feed.jmx.JmxAttributePollConfig;
+import brooklyn.event.feed.jmx.JmxFeed;
+import brooklyn.util.exceptions.Exceptions;
+
+public class QpidQueueImpl extends QpidDestinationImpl implements QpidQueue {
+    public QpidQueueImpl() {
+    }
+
+    @Override
+    public void onManagementStarting() {
+        super.onManagementStarting();
+        setAttribute(QUEUE_NAME, getName());
+        try {
+            exchange = new ObjectName(format("org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=\"%s\",name=\"%s\",ExchangeType=direct", virtualHost, getExchangeName()));
+        } catch (MalformedObjectNameException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    @Override
+    protected void connectSensors() {
+        String queue = format("org.apache.qpid:type=VirtualHost.Queue,VirtualHost=\"%s\",name=\"%s\"", virtualHost, getName());
+        
+        jmxFeed = JmxFeed.builder()
+                .entity(this)
+                .helper(jmxHelper)
+                .pollAttribute(new JmxAttributePollConfig<Integer>(QUEUE_DEPTH_BYTES)
+                        .objectName(queue)
+                        .attributeName("QueueDepth"))
+                .pollAttribute(new JmxAttributePollConfig<Integer>(QUEUE_DEPTH_MESSAGES)
+                        .objectName(queue)
+                        .attributeName("MessageCount"))
+                .build();
+    }
+
+    @Override
+    public String getExchangeName() {
+        return AmqpExchange.DIRECT;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidSshDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidSshDriver.java
new file mode 100644
index 0000000..3c6daf5
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidSshDriver.java
@@ -0,0 +1,137 @@
+/*
+ * 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.entity.messaging.qpid;
+
+import static java.lang.String.format;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Networking;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+
+import com.google.common.collect.ImmutableMap;
+
+public class QpidSshDriver extends JavaSoftwareProcessSshDriver implements QpidDriver{
+
+    private static final Logger log = LoggerFactory.getLogger(QpidSshDriver.class);
+
+    public QpidSshDriver(QpidBrokerImpl entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    @Override
+    protected String getLogFileLocation() { return Os.mergePaths(getRunDir(), "log", "qpid.log"); }
+
+    @Override
+    public Integer getAmqpPort() { return entity.getAttribute(QpidBroker.AMQP_PORT); }
+
+    @Override
+    public String getAmqpVersion() { return entity.getAttribute(QpidBroker.AMQP_VERSION); }
+
+    public Integer getHttpManagementPort() { return entity.getAttribute(QpidBroker.HTTP_MANAGEMENT_PORT); }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this);
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("qpid-broker-%s", getVersion()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+
+        List<String> commands = new LinkedList<String>();
+        commands.addAll( BashCommands.commandsToDownloadUrlsAs(urls, saveAs));
+        commands.add(BashCommands.INSTALL_TAR);
+        commands.add("tar xzfv "+saveAs);
+
+        newScript(INSTALLING)
+                .body.append(commands)
+                .execute();
+    }
+
+    @Override
+    public void customize() {
+        Networking.checkPortsValid(MutableMap.of("jmxPort", getJmxPort(), "amqpPort", getAmqpPort()));
+        newScript(CUSTOMIZING)
+                .body.append(
+                        format("cp -R %s/{bin,etc,lib} .", getExpandedInstallDir()),
+                        "mkdir lib/opt"
+                    )
+                .execute();
+    }
+
+    @Override
+    public void launch() {
+        newScript(ImmutableMap.of(USE_PID_FILE, false), LAUNCHING)
+                .body.append("nohup ./bin/qpid-server -b '*' > qpid-server-launch.log 2>&1 &")
+                .execute();
+    }
+
+    public String getPidFile() { return "qpid-server.pid"; }
+    
+    @Override
+    public boolean isRunning() {
+        return newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), CHECK_RUNNING).execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), STOPPING).execute();
+    }
+
+    @Override
+    public void kill() {
+        newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), KILLING).execute();
+    }
+
+    @Override
+    public Map<String, Object> getCustomJavaSystemProperties() {
+        return MutableMap.<String, Object>builder()
+                .putAll(super.getCustomJavaSystemProperties())
+                .put("connector.port", getAmqpPort())
+                .put("management.enabled", "true")
+                .put("management.jmxport.registryServer", getRmiRegistryPort())
+                .put("management.jmxport.connectorServer", getJmxPort())
+                .put("management.http.enabled", Boolean.toString(getHttpManagementPort() != null))
+                .putIfNotNull("management.http.port", getHttpManagementPort())
+                .build();
+    }
+
+    @Override
+    public Map<String, String> getShellEnvironment() {
+        return MutableMap.<String, String>builder()
+                .putAll(super.getShellEnvironment())
+                .put("QPID_HOME", getRunDir())
+                .put("QPID_WORK", getRunDir())
+                .renameKey("JAVA_OPTS", "QPID_OPTS")
+                .build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidTopic.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidTopic.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidTopic.java
new file mode 100644
index 0000000..bee9519
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidTopic.java
@@ -0,0 +1,27 @@
+/*
+ * 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.entity.messaging.qpid;
+
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+
+import org.apache.brooklyn.entity.messaging.Topic;
+
+@ImplementedBy(QpidTopicImpl.class)
+public interface QpidTopic extends QpidDestination, Topic {
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidTopicImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidTopicImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidTopicImpl.java
new file mode 100644
index 0000000..8de02d9
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/qpid/QpidTopicImpl.java
@@ -0,0 +1,56 @@
+/*
+ * 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.entity.messaging.qpid;
+
+import static java.lang.String.format;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.entity.messaging.amqp.AmqpExchange;
+import brooklyn.util.exceptions.Exceptions;
+
+public class QpidTopicImpl extends QpidDestinationImpl implements QpidTopic {
+
+    public QpidTopicImpl() {
+    }
+
+    @Override
+    public void onManagementStarting() {
+        super.onManagementStarting();
+        setAttribute(TOPIC_NAME, getName());
+        try {
+            String virtualHost = getParent().getVirtualHost();
+            exchange = new ObjectName(format("org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=\"%s\",name=\"%s\",ExchangeType=topic", virtualHost, getExchangeName()));
+        } catch (MalformedObjectNameException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    // TODO sensors
+    @Override
+    public void connectSensors() {
+    }
+
+    @Override
+    public String getExchangeName() { return AmqpExchange.TOPIC; }
+
+    @Override
+    public String getTopicName() { return getQueueName(); }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..7e0f54e
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBroker.java
@@ -0,0 +1,91 @@
+/*
+ * 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.entity.messaging.rabbit;
+
+import java.util.Map;
+
+import com.google.common.annotations.Beta;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import org.apache.brooklyn.entity.messaging.MessageBroker;
+import org.apache.brooklyn.entity.messaging.amqp.AmqpServer;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Rabbit MQ broker instance, using AMQP 0-9-1.
+ */
+@Catalog(name="RabbitMQ Broker", description="RabbitMQ is an open source message broker software (i.e. message-oriented middleware) that implements the Advanced Message Queuing Protocol (AMQP) standard", iconUrl="classpath:///RabbitMQLogo.png")
+@ImplementedBy(RabbitBrokerImpl.class)
+public interface RabbitBroker extends SoftwareProcess, MessageBroker, AmqpServer {
+
+    @SetFromFlag("version")
+    public static final ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "2.8.7");
+
+    @SetFromFlag("downloadUrl")
+    public static final BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
+            SoftwareProcess.DOWNLOAD_URL, "http://www.rabbitmq.com/releases/rabbitmq-server/v${version}/rabbitmq-server-generic-unix-${version}.tar.gz");
+    
+    @SetFromFlag("erlangVersion")
+    public static final BasicConfigKey<String> ERLANG_VERSION = new BasicConfigKey<String>(String.class, "erlang.version", "Erlang runtime version", "R15B");
+
+    @SetFromFlag("rabbitmqConfigTemplateUrl")
+    ConfigKey<String> CONFIG_TEMPLATE_URL = ConfigKeys.newStringConfigKey(
+            "rabbitmq.templateUrl", "Template file (in freemarker format) for the rabbitmq.config config file",
+            "classpath://org/apache/brooklyn/entity/messaging/rabbit/rabbitmq.config");
+
+    @SetFromFlag("amqpPort")
+    public static final PortAttributeSensorAndConfigKey AMQP_PORT = AmqpServer.AMQP_PORT;
+
+    @SetFromFlag("virtualHost")
+    public static final BasicAttributeSensorAndConfigKey<String> VIRTUAL_HOST_NAME = AmqpServer.VIRTUAL_HOST_NAME;
+
+    @SetFromFlag("amqpVersion")
+    public static final BasicAttributeSensorAndConfigKey<String> AMQP_VERSION = new BasicAttributeSensorAndConfigKey<String>(
+            AmqpServer.AMQP_VERSION, AmqpServer.AMQP_0_9_1);
+
+    @SetFromFlag("managmentPort")
+    public static final PortAttributeSensorAndConfigKey MANAGEMENT_PORT = new PortAttributeSensorAndConfigKey(
+            "rabbitmq.management.port", "Port on which management interface will be available", "15672+");
+
+    public static AttributeSensor<String> MANAGEMENT_URL = Sensors.newStringSensor(
+            "rabbitmq.management.url", "Management URL is only available if management plugin flag is true");
+
+    @SetFromFlag("enableManagementPlugin")
+    public static final ConfigKey<Boolean> ENABLE_MANAGEMENT_PLUGIN = ConfigKeys.newBooleanConfigKey(
+            "rabbitmq.management.plugin", "Management plugin will be enabled", false);
+
+    RabbitQueue createQueue(Map properties);
+
+    // TODO required by RabbitDestination due to close-coupling between that and RabbitBroker; how best to improve?
+    @Beta
+    Map<String, String> getShellEnvironment();
+    
+    @Beta
+    String getRunDir();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java
new file mode 100644
index 0000000..82347bf
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.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.entity.messaging.rabbit;
+
+import static java.lang.String.format;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Objects.ToStringHelper;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.SoftwareProcessImpl;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Rabbit MQ broker instance, using AMQP 0-9-1.
+ */
+public class RabbitBrokerImpl extends SoftwareProcessImpl implements RabbitBroker {
+    private static final Logger log = LoggerFactory.getLogger(RabbitBrokerImpl.class);
+
+    public String getVirtualHost() { return getAttribute(VIRTUAL_HOST_NAME); }
+    public String getAmqpVersion() { return getAttribute(AMQP_VERSION); }
+    public Integer getAmqpPort() { return getAttribute(AMQP_PORT); }
+
+    public RabbitBrokerImpl() {
+        super();
+    }
+
+    @Override
+    public RabbitDriver getDriver() {
+        return (RabbitDriver) super.getDriver();
+    }
+
+    @Override
+    public Map<String, String> getShellEnvironment() {
+        return getDriver().getShellEnvironment();
+    }
+    
+    @Override
+    public String getRunDir() {
+        return getDriver().getRunDir();
+    }
+    
+    @Override
+    protected void postStart() {
+        super.postStart();
+
+        getDriver().configure();
+
+        // TODO implement this using AMQP connection, no external mechanism available
+        // queueNames.each { String name -> addQueue(name) }
+    }
+
+    public void setBrokerUrl() {
+        String urlFormat = "amqp://guest:guest@%s:%d/%s";
+        setAttribute(BROKER_URL, format(urlFormat, getAttribute(HOSTNAME), getAttribute(AMQP_PORT), getAttribute(VIRTUAL_HOST_NAME)));
+    }
+
+    public RabbitQueue createQueue(Map properties) {
+        RabbitQueue result = addChild(EntitySpec.create(RabbitQueue.class).configure(properties));
+        Entities.manage(result);
+        result.create();
+        return result;
+    }
+
+    @Override
+    public Class<? extends RabbitDriver> getDriverInterface() {
+        return RabbitDriver.class;
+    }
+
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+
+        connectServiceUpIsRunning();
+
+        setBrokerUrl();
+
+        if (getEnableManagementPlugin()) {
+            setAttribute(MANAGEMENT_URL, format("http://%s:%s/", getAttribute(HOSTNAME), getAttribute(MANAGEMENT_PORT)));
+        }
+    }
+
+    @Override
+    public void disconnectSensors() {
+        super.disconnectSensors();
+        disconnectServiceUpIsRunning();
+    }
+
+    public boolean getEnableManagementPlugin() {
+        return Boolean.TRUE.equals(getConfig(ENABLE_MANAGEMENT_PLUGIN));
+    }
+
+    public Integer getManagementPort() {
+        return getAttribute(MANAGEMENT_PORT);
+    }
+
+    @Override
+    protected ToStringHelper toStringHelper() {
+        return super.toStringHelper().add("amqpPort", getAmqpPort());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitDestination.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitDestination.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitDestination.java
new file mode 100644
index 0000000..0f2a7e4
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitDestination.java
@@ -0,0 +1,92 @@
+/*
+ * 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.entity.messaging.rabbit;
+
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.AbstractEntity;
+import org.apache.brooklyn.entity.messaging.amqp.AmqpExchange;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+public abstract class RabbitDestination extends AbstractEntity implements AmqpExchange {
+    public static final Logger log = LoggerFactory.getLogger(RabbitDestination.class);
+    
+    private String virtualHost;
+    private String exchange;
+    protected SshMachineLocation machine;
+    protected Map<String,String> shellEnvironment;
+
+    public RabbitDestination() {
+    }
+
+    @Override
+    public void onManagementStarting() {
+        super.onManagementStarting();
+        
+        exchange = (getConfig(EXCHANGE_NAME) != null) ? getConfig(EXCHANGE_NAME) : getDefaultExchangeName();
+        virtualHost = getConfig(RabbitBroker.VIRTUAL_HOST_NAME);
+        setAttribute(RabbitBroker.VIRTUAL_HOST_NAME, virtualHost);
+        
+        machine = (SshMachineLocation) Iterables.find(getParent().getLocations(), Predicates.instanceOf(SshMachineLocation.class));
+        shellEnvironment = getParent().getShellEnvironment();
+    }
+
+    // FIXME Should return RabbitBroker; won't work if gets a proxy rather than "real" entity
+    @Override
+    public RabbitBroker getParent() {
+        return (RabbitBroker) super.getParent();
+    }
+    
+    public void create() {
+        connectSensors();
+    }
+    
+    public void delete() {
+        disconnectSensors();
+    }
+
+    protected void connectSensors() { }
+
+    protected void disconnectSensors() { }
+
+    public String getVirtualHost() {
+        return virtualHost;
+    }
+    
+    @Override
+    public String getExchangeName() { 
+        return exchange;
+    }
+    
+    public String getDefaultExchangeName() {
+        return AmqpExchange.DIRECT;
+    }
+
+    @Override
+    protected ToStringHelper toStringHelper() {
+        return super.toStringHelper().add("virtualHost", getParent().getVirtualHost()).add("exchange", getExchangeName());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitDriver.java
new file mode 100644
index 0000000..2c989d5
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitDriver.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.entity.messaging.rabbit;
+
+import java.util.Map;
+
+import brooklyn.entity.basic.SoftwareProcessDriver;
+
+public interface RabbitDriver extends SoftwareProcessDriver {
+    
+    public void configure();
+    
+    public Map<String, String> getShellEnvironment();
+
+    public String getRunDir();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..cb12b4f
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitQueue.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.entity.messaging.rabbit;
+
+import org.apache.brooklyn.entity.messaging.Queue;
+import brooklyn.event.feed.ssh.SshFeed;
+import brooklyn.event.feed.ssh.SshPollConfig;
+import brooklyn.event.feed.ssh.SshPollValue;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+
+public class RabbitQueue extends RabbitDestination implements Queue {
+
+    private SshFeed sshFeed;
+
+    public RabbitQueue() {
+    }
+    
+    public String getName() {
+        return getDisplayName();
+    }
+
+    @Override
+    public void create() {
+        setAttribute(QUEUE_NAME, getName());
+        super.create();
+    }
+
+    @Override
+    protected void connectSensors() {
+        String runDir = getParent().getRunDir();
+        String cmd = String.format("%s/sbin/rabbitmqctl list_queues -p /%s  | grep '%s'", runDir, getVirtualHost(), getQueueName());
+        
+        sshFeed = SshFeed.builder()
+                .entity(this)
+                .machine(machine)
+                .poll(new SshPollConfig<Integer>(QUEUE_DEPTH_BYTES)
+                        .env(shellEnvironment)
+                        .command(cmd)
+                        .onFailure(Functions.constant(-1))
+                        .onSuccess(new Function<SshPollValue, Integer>() {
+                                @Override public Integer apply(SshPollValue input) {
+                                    return 0; // TODO parse out queue depth from output
+                                }}))
+                .poll(new SshPollConfig<Integer>(QUEUE_DEPTH_MESSAGES)
+                        .env(shellEnvironment)
+                        .command(cmd)
+                        .onFailure(Functions.constant(-1))
+                        .onSuccess(new Function<SshPollValue, Integer>() {
+                                @Override public Integer apply(SshPollValue input) {
+                                    return 0; // TODO parse out queue depth from output
+                                }}))
+                .build();
+    }
+    
+    @Override
+    protected void disconnectSensors() {
+        if (sshFeed != null) sshFeed.stop();
+        super.disconnectSensors();
+    }
+    
+    /**
+     * Return the AMQP name for the queue.
+     */
+    public String getQueueName() {
+        return getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitSshDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitSshDriver.java
new file mode 100644
index 0000000..56e248f
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitSshDriver.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.entity.messaging.rabbit;
+
+import static brooklyn.util.ssh.BashCommands.*;
+import static java.lang.String.format;
+
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.lifecycle.ScriptHelper;
+import org.apache.brooklyn.entity.messaging.amqp.AmqpServer;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Networking;
+import brooklyn.util.os.Os;
+
+/**
+ * TODO javadoc
+ */
+public class RabbitSshDriver extends AbstractSoftwareProcessSshDriver implements RabbitDriver {
+
+    private static final Logger log = LoggerFactory.getLogger(RabbitSshDriver.class);
+
+    // See http://fedoraproject.org/wiki/EPEL/FAQ#howtouse
+    private static final Map<String, String> CENTOS_VERSION_TO_EPEL_VERSION = ImmutableMap.of(
+        "5", "5-4",
+        "6", "6-8",
+        "7", "7-5"
+    );
+
+    public RabbitSshDriver(RabbitBrokerImpl entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    protected String getLogFileLocation() { return getRunDir()+"/"+entity.getId()+".log"; }
+
+    public Integer getAmqpPort() { return entity.getAttribute(AmqpServer.AMQP_PORT); }
+
+    public String getVirtualHost() { return entity.getAttribute(AmqpServer.VIRTUAL_HOST_NAME); }
+
+    public String getErlangVersion() { return entity.getConfig(RabbitBroker.ERLANG_VERSION); }
+
+    @Override
+    public RabbitBrokerImpl getEntity() {
+        return (RabbitBrokerImpl) super.getEntity();
+    }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this);
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("rabbitmq_server-%s", getVersion()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+        // Version and architecture are only required for download of epel package on RHEL/Centos systems so pick sensible
+        // defaults if unavailable
+        String osMajorVersion = getMachine().getOsDetails().getVersion();
+        if (Strings.isNullOrEmpty(osMajorVersion)) {
+            osMajorVersion = "7";
+        } else {
+            osMajorVersion = osMajorVersion.indexOf(".") > 0 ? osMajorVersion.substring(0, osMajorVersion.indexOf('.')) : osMajorVersion;
+            if (!CENTOS_VERSION_TO_EPEL_VERSION.keySet().contains(osMajorVersion)) {
+                osMajorVersion = "7";
+            }
+        }
+        String epelVersion = CENTOS_VERSION_TO_EPEL_VERSION.get(osMajorVersion);
+        String osArchitecture = getMachine().getOsDetails().getArch();
+        if (Strings.isNullOrEmpty(osArchitecture)) {
+            osArchitecture = "x86_64";
+        }
+
+        List<String> commands = ImmutableList.<String>builder()
+                // EPEL repository for erlang install required on some Centos distributions
+                .add(chainGroup("which yum", sudo("yum -y update ca-certificates"), sudo("rpm -Uvh " +
+                        format("http://download.fedoraproject.org/pub/epel/%s/%s/epel-release-%s.noarch.rpm", osMajorVersion, osArchitecture, epelVersion))))
+                .add(ifExecutableElse0("zypper", chainGroup(
+                        ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/SLE_11_SP3 erlang_sles_11")),
+                        ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/openSUSE_11.4 erlang_suse_11")),
+                        ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/openSUSE_12.3 erlang_suse_12")),
+                        ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/openSUSE_13.1 erlang_suse_13")))))
+                .add(installPackage( // NOTE only 'port' states the version of Erlang used, maybe remove this constraint?
+                        ImmutableMap.of(
+                                "apt", "erlang-nox erlang-dev",
+                                "port", "erlang@"+getErlangVersion()+"+ssl"),
+                        "erlang"))
+                .addAll(commandsToDownloadUrlsAs(urls, saveAs))
+                .add(installExecutable("tar"))
+                .add(format("tar xvzf %s",saveAs))
+                .build();
+
+        newScript(INSTALLING).
+                failOnNonZeroResultCode().
+                body.append(commands).execute();
+    }
+
+    @Override
+    public void customize() {
+        Networking.checkPortsValid(MutableMap.of("amqpPort", getAmqpPort()));
+        ScriptHelper scriptHelper = newScript(CUSTOMIZING);
+
+        scriptHelper.body.append(
+                format("cp -R %s/* .", getExpandedInstallDir())
+        );
+
+        if (Boolean.TRUE.equals(entity.getConfig(RabbitBroker.ENABLE_MANAGEMENT_PLUGIN))) {
+            scriptHelper.body.append(
+                    "./sbin/rabbitmq-plugins enable rabbitmq_management"
+            );
+        }
+        scriptHelper.failOnNonZeroResultCode();
+        scriptHelper.execute();
+
+        copyTemplate(entity.getConfig(RabbitBroker.CONFIG_TEMPLATE_URL), getConfigPath() + ".config");
+    }
+
+    @Override
+    public void launch() {
+        newScript(MutableMap.of("usePidFile", false), LAUNCHING)
+            .body.append(
+                "nohup ./sbin/rabbitmq-server > console-out.log 2> console-err.log &",
+                "for i in {1..10}\n" +
+                    "do\n" +
+                     "    grep 'broker running' console-out.log && exit\n" +
+                     "    sleep 1\n" +
+                     "done",
+                "echo \"Couldn't determine if rabbitmq-server is running\"",
+                "exit 1"
+            ).execute();
+    }
+
+    @Override
+    public void configure() {
+        newScript(CUSTOMIZING)
+            .body.append(
+                "./sbin/rabbitmqctl add_vhost "+getEntity().getVirtualHost(),
+                "./sbin/rabbitmqctl set_permissions -p "+getEntity().getVirtualHost()+" guest \".*\" \".*\" \".*\""
+            ).execute();
+    }
+
+
+    public String getPidFile() { return "rabbitmq.pid"; }
+
+    @Override
+    public boolean isRunning() {
+        return newScript(MutableMap.of("usePidFile", false), CHECK_RUNNING)
+                .body.append("./sbin/rabbitmqctl -q status")
+                .execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(MutableMap.of("usePidFile", false), STOPPING)
+                .body.append("./sbin/rabbitmqctl stop")
+                .execute();
+    }
+
+
+    @Override
+    public void kill() {
+        stop(); // TODO No pid file to easily do `kill -9`
+    }
+
+    @Override
+    public Map<String, String> getShellEnvironment() {
+        return MutableMap.<String, String>builder()
+                .putAll(super.getShellEnvironment())
+                .put("RABBITMQ_HOME", getRunDir())
+                .put("RABBITMQ_LOG_BASE", getRunDir())
+                .put("RABBITMQ_NODENAME", getEntity().getId())
+                .put("RABBITMQ_NODE_PORT", getAmqpPort().toString())
+                .put("RABBITMQ_PID_FILE", getRunDir()+"/"+getPidFile())
+                .put("RABBITMQ_CONFIG_FILE", getConfigPath())
+                .build();
+    }
+
+    private String getConfigPath() {
+        return getRunDir() + "/rabbitmq";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..8c4a4bf
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/Storm.java
@@ -0,0 +1,105 @@
+/*
+ * 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.entity.messaging.storm;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.config.render.RendererHints;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.java.UsesJmx;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a Storm node (UI, Nimbus or Supervisor).
+ */
+@Catalog(name="Storm Node", description="Apache Storm is a distributed realtime computation system. "
+        + "Storm makes it easy to reliably process unbounded streams of data, doing for realtime processing "
+        + "what Hadoop did for batch processing")
+@ImplementedBy(StormImpl.class)
+public interface Storm extends SoftwareProcess, UsesJmx {
+
+    @SetFromFlag("version")
+    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "0.8.2");
+
+    @SetFromFlag("nimbusHostname")
+    ConfigKey<String> NIMBUS_HOSTNAME = ConfigKeys.newStringConfigKey("storm.nimbus.hostname");
+    
+    @SetFromFlag("nimbusEntity")
+    ConfigKey<Entity> NIMBUS_ENTITY = ConfigKeys.newConfigKey(Entity.class, "storm.nimbus.entity");
+
+    @SetFromFlag("downloadUrl")
+    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
+            SoftwareProcess.DOWNLOAD_URL, "https://dl.dropboxusercontent.com/s/fl4kr7w0oc8ihdw/storm-${version}.zip");
+
+    ConfigKey<Object> START_MUTEX = ConfigKeys.newConfigKey(Object.class, "storm.start.mutex");
+
+    @SetFromFlag("role")
+    ConfigKey<Role> ROLE = ConfigKeys.newConfigKey(Role.class, "storm.role", "The Storm server role");
+
+    @SetFromFlag("localDir")
+    ConfigKey<String> LOCAL_DIR = ConfigKeys.newStringConfigKey("storm.local.dir", "Setting for Storm local dir");
+    
+    @SetFromFlag("uiPort")
+    PortAttributeSensorAndConfigKey UI_PORT = new PortAttributeSensorAndConfigKey("storm.ui.port", "Storm UI port", "8080+");
+
+    @SetFromFlag("thriftPort")
+    PortAttributeSensorAndConfigKey THRIFT_PORT = new PortAttributeSensorAndConfigKey("storm.thrift.port", "Storm Thrift port", "6627");
+
+    @SetFromFlag("zookeeperEnsemble")
+    ConfigKey<ZooKeeperEnsemble> ZOOKEEPER_ENSEMBLE = ConfigKeys.newConfigKey(ZooKeeperEnsemble.class,
+            "storm.zookeeper.ensemble", "Zookeeper ensemble entity");
+
+    @SetFromFlag("stormConfigTemplateUrl")
+    ConfigKey<String> STORM_CONFIG_TEMPLATE_URL = ConfigKeys.newStringConfigKey("storm.config.templateUrl",
+            "Template file (in freemarker format) for the storm.yaml config file",
+            "classpath://org/apache/brooklyn/entity/messaging/storm/storm.yaml");
+
+    @SetFromFlag("zeromqVersion")
+    ConfigKey<String> ZEROMQ_VERSION = ConfigKeys.newStringConfigKey("storm.zeromq.version", "zeromq version", "2.1.7");
+
+    AttributeSensor<Boolean> SERVICE_UP_JMX = Sensors.newBooleanSensor("storm.service.jmx.up", "Whether JMX is up for this service");
+
+    String getStormConfigTemplateUrl();
+
+    String getHostname();
+
+    Role getRole();
+    
+    enum Role { NIMBUS, SUPERVISOR, UI }
+
+    AttributeSensor<String> STORM_UI_URL = StormUiUrl.STORM_UI_URL;
+    
+    class StormUiUrl {
+        public static final AttributeSensor<String> STORM_UI_URL = Sensors.newStringSensor("storm.ui.url", "URL");
+
+        static {
+            RendererHints.register(STORM_UI_URL, RendererHints.namedActionWithUrl());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeployment.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeployment.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeployment.java
new file mode 100644
index 0000000..8f505a6
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeployment.java
@@ -0,0 +1,42 @@
+/*
+ * 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.entity.messaging.storm;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.trait.Startable;
+
+@Catalog(name="Storm Deployment", description="A Storm cluster. Apache Storm is a distributed realtime computation system. "
+        + "Storm makes it easy to reliably process unbounded streams of data, doing for realtime processing "
+        + "what Hadoop did for batch processing")
+@ImplementedBy(StormDeploymentImpl.class)
+public interface StormDeployment extends Entity, Startable {
+
+    @SetFromFlag("supervisors.count")
+    ConfigKey<Integer> SUPERVISORS_COUNT = ConfigKeys.newConfigKey("storm.supervisors.count", "Number of supervisor nodes", 3);
+
+    @SetFromFlag("zookeepers.count")
+    ConfigKey<Integer> ZOOKEEPERS_COUNT = ConfigKeys.newConfigKey("storm.zookeepers.count", "Number of zookeeper nodes", 1);
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..0e5d006
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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.entity.messaging.storm;
+
+import static org.apache.brooklyn.entity.messaging.storm.Storm.ROLE;
+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 org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.enricher.Enrichers;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.BasicStartableImpl;
+import brooklyn.entity.group.DynamicCluster;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble;
+
+public class StormDeploymentImpl extends BasicStartableImpl implements StormDeployment {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(StormDeploymentImpl.class);
+
+    @Override
+    public void init() {
+        super.init();
+        new ResourceUtils(this).checkUrlExists(Storm.STORM_CONFIG_TEMPLATE_URL.getDefaultValue());
+        
+        setDefaultDisplayName("Storm Deployment");
+        
+        ZooKeeperEnsemble zooKeeperEnsemble = addChild(EntitySpec.create(
+            ZooKeeperEnsemble.class).configure(
+                ZooKeeperEnsemble.INITIAL_SIZE, getConfig(ZOOKEEPERS_COUNT)));
+        
+        setConfig(Storm.ZOOKEEPER_ENSEMBLE, zooKeeperEnsemble);
+        
+        Storm nimbus = addChild(EntitySpec.create(Storm.class).configure(ROLE, NIMBUS));
+        
+        setConfig(Storm.NIMBUS_ENTITY, nimbus);
+        setConfig(Storm.START_MUTEX, new Object());
+        
+        addChild(EntitySpec.create(DynamicCluster.class)
+            .configure(DynamicCluster.MEMBER_SPEC, 
+                EntitySpec.create(Storm.class).configure(ROLE, SUPERVISOR))
+            .configure(DynamicCluster.INITIAL_SIZE, getConfig(SUPERVISORS_COUNT))
+            .displayName("Storm Supervisor Cluster"));
+        
+        Storm ui = addChild(EntitySpec.create(Storm.class).configure(ROLE, UI));
+        
+        addEnricher(Enrichers.builder()
+                .propagating(Storm.STORM_UI_URL)
+                .from(ui)
+                .build());
+        addEnricher(Enrichers.builder()
+                .propagating(Attributes.HOSTNAME)
+                .from(nimbus)
+                .build());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDriver.java
new file mode 100644
index 0000000..f91429e
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDriver.java
@@ -0,0 +1,27 @@
+/*
+ * 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.entity.messaging.storm;
+
+import brooklyn.entity.java.JavaSoftwareProcessDriver;
+
+public interface StormDriver extends JavaSoftwareProcessDriver {
+
+    String getJvmOptsLine();
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..b2e5436
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormImpl.java
@@ -0,0 +1,118 @@
+/*
+ * 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.entity.messaging.storm;
+
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.entity.java.JavaAppUtils;
+import brooklyn.entity.java.JavaSoftwareProcessDriver;
+import brooklyn.event.feed.jmx.JmxFeed;
+import brooklyn.event.feed.jmx.JmxHelper;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+public class StormImpl extends SoftwareProcessImpl implements Storm {
+
+    private static final Logger log = LoggerFactory.getLogger(StormImpl.class);
+
+    public static final ObjectName STORM_MBEAN = JmxHelper.createObjectName("backtype.storm.daemon.nimbus:type=*");
+
+    private JmxHelper jmxHelper;
+    private volatile JmxFeed jmxFeed;
+    
+    public StormImpl() {}
+    
+    @Override
+    public String getHostname() { return getAttribute(HOSTNAME); }
+
+    @Override
+    public Role getRole() { return getConfig(ROLE); }
+
+    @Override
+    public String getStormConfigTemplateUrl() { return getConfig(STORM_CONFIG_TEMPLATE_URL); }   
+    
+    @Override
+    public Class<?> getDriverInterface() {
+        return StormDriver.class;
+    }
+
+    public String getRoleName() { return getRole().name().toLowerCase(); }
+
+    @Override
+    protected void preStart() {
+        setDefaultDisplayName("Storm Node ("+ getRoleName()+")");
+        super.preStart();
+    }
+    
+    @Override
+    protected void connectSensors() {
+        super.connectSensors();
+
+        // give it plenty of time to start before we advertise ourselves
+        Time.sleep(Duration.TEN_SECONDS);
+
+        if (getRole() == Role.UI) {
+            setAttribute(STORM_UI_URL, "http://"+getAttribute(Attributes.HOSTNAME)+":"+getAttribute(UI_PORT)+"/");
+        }
+
+        if (((JavaSoftwareProcessDriver)getDriver()).isJmxEnabled()) {
+            jmxHelper = new JmxHelper(this);
+//            jmxFeed = JmxFeed.builder()
+//                    .entity(this)
+//                    .period(3000, TimeUnit.MILLISECONDS)
+//                    .helper(jmxHelper)
+//                    .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP_JMX)
+//                            .objectName(STORM_MBEAN)
+//                            .attributeName("Initialized")
+//                            .onSuccess(Functions.forPredicate(Predicates.notNull()))
+//                            .onException(Functions.constant(false)))
+//                    // TODO SERVICE_UP should really be a combo of JMX plus is running
+//                    .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP)
+//                            .objectName(STORM_MBEAN)
+//                            .attributeName("Initialized")
+//                            .onSuccess(Functions.forPredicate(Predicates.notNull()))
+//                            .onException(Functions.constant(false)))
+//                    .build();
+            jmxFeed = JavaAppUtils.connectMXBeanSensors(this);
+            
+            // FIXME for now we do service up based on pid check -- we get a warning that:
+            // JMX object backtype.storm.daemon.nimbus:type=* not found at service:jmx:jmxmp://108.59.82.105:31001
+            // (JMX is up fine, but no such object there)
+            connectServiceUpIsRunning();
+         } else {
+            // if not using JMX
+            log.warn("Storm running without JMX monitoring; limited visibility of service available");
+            connectServiceUpIsRunning();
+        }
+    }
+
+    @Override
+    public void disconnectSensors() {
+        super.disconnectSensors();
+        disconnectServiceUpIsRunning();
+        if (jmxFeed != null) jmxFeed.stop();
+        if (jmxHelper !=null) jmxHelper.terminate();
+    }
+
+}


[16/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/XmlUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/XmlUtil.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/XmlUtil.java
new file mode 100644
index 0000000..637f078
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/XmlUtil.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.util.xstream;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+import brooklyn.util.exceptions.Exceptions;
+
+public class XmlUtil {
+
+    public static Object xpath(String xml, String xpath) {
+        // TODO Could share factory/doc in thread-local storage; see http://stackoverflow.com/questions/9828254/is-documentbuilderfactory-thread-safe-in-java-5
+        try {
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            Document doc = builder.parse(new ByteArrayInputStream(xml.getBytes()));
+            XPathFactory xPathfactory = XPathFactory.newInstance();
+            XPathExpression expr = xPathfactory.newXPath().compile(xpath);
+            
+            return expr.evaluate(doc);
+            
+        } catch (ParserConfigurationException e) {
+            throw Exceptions.propagate(e);
+        } catch (SAXException e) {
+            throw Exceptions.propagate(e);
+        } catch (IOException e) {
+            throw Exceptions.propagate(e);
+        } catch (XPathExpressionException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java b/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java
index 9daf1c5..c3b6c61 100644
--- a/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/location/access/BrooklynAccessUtils.java
@@ -23,6 +23,10 @@ import java.util.Collection;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,10 +41,6 @@ import org.apache.brooklyn.location.basic.SupportsPortForwarding;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.net.Cidr;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Supplier;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerLocationResolver.java
index db35a34..3e23f45 100644
--- a/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/access/PortForwardManagerLocationResolver.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.basic.LocationConfigUtils;
 import org.apache.brooklyn.location.basic.LocationInternal;
 import org.apache.brooklyn.location.basic.LocationPredicates;
@@ -30,8 +31,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.basic.AbstractLocationResolver;
 
-import brooklyn.util.config.ConfigBag;
-
 import com.google.common.base.Optional;
 import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java b/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java
index 554a781..0a96956 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocation.java
@@ -38,6 +38,9 @@ import org.apache.brooklyn.api.mementos.LocationMemento;
 import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.management.internal.LocalLocationManager;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,9 +59,6 @@ import org.apache.brooklyn.location.geo.HasHostGeoInfo;
 import org.apache.brooklyn.location.geo.HostGeoInfo;
 
 import brooklyn.util.collections.SetFromLiveMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.stream.Streams;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocationResolver.java
index 26f895c..aea65ae 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/AbstractLocationResolver.java
@@ -31,12 +31,12 @@ import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.api.location.LocationResolver;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.location.basic.AbstractLocationResolver.SpecParser.ParsedSpec;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.text.KeyValueParser;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/AggregatingMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/AggregatingMachineProvisioningLocation.java b/core/src/main/java/org/apache/brooklyn/location/basic/AggregatingMachineProvisioningLocation.java
index c814209..ae1a534 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/AggregatingMachineProvisioningLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/AggregatingMachineProvisioningLocation.java
@@ -29,8 +29,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.stream.Streams;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/BasicLocationRegistry.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/BasicLocationRegistry.java b/core/src/main/java/org/apache/brooklyn/location/basic/BasicLocationRegistry.java
index 3cb9f14..4f8637e 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/BasicLocationRegistry.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/BasicLocationRegistry.java
@@ -42,12 +42,12 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.catalog.CatalogPredicates;
 import org.apache.brooklyn.core.management.internal.LocalLocationManager;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.config.ConfigMap;
 import brooklyn.config.ConfigPredicates;
 import brooklyn.config.ConfigUtils;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.guava.Maybe.Absent;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/BasicMachineDetails.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/BasicMachineDetails.java b/core/src/main/java/org/apache/brooklyn/location/basic/BasicMachineDetails.java
index d6b51c6..9404af2 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/BasicMachineDetails.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/BasicMachineDetails.java
@@ -32,15 +32,15 @@ import org.apache.brooklyn.api.location.HardwareDetails;
 import org.apache.brooklyn.api.location.MachineDetails;
 import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskTags;
+import org.apache.brooklyn.core.util.task.ssh.internal.PlainSshExecTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskTags;
-import brooklyn.util.task.ssh.internal.PlainSshExecTaskFactory;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/ByonLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/ByonLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/basic/ByonLocationResolver.java
index 70735e5..c5680ba 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/ByonLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/ByonLocationResolver.java
@@ -29,6 +29,8 @@ import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.core.management.internal.LocalLocationManager;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,8 +44,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Sanitizer;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.net.UserAndHostAndPort;
 import brooklyn.util.text.WildcardGlobs;
 import brooklyn.util.text.WildcardGlobs.PhraseTreatment;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/FixedListMachineProvisioningLocation.java b/core/src/main/java/org/apache/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
index 7b9d73e..170867d 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/FixedListMachineProvisioningLocation.java
@@ -35,6 +35,8 @@ import org.apache.brooklyn.api.location.MachineLocationCustomizer;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.api.management.LocationManager;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,8 +58,6 @@ import org.apache.brooklyn.location.cloud.CloudLocationConfig;
 import brooklyn.util.collections.CollectionFunctionals;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.text.WildcardGlobs;
 import brooklyn.util.text.WildcardGlobs.PhraseTreatment;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/HostLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/HostLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/basic/HostLocationResolver.java
index 8eb983c..d1eb838 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/HostLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/HostLocationResolver.java
@@ -23,9 +23,9 @@ import java.util.Map;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.basic.AbstractLocationResolver.SpecParser.ParsedSpec;
 
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.guava.Maybe.Absent;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostLocationResolver.java
index 859fa99..9e06f58 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostLocationResolver.java
@@ -23,8 +23,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.api.location.LocationResolver;
-
-import brooklyn.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 /**
  * Examples of valid specs:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java b/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java
index cfaf241..b87b85e 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostMachineProvisioningLocation.java
@@ -32,6 +32,11 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.core.util.BrooklynNetworkUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.internal.ssh.process.ProcessTool;
+import org.apache.brooklyn.core.util.mutex.MutexSupport;
+import org.apache.brooklyn.core.util.mutex.WithMutexes;
 import org.apache.brooklyn.location.geo.HostGeoInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -43,12 +48,7 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.rebind.persister.FileBasedObjectStore;
 import brooklyn.entity.rebind.persister.LocationWithObjectStore;
 import brooklyn.entity.rebind.persister.PersistenceObjectStore;
-import brooklyn.util.BrooklynNetworkUtils;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.internal.ssh.process.ProcessTool;
-import brooklyn.util.mutex.MutexSupport;
-import brooklyn.util.mutex.WithMutexes;
 import brooklyn.util.net.Networking;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostPropertiesFromBrooklynProperties.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostPropertiesFromBrooklynProperties.java b/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostPropertiesFromBrooklynProperties.java
index 1830ddd..7a6c8a9 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostPropertiesFromBrooklynProperties.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/LocalhostPropertiesFromBrooklynProperties.java
@@ -20,11 +20,10 @@ package org.apache.brooklyn.location.basic;
 
 import java.util.Map;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.util.config.ConfigBag;
-
 import com.google.common.base.Strings;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/LocationConfigUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/LocationConfigUtils.java b/core/src/main/java/org/apache/brooklyn/location/basic/LocationConfigUtils.java
index d34a199..47784b1 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/LocationConfigUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/LocationConfigUtils.java
@@ -32,6 +32,10 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+import org.apache.brooklyn.core.util.crypto.SecureKeys.PassphraseProblem;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,13 +44,9 @@ import brooklyn.entity.basic.ConfigKeys;
 
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.crypto.AuthorizedKeysParser;
-import brooklyn.util.crypto.SecureKeys;
-import brooklyn.util.crypto.SecureKeys.PassphraseProblem;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.StringFunctions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/LocationInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/LocationInternal.java b/core/src/main/java/org/apache/brooklyn/location/basic/LocationInternal.java
index de3e9a0..4a444c7 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/LocationInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/LocationInternal.java
@@ -24,12 +24,12 @@ import org.apache.brooklyn.api.entity.rebind.RebindSupport;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.mementos.LocationMemento;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.basic.BrooklynObjectInternal;
 import brooklyn.config.ConfigInheritance;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.annotations.Beta;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/LocationPropertiesFromBrooklynProperties.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/LocationPropertiesFromBrooklynProperties.java b/core/src/main/java/org/apache/brooklyn/location/basic/LocationPropertiesFromBrooklynProperties.java
index e1feb18..2655fc9 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/LocationPropertiesFromBrooklynProperties.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/LocationPropertiesFromBrooklynProperties.java
@@ -23,6 +23,8 @@ import static com.google.common.base.Preconditions.checkArgument;
 import java.io.File;
 import java.util.Map;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -30,8 +32,6 @@ import brooklyn.config.BrooklynProperties;
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.config.ConfigUtils;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.os.Os;
 
 import com.google.common.base.Predicates;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/MultiLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/MultiLocation.java b/core/src/main/java/org/apache/brooklyn/location/basic/MultiLocation.java
index b702a92..5740a8f 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/MultiLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/MultiLocation.java
@@ -32,6 +32,7 @@ import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.location.cloud.AbstractAvailabilityZoneExtension;
 import org.apache.brooklyn.location.cloud.AvailabilityZoneExtension;
 
@@ -41,7 +42,6 @@ import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.CompoundRuntimeException;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Predicate;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/NamedLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/NamedLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/basic/NamedLocationResolver.java
index a9f6499..d57b681 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/NamedLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/NamedLocationResolver.java
@@ -28,10 +28,10 @@ import org.apache.brooklyn.api.location.LocationDefinition;
 import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.api.location.LocationResolver;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.text.Strings;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/PortRanges.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/PortRanges.java b/core/src/main/java/org/apache/brooklyn/location/basic/PortRanges.java
index 2e1bdcc..92c3010 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/PortRanges.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/PortRanges.java
@@ -30,8 +30,7 @@ import java.util.NoSuchElementException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.brooklyn.api.location.PortRange;
-
-import brooklyn.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import com.google.common.base.Function;
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/SingleMachineLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/SingleMachineLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/basic/SingleMachineLocationResolver.java
index fb5f676..3db980e 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/SingleMachineLocationResolver.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/SingleMachineLocationResolver.java
@@ -23,8 +23,8 @@ import java.util.Map;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationRegistry;
 import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.guava.Maybe.Absent;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/SingleMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/SingleMachineProvisioningLocation.java b/core/src/main/java/org/apache/brooklyn/location/basic/SingleMachineProvisioningLocation.java
index 5f249d2..bac439f 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/SingleMachineProvisioningLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/SingleMachineProvisioningLocation.java
@@ -23,11 +23,10 @@ import java.util.Map;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.util.flags.SetFromFlag;
-
 import com.google.common.collect.ImmutableMap;
 
 public class SingleMachineProvisioningLocation<T extends MachineLocation> extends FixedListMachineProvisioningLocation<T> {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/basic/SshMachineLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/basic/SshMachineLocation.java b/core/src/main/java/org/apache/brooklyn/location/basic/SshMachineLocation.java
index 0a8dd44..7c58194 100644
--- a/core/src/main/java/org/apache/brooklyn/location/basic/SshMachineLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/basic/SshMachineLocation.java
@@ -51,6 +51,22 @@ import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.api.location.PortRange;
 import org.apache.brooklyn.api.location.PortSupplier;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+import org.apache.brooklyn.core.util.file.ArchiveUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshException;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.sshj.SshjTool;
+import org.apache.brooklyn.core.util.mutex.MutexSupport;
+import org.apache.brooklyn.core.util.mutex.WithMutexes;
+import org.apache.brooklyn.core.util.task.ScheduledTask;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.system.internal.ExecWithLoggingHelpers;
+import org.apache.brooklyn.core.util.task.system.internal.ExecWithLoggingHelpers.ExecRunner;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -87,22 +103,10 @@ import brooklyn.event.basic.MapConfigKey;
 
 import org.apache.brooklyn.location.access.PortForwardManager;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.crypto.SecureKeys;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
-import brooklyn.util.file.ArchiveUtils;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.KeyTransformingLoadingCache.KeyTransformingSameTypeLoadingCache;
-import brooklyn.util.internal.ssh.ShellTool;
-import brooklyn.util.internal.ssh.SshException;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.internal.ssh.sshj.SshjTool;
-import brooklyn.util.mutex.MutexSupport;
-import brooklyn.util.mutex.WithMutexes;
 import brooklyn.util.net.Urls;
 import brooklyn.util.pool.BasicPool;
 import brooklyn.util.pool.Pool;
@@ -110,10 +114,6 @@ import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.stream.KnownSizeInputStream;
 import brooklyn.util.stream.ReaderInputStream;
 import brooklyn.util.stream.StreamGobbler;
-import brooklyn.util.task.ScheduledTask;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.system.internal.ExecWithLoggingHelpers;
-import brooklyn.util.task.system.internal.ExecWithLoggingHelpers.ExecRunner;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 import groovy.lang.Closure;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/cloud/AbstractCloudMachineProvisioningLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/cloud/AbstractCloudMachineProvisioningLocation.java b/core/src/main/java/org/apache/brooklyn/location/cloud/AbstractCloudMachineProvisioningLocation.java
index 437d49b..4b297f8 100644
--- a/core/src/main/java/org/apache/brooklyn/location/cloud/AbstractCloudMachineProvisioningLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/cloud/AbstractCloudMachineProvisioningLocation.java
@@ -24,11 +24,11 @@ import java.util.Map;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 import org.apache.brooklyn.location.basic.AbstractLocation;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.internal.ssh.SshTool;
 
 public abstract class AbstractCloudMachineProvisioningLocation extends AbstractLocation
 implements MachineProvisioningLocation<MachineLocation>, CloudLocationConfig

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/cloud/CloudLocationConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/cloud/CloudLocationConfig.java b/core/src/main/java/org/apache/brooklyn/location/cloud/CloudLocationConfig.java
index a44ca49..ad6a11c 100644
--- a/core/src/main/java/org/apache/brooklyn/location/cloud/CloudLocationConfig.java
+++ b/core/src/main/java/org/apache/brooklyn/location/cloud/CloudLocationConfig.java
@@ -28,10 +28,9 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicConfigKey;
 
 import org.apache.brooklyn.api.location.MachineLocationCustomizer;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.location.basic.LocationConfigKeys;
 
-import brooklyn.util.flags.SetFromFlag;
-
 public interface CloudLocationConfig {
 
     public static final ConfigKey<String> CLOUD_ENDPOINT = LocationConfigKeys.CLOUD_ENDPOINT;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/cloud/names/AbstractCloudMachineNamer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/cloud/names/AbstractCloudMachineNamer.java b/core/src/main/java/org/apache/brooklyn/location/cloud/names/AbstractCloudMachineNamer.java
index b06b88a..2df845e 100644
--- a/core/src/main/java/org/apache/brooklyn/location/cloud/names/AbstractCloudMachineNamer.java
+++ b/core/src/main/java/org/apache/brooklyn/location/cloud/names/AbstractCloudMachineNamer.java
@@ -20,9 +20,9 @@ package org.apache.brooklyn.location.cloud.names;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.trait.HasShortName;
-
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
-import brooklyn.util.config.ConfigBag;
+
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/cloud/names/BasicCloudMachineNamer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/cloud/names/BasicCloudMachineNamer.java b/core/src/main/java/org/apache/brooklyn/location/cloud/names/BasicCloudMachineNamer.java
index 818053d..26c41ee 100644
--- a/core/src/main/java/org/apache/brooklyn/location/cloud/names/BasicCloudMachineNamer.java
+++ b/core/src/main/java/org/apache/brooklyn/location/cloud/names/BasicCloudMachineNamer.java
@@ -20,9 +20,9 @@ package org.apache.brooklyn.location.cloud.names;
 
 import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
-
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
-import brooklyn.util.config.ConfigBag;
+
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.StringShortener;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/cloud/names/CloudMachineNamer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/cloud/names/CloudMachineNamer.java b/core/src/main/java/org/apache/brooklyn/location/cloud/names/CloudMachineNamer.java
index df7fd8b..b475436 100644
--- a/core/src/main/java/org/apache/brooklyn/location/cloud/names/CloudMachineNamer.java
+++ b/core/src/main/java/org/apache/brooklyn/location/cloud/names/CloudMachineNamer.java
@@ -20,10 +20,9 @@ package org.apache.brooklyn.location.cloud.names;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
 
-import brooklyn.util.config.ConfigBag;
-
 /**
  * Interface used to construct names for individual cloud machines and for groups of machines.
  * <p>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/cloud/names/CustomMachineNamer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/cloud/names/CustomMachineNamer.java b/core/src/main/java/org/apache/brooklyn/location/cloud/names/CustomMachineNamer.java
index 472adde..0bac6c8 100644
--- a/core/src/main/java/org/apache/brooklyn/location/cloud/names/CustomMachineNamer.java
+++ b/core/src/main/java/org/apache/brooklyn/location/cloud/names/CustomMachineNamer.java
@@ -21,14 +21,16 @@ package org.apache.brooklyn.location.cloud.names;
 import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityInternal;
+
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
-import brooklyn.util.config.ConfigBag;
+
 import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/dynamic/DynamicLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/dynamic/DynamicLocation.java b/core/src/main/java/org/apache/brooklyn/location/dynamic/DynamicLocation.java
index 4c38b7e..5b6fd05 100644
--- a/core/src/main/java/org/apache/brooklyn/location/dynamic/DynamicLocation.java
+++ b/core/src/main/java/org/apache/brooklyn/location/dynamic/DynamicLocation.java
@@ -20,12 +20,12 @@ package org.apache.brooklyn.location.dynamic;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import com.google.common.annotations.Beta;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * A location that is created and owned by an entity at runtime.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/dynamic/LocationOwner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/dynamic/LocationOwner.java b/core/src/main/java/org/apache/brooklyn/location/dynamic/LocationOwner.java
index b061b69..84348cb 100644
--- a/core/src/main/java/org/apache/brooklyn/location/dynamic/LocationOwner.java
+++ b/core/src/main/java/org/apache/brooklyn/location/dynamic/LocationOwner.java
@@ -24,12 +24,12 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationDefinition;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.annotations.Beta;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/geo/HostGeoInfo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/geo/HostGeoInfo.java b/core/src/main/java/org/apache/brooklyn/location/geo/HostGeoInfo.java
index ad05bbd..c85060c 100644
--- a/core/src/main/java/org/apache/brooklyn/location/geo/HostGeoInfo.java
+++ b/core/src/main/java/org/apache/brooklyn/location/geo/HostGeoInfo.java
@@ -26,13 +26,13 @@ import javax.annotation.Nullable;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.AddressableLocation;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.location.basic.AbstractLocation;
 import org.apache.brooklyn.location.basic.LocationConfigKeys;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.internal.BrooklynSystemProperties;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/location/geo/LocalhostExternalIpLoader.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/geo/LocalhostExternalIpLoader.java b/core/src/main/java/org/apache/brooklyn/location/geo/LocalhostExternalIpLoader.java
index 1d31f0f..7235e41 100644
--- a/core/src/main/java/org/apache/brooklyn/location/geo/LocalhostExternalIpLoader.java
+++ b/core/src/main/java/org/apache/brooklyn/location/geo/LocalhostExternalIpLoader.java
@@ -26,10 +26,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.text.StringPredicates;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java b/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
index d5590fc..d6a9ed0 100644
--- a/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
+++ b/core/src/test/java/brooklyn/camp/lite/CampYamlLiteTest.java
@@ -55,15 +55,15 @@ import org.apache.brooklyn.core.catalog.internal.CatalogDto;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.core.management.osgi.OsgiStandaloneTest;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.effector.AddChildrenEffector;
 import brooklyn.entity.effector.Effectors;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.stream.Streams;
 
 import com.google.common.base.Joiner;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/camp/lite/TestAppAssemblyInstantiator.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/camp/lite/TestAppAssemblyInstantiator.java b/core/src/test/java/brooklyn/camp/lite/TestAppAssemblyInstantiator.java
index 22d3ab8..2fa3415 100644
--- a/core/src/test/java/brooklyn/camp/lite/TestAppAssemblyInstantiator.java
+++ b/core/src/test/java/brooklyn/camp/lite/TestAppAssemblyInstantiator.java
@@ -32,13 +32,13 @@ import java.util.Set;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
 
 import brooklyn.camp.brooklyn.api.AssemblyTemplateSpecInstantiator;
 import brooklyn.camp.brooklyn.api.HasBrooklynManagementContext;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 
 /** simple illustrative instantiator which always makes a {@link TestApplication}, populated with {@link TestEntity} children,
  * all setting {@link TestEntity#CONF_NAME} for the name in the plan and in the service specs

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java b/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
index 396c76a..7ee1177 100644
--- a/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
+++ b/core/src/test/java/brooklyn/enricher/basic/BasicEnricherTest.java
@@ -25,6 +25,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EnricherSpec;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestApplicationNoEnrichersImpl;
 import org.testng.Assert;
@@ -38,7 +39,6 @@ import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.BrooklynConfigKeys;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * Test that enricher can be created and accessed, by construction and by spec

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/EffectorSayHiTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/EffectorSayHiTest.java b/core/src/test/java/brooklyn/entity/EffectorSayHiTest.java
index 62579e3..80cfe2a 100644
--- a/core/src/test/java/brooklyn/entity/EffectorSayHiTest.java
+++ b/core/src/test/java/brooklyn/entity/EffectorSayHiTest.java
@@ -34,6 +34,7 @@ import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.management.ExecutionContext;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.task.BasicTask;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.BeforeMethod;
@@ -45,7 +46,6 @@ import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.MethodEffector;
 import brooklyn.entity.trait.Startable;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.task.BasicTask;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/SetFromFlagTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/SetFromFlagTest.java b/core/src/test/java/brooklyn/entity/SetFromFlagTest.java
index c5cfc0b..08d0428 100644
--- a/core/src/test/java/brooklyn/entity/SetFromFlagTest.java
+++ b/core/src/test/java/brooklyn/entity/SetFromFlagTest.java
@@ -24,6 +24,7 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.AbstractEntity;
@@ -31,7 +32,6 @@ import brooklyn.entity.basic.AbstractEntity;
 import org.apache.brooklyn.location.basic.PortRanges;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
 
 public class SetFromFlagTest {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/basic/ConfigMapTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/ConfigMapTest.java b/core/src/test/java/brooklyn/entity/basic/ConfigMapTest.java
index a532d15..f67a193 100644
--- a/core/src/test/java/brooklyn/entity/basic/ConfigMapTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/ConfigMapTest.java
@@ -35,6 +35,8 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.ExecutionManager;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.apache.brooklyn.core.util.task.DeferredSupplier;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
@@ -46,8 +48,6 @@ import brooklyn.config.ConfigPredicates;
 import brooklyn.entity.BrooklynAppUnitTestSupport;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.IntegerAttributeSensorAndConfigKey;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.task.BasicTask;
-import brooklyn.util.task.DeferredSupplier;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/basic/DependentConfigurationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/DependentConfigurationTest.java b/core/src/test/java/brooklyn/entity/basic/DependentConfigurationTest.java
index 2919055..dd107aa 100644
--- a/core/src/test/java/brooklyn/entity/basic/DependentConfigurationTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/DependentConfigurationTest.java
@@ -31,6 +31,7 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicTask;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.slf4j.Logger;
@@ -46,7 +47,6 @@ import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.javalang.JavaClassNames;
-import brooklyn.util.task.BasicTask;
 import brooklyn.util.text.StringPredicates;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/basic/EntityConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/EntityConfigTest.java b/core/src/test/java/brooklyn/entity/basic/EntityConfigTest.java
index 4878e33..e41e3a3 100644
--- a/core/src/test/java/brooklyn/entity/basic/EntityConfigTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/EntityConfigTest.java
@@ -22,13 +22,13 @@ import static org.testng.Assert.assertEquals;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.config.ConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java b/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
index 0bb8c2f..80ebfb7 100644
--- a/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.apache.brooklyn.test.entity.TestEntityImpl;
 import org.apache.brooklyn.test.entity.TestEntityNoEnrichersImpl;
@@ -42,7 +43,6 @@ import org.apache.brooklyn.location.basic.SimulatedLocation;
 
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.test.Asserts;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/basic/MapListAndOtherStructuredConfigKeyTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/MapListAndOtherStructuredConfigKeyTest.groovy b/core/src/test/java/brooklyn/entity/basic/MapListAndOtherStructuredConfigKeyTest.groovy
index a52e7d5..86bdc18 100644
--- a/core/src/test/java/brooklyn/entity/basic/MapListAndOtherStructuredConfigKeyTest.groovy
+++ b/core/src/test/java/brooklyn/entity/basic/MapListAndOtherStructuredConfigKeyTest.groovy
@@ -39,7 +39,7 @@ import org.apache.brooklyn.test.entity.TestApplication
 import org.apache.brooklyn.test.entity.TestEntity
 import brooklyn.util.collections.MutableMap
 import brooklyn.util.exceptions.Exceptions
-import brooklyn.util.task.DeferredSupplier
+import org.apache.brooklyn.core.util.task.DeferredSupplier
 
 import com.google.common.collect.ImmutableList
 import com.google.common.collect.ImmutableSet

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/basic/SanitizerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/SanitizerTest.java b/core/src/test/java/brooklyn/entity/basic/SanitizerTest.java
index c9d40a5..ed07c75 100644
--- a/core/src/test/java/brooklyn/entity/basic/SanitizerTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/SanitizerTest.java
@@ -22,10 +22,9 @@ import static org.testng.Assert.assertEquals;
 
 import java.util.Map;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.testng.annotations.Test;
 
-import brooklyn.util.config.ConfigBag;
-
 import com.google.common.collect.ImmutableMap;
 
 public class SanitizerTest {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/effector/EffectorBasicTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/effector/EffectorBasicTest.java b/core/src/test/java/brooklyn/entity/effector/EffectorBasicTest.java
index fa963c3..f8f4eb1 100644
--- a/core/src/test/java/brooklyn/entity/effector/EffectorBasicTest.java
+++ b/core/src/test/java/brooklyn/entity/effector/EffectorBasicTest.java
@@ -26,6 +26,7 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.HasTaskChildren;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.test.TestUtils;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.slf4j.Logger;
@@ -43,7 +44,6 @@ import org.apache.brooklyn.location.basic.SimulatedLocation;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.collect.ImmutableList;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/effector/EffectorConcatenateTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/effector/EffectorConcatenateTest.java b/core/src/test/java/brooklyn/entity/effector/EffectorConcatenateTest.java
index 56382d8..63b10da 100644
--- a/core/src/test/java/brooklyn/entity/effector/EffectorConcatenateTest.java
+++ b/core/src/test/java/brooklyn/entity/effector/EffectorConcatenateTest.java
@@ -30,6 +30,8 @@ import java.util.concurrent.atomic.AtomicReference;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.ExecutionManager;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestApplicationImpl;
 import org.slf4j.Logger;
@@ -45,8 +47,6 @@ import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.MethodEffector;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.task.BasicExecutionContext;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/effector/EffectorTaskTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/effector/EffectorTaskTest.java b/core/src/test/java/brooklyn/entity/effector/EffectorTaskTest.java
index 38dd2b8..0f6f041 100644
--- a/core/src/test/java/brooklyn/entity/effector/EffectorTaskTest.java
+++ b/core/src/test/java/brooklyn/entity/effector/EffectorTaskTest.java
@@ -26,6 +26,11 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.HasTaskChildren;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicSequentialTask;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -38,12 +43,7 @@ import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.effector.EffectorTasks.EffectorTaskFactory;
 import brooklyn.entity.trait.Startable;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.DynamicSequentialTask;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/Dumpers.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/Dumpers.java b/core/src/test/java/brooklyn/entity/rebind/Dumpers.java
index 12e47ad..934df5c 100644
--- a/core/src/test/java/brooklyn/entity/rebind/Dumpers.java
+++ b/core/src/test/java/brooklyn/entity/rebind/Dumpers.java
@@ -31,11 +31,11 @@ import java.util.Random;
 
 import javax.annotation.Nullable;
 
+import org.apache.brooklyn.core.util.flags.FlagUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.javalang.Serializers;
 import brooklyn.util.javalang.Serializers.ObjectReplacer;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindCatalogEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogEntityTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogEntityTest.java
index 3debe30..dc440bc 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogEntityTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogEntityTest.java
@@ -45,10 +45,9 @@ import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.ha.ManagementNodeState;
 import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.javalang.UrlClassLoader;
 import org.apache.brooklyn.test.TestResourceUnavailableException;
 
-import brooklyn.util.javalang.UrlClassLoader;
-
 import com.google.common.base.Function;
 
 public class RebindCatalogEntityTest extends RebindTestFixture<StartableApplication> {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
index 3102dd2..ea21787 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
@@ -32,6 +32,7 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EnricherSpec;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -55,7 +56,6 @@ import org.apache.brooklyn.location.basic.SimulatedLocation;
 
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.StringFunctions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindEntityDynamicTypeInfoTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindEntityDynamicTypeInfoTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindEntityDynamicTypeInfoTest.java
index d7ad132..883b1aa 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindEntityDynamicTypeInfoTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindEntityDynamicTypeInfoTest.java
@@ -27,6 +27,7 @@ import java.util.concurrent.ExecutionException;
 
 import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.slf4j.Logger;
@@ -38,7 +39,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.effector.EffectorBody;
 import brooklyn.entity.effector.Effectors;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.stream.Streams;
 
 public class RebindEntityDynamicTypeInfoTest extends RebindTestFixtureWithApp {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
index 992ca8e..3ece27b 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindEntityTest.java
@@ -53,6 +53,7 @@ import org.apache.brooklyn.api.management.ha.ManagementNodeState;
 import org.apache.brooklyn.api.mementos.BrooklynMementoManifest;
 import org.apache.brooklyn.api.mementos.EntityMemento;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.apache.brooklyn.test.entity.TestEntityImpl;
@@ -79,7 +80,6 @@ import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Durations;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindFailuresTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindFailuresTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindFailuresTest.java
index ba168cf..674d77e 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindFailuresTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindFailuresTest.java
@@ -40,6 +40,7 @@ import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -54,7 +55,6 @@ import brooklyn.entity.rebind.RebindEntityTest.MyEntity;
 import brooklyn.entity.rebind.RebindEntityTest.MyEntityImpl;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.os.Os;
 
 import com.google.common.base.Charsets;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindFeedTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindFeedTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindFeedTest.java
index c368a7a..d0d03d6 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindFeedTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindFeedTest.java
@@ -29,6 +29,8 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.management.internal.BrooklynGarbageCollector;
+import org.apache.brooklyn.core.util.http.BetterMockWebServer;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.apache.brooklyn.test.entity.TestEntityImpl.TestEntityWithoutEnrichers;
@@ -57,8 +59,6 @@ import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableList;
-import brooklyn.util.http.BetterMockWebServer;
-import brooklyn.util.task.BasicExecutionManager;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindFeedWithHaTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindFeedWithHaTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindFeedWithHaTest.java
index 868665f..c42090b 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindFeedWithHaTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindFeedWithHaTest.java
@@ -31,6 +31,8 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.http.BetterMockWebServer;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -41,9 +43,7 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import brooklyn.util.http.BetterMockWebServer;
 import brooklyn.util.repeat.Repeater;
-import brooklyn.util.task.BasicExecutionManager;
 import brooklyn.util.time.Duration;
 
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
index 8c93fc7..7e54ac4 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindLocationTest.java
@@ -33,6 +33,7 @@ import org.apache.brooklyn.api.entity.rebind.RebindSupport;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.mementos.LocationMemento;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.testng.Assert;
 import org.testng.annotations.BeforeMethod;
@@ -46,7 +47,6 @@ import org.apache.brooklyn.location.basic.AbstractLocation;
 
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindManagerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindManagerTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindManagerTest.java
index 676d040..c1312e5 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindManagerTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindManagerTest.java
@@ -25,13 +25,12 @@ import java.util.concurrent.Callable;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicTask;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.apache.brooklyn.test.entity.TestEntityImpl;
 import org.testng.annotations.Test;
 
-import brooklyn.util.task.BasicTask;
-import brooklyn.util.task.DynamicTasks;
-
 import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
index f77e3d4..d74a6fc 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
@@ -33,6 +33,7 @@ import org.apache.brooklyn.api.mementos.BrooklynMementoManifest;
 import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.testng.annotations.Test;
@@ -50,7 +51,6 @@ import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
index 5c39216..966ecea 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindTestFixture.java
@@ -43,6 +43,7 @@ import org.apache.brooklyn.api.mementos.BrooklynMementoManifest;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
 
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityFunctions;
@@ -53,7 +54,6 @@ import brooklyn.entity.rebind.persister.PersistMode;
 import brooklyn.entity.trait.Startable;
 import brooklyn.util.os.Os;
 import brooklyn.util.repeat.Repeater;
-import brooklyn.util.task.BasicExecutionManager;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/rebind/transformer/impl/XsltTransformerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/transformer/impl/XsltTransformerTest.java b/core/src/test/java/brooklyn/entity/rebind/transformer/impl/XsltTransformerTest.java
index 5791dd4..cdd89a5 100644
--- a/core/src/test/java/brooklyn/entity/rebind/transformer/impl/XsltTransformerTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/transformer/impl/XsltTransformerTest.java
@@ -20,11 +20,11 @@ package brooklyn.entity.rebind.transformer.impl;
 
 import static org.testng.Assert.assertEquals;
 
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.testng.annotations.Test;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.os.Os;
-import brooklyn.util.text.TemplateProcessor;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/trait/FailingEntity.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/trait/FailingEntity.java b/core/src/test/java/brooklyn/entity/trait/FailingEntity.java
index 4d06fc4..4b8c85e 100644
--- a/core/src/test/java/brooklyn/entity/trait/FailingEntity.java
+++ b/core/src/test/java/brooklyn/entity/trait/FailingEntity.java
@@ -22,11 +22,11 @@ import java.util.List;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.TestEntity;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/trait/FailingEntityImpl.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/trait/FailingEntityImpl.java b/core/src/test/java/brooklyn/entity/trait/FailingEntityImpl.java
index 4d1d9f9..e4a5d77 100644
--- a/core/src/test/java/brooklyn/entity/trait/FailingEntityImpl.java
+++ b/core/src/test/java/brooklyn/entity/trait/FailingEntityImpl.java
@@ -22,12 +22,12 @@ import java.util.Collection;
 
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.test.entity.TestEntityImpl;
 import org.testng.Assert;
 
 import brooklyn.entity.basic.Entities;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.Tasks;
 
 public class FailingEntityImpl extends TestEntityImpl implements FailingEntity {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/entity/trait/StartableMethodsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/trait/StartableMethodsTest.java b/core/src/test/java/brooklyn/entity/trait/StartableMethodsTest.java
index 1a3537d..f457b0d 100644
--- a/core/src/test/java/brooklyn/entity/trait/StartableMethodsTest.java
+++ b/core/src/test/java/brooklyn/entity/trait/StartableMethodsTest.java
@@ -23,6 +23,7 @@ import static org.testng.Assert.fail;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -30,8 +31,8 @@ import org.testng.annotations.Test;
 import brooklyn.entity.BrooklynAppUnitTestSupport;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.trait.FailingEntity.RecordingEventListener;
+
 import org.apache.brooklyn.location.basic.SimulatedLocation;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.collect.ImmutableList;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/event/feed/PollerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/event/feed/PollerTest.java b/core/src/test/java/brooklyn/event/feed/PollerTest.java
index fc799e0..1427c93 100644
--- a/core/src/test/java/brooklyn/event/feed/PollerTest.java
+++ b/core/src/test/java/brooklyn/event/feed/PollerTest.java
@@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,7 +36,6 @@ import org.testng.annotations.Test;
 import brooklyn.entity.BrooklynAppUnitTestSupport;
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.task.DynamicTasks;
 import brooklyn.util.time.Duration;
 
 public class PollerTest extends BrooklynAppUnitTestSupport {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java
----------------------------------------------------------------------
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 aa16b8c..e367bdf 100644
--- a/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java
+++ b/core/src/test/java/brooklyn/event/feed/http/HttpFeedTest.java
@@ -29,6 +29,8 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.http.BetterMockWebServer;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,8 +51,6 @@ import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.guava.Functionals;
-import brooklyn.util.http.BetterMockWebServer;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.net.Networking;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/event/feed/http/HttpValueFunctionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/event/feed/http/HttpValueFunctionsTest.java b/core/src/test/java/brooklyn/event/feed/http/HttpValueFunctionsTest.java
index 7769427..2f83cc5 100644
--- a/core/src/test/java/brooklyn/event/feed/http/HttpValueFunctionsTest.java
+++ b/core/src/test/java/brooklyn/event/feed/http/HttpValueFunctionsTest.java
@@ -25,11 +25,10 @@ import static org.testng.Assert.assertTrue;
 
 import java.util.NoSuchElementException;
 
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import brooklyn.util.http.HttpToolResponse;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.gson.JsonElement;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java b/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
index df779e1..5ac58c9 100644
--- a/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
+++ b/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
@@ -23,13 +23,13 @@ import static org.testng.Assert.assertEquals;
 import java.util.Map;
 
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.testng.annotations.Test;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.BrooklynAppUnitTestSupport;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * Test that policy can be created and accessed, by construction and by spec

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/qa/longevity/EntityCleanupLongevityTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/qa/longevity/EntityCleanupLongevityTestFixture.java b/core/src/test/java/brooklyn/qa/longevity/EntityCleanupLongevityTestFixture.java
index 85eaf3d..790bfe1 100644
--- a/core/src/test/java/brooklyn/qa/longevity/EntityCleanupLongevityTestFixture.java
+++ b/core/src/test/java/brooklyn/qa/longevity/EntityCleanupLongevityTestFixture.java
@@ -29,6 +29,8 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.core.management.internal.AbstractManagementContext;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.TaskScheduler;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -46,8 +48,6 @@ import brooklyn.internal.storage.impl.BrooklynStorageImpl;
 
 import org.apache.brooklyn.location.basic.SimulatedLocation;
 
-import brooklyn.util.task.BasicExecutionManager;
-import brooklyn.util.task.TaskScheduler;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/qa/performance/FilePersistencePerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/qa/performance/FilePersistencePerformanceTest.java b/core/src/test/java/brooklyn/qa/performance/FilePersistencePerformanceTest.java
index 098648d..0b35670 100644
--- a/core/src/test/java/brooklyn/qa/performance/FilePersistencePerformanceTest.java
+++ b/core/src/test/java/brooklyn/qa/performance/FilePersistencePerformanceTest.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.brooklyn.core.util.internal.ssh.process.ProcessTool;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -31,7 +32,6 @@ import brooklyn.entity.rebind.persister.FileBasedStoreObjectAccessor;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.internal.ssh.process.ProcessTool;
 
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableList;



[37/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/ResourceUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/ResourceUtils.java b/core/src/main/java/brooklyn/util/ResourceUtils.java
deleted file mode 100644
index 338b223..0000000
--- a/core/src/main/java/brooklyn/util/ResourceUtils.java
+++ /dev/null
@@ -1,639 +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 brooklyn.util;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.InetAddress;
-import java.net.JarURLConnection;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.apache.brooklyn.api.management.classloading.BrooklynClassLoadingContext;
-import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
-import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
-import org.apache.brooklyn.core.internal.BrooklynInitialization;
-import org.apache.brooklyn.core.management.classloading.JavaBrooklynClassLoadingContext;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.auth.Credentials;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.util.EntityUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpTool.HttpClientBuilder;
-import brooklyn.util.javalang.Threads;
-import brooklyn.util.net.Urls;
-import brooklyn.util.os.Os;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.text.DataUriSchemeParser;
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Throwables;
-import com.google.common.collect.Lists;
-
-public class ResourceUtils {
-    
-    private static final Logger log = LoggerFactory.getLogger(ResourceUtils.class);
-    private static final List<Function<Object,BrooklynClassLoadingContext>> classLoaderProviders = Lists.newCopyOnWriteArrayList();
-
-    private BrooklynClassLoadingContext loader = null;
-    private String context = null;
-    private Object contextObject = null;
-    
-    static { BrooklynInitialization.initNetworking(); }
-    
-    /**
-     * Creates a {@link ResourceUtils} object with a specific class loader and context.
-     * <p>
-     * Use the provided {@link ClassLoader} object for class loading with the
-     * {@code contextObject} for context and the {@code contextMessage} string for
-     * error messages.
-     *
-     * @see ResourceUtils#create(Object, String)
-     * @see ResourceUtils#create(Object)
-     */
-    public static final ResourceUtils create(ClassLoader loader, Object contextObject, String contextMessage) {
-        return new ResourceUtils(loader, contextObject, contextMessage);
-    }
-
-    /**
-     * Creates a {@link ResourceUtils} object with a specific class loader and context.
-     * <p>
-     * Use the provided {@link BrooklynClassLoadingContext} object for class loading with the
-     * {@code contextObject} for context and the {@code contextMessage} string for
-     * error messages.
-     *
-     * @see ResourceUtils#create(Object, String)
-     * @see ResourceUtils#create(Object)
-     */
-    public static final ResourceUtils create(BrooklynClassLoadingContext loader, Object contextObject, String contextMessage) {
-        return new ResourceUtils(loader, contextObject, contextMessage);
-    }
-
-    /**
-     * Creates a {@link ResourceUtils} object with the given context.
-     * <p>
-     * Uses the {@link ClassLoader} of the given {@code contextObject} for class
-     * loading and the {@code contextMessage} string for error messages.
-     *
-     * @see ResourceUtils#create(ClassLoader, Object, String)
-     * @see ResourceUtils#create(Object)
-     */
-    public static final ResourceUtils create(Object contextObject, String contextMessage) {
-        return new ResourceUtils(contextObject, contextMessage);
-    }
-
-    /**
-     * Creates a {@link ResourceUtils} object with the given context.
-     * <p>
-     * Uses the {@link ClassLoader} of the given {@code contextObject} for class
-     * loading and its {@link Object#toString()} (preceded by the word 'for') as
-     * the string used in error messages.
-     *
-     * @see ResourceUtils#create(ClassLoader, Object, String)
-     * @see ResourceUtils#create(Object)
-     */
-    public static final ResourceUtils create(Object contextObject) {
-        return new ResourceUtils(contextObject);
-    }
-
-    /**
-     * Creates a {@link ResourceUtils} object with itself as the context.
-     *
-     * @see ResourceUtils#create(Object)
-     */
-    public static final ResourceUtils create() {
-        return new ResourceUtils(null);
-    }
-
-    public ResourceUtils(ClassLoader loader, Object contextObject, String contextMessage) {
-        this(getClassLoadingContextInternal(loader, contextObject), contextObject, contextMessage);
-    }
-    
-    public ResourceUtils(BrooklynClassLoadingContext loader, Object contextObject, String contextMessage) {
-        this.loader = loader;
-        this.contextObject = contextObject;
-        this.context = contextMessage;
-    }
-
-    public ResourceUtils(Object contextObject, String contextMessage) {
-        this(contextObject==null ? null : getClassLoadingContextInternal(null, contextObject), contextObject, contextMessage);
-    }
-
-    public ResourceUtils(Object contextObject) {
-        this(contextObject, Strings.toString(contextObject));
-    }
-    
-    /** used to register custom mechanisms for getting classloaders given an object */
-    public static void addClassLoaderProvider(Function<Object,BrooklynClassLoadingContext> provider) {
-        classLoaderProviders.add(provider);
-    }
-    
-    // TODO rework this class so it accepts but does not require a BCLC ?
-    @SuppressWarnings("deprecation")
-    protected static BrooklynClassLoadingContext getClassLoadingContextInternal(ClassLoader loader, Object contextObject) {
-        if (contextObject instanceof BrooklynClassLoadingContext)
-            return (BrooklynClassLoadingContext) contextObject;
-        
-        for (Function<Object,BrooklynClassLoadingContext> provider: classLoaderProviders) {
-            BrooklynClassLoadingContext result = provider.apply(contextObject);
-            if (result!=null) return result;
-        }
-
-        BrooklynClassLoadingContext bl = BrooklynLoaderTracker.getLoader();
-        ManagementContext mgmt = (bl!=null ? bl.getManagementContext() : null);
-
-        ClassLoader cl = loader;
-        if (cl==null) cl = contextObject instanceof Class ? ((Class<?>)contextObject).getClassLoader() : 
-            contextObject instanceof ClassLoader ? ((ClassLoader)contextObject) : 
-                contextObject.getClass().getClassLoader();
-            
-        return JavaBrooklynClassLoadingContext.create(mgmt, cl);
-    }
-    
-    /** This should not be exposed as it risks it leaking into places where it would be serialized.
-     * Better for callers use {@link CatalogUtils#getClassLoadingContext(org.apache.brooklyn.api.entity.Entity)} or similar. }.
-     */
-    private BrooklynClassLoadingContext getLoader() {
-        return (loader!=null ? loader : getClassLoadingContextInternal(null, contextObject!=null ? contextObject : this));
-    }
-
-    /**
-     * @return all resources in Brooklyn's {@link BrooklynClassLoadingContext} with the given name.
-     */
-    public Iterable<URL> getResources(String name) {
-        return getLoader().getResources(name);
-    }
-    
-    /**
-     * Takes a string which is treated as a URL (with some extended "schemes" also expected),
-     * or as a path to something either on the classpath (absolute only) or the local filesystem (relative or absolute, depending on leading slash)
-     * <p>
-     * URLs can be of the form <b>classpath://com/acme/Foo.properties</b>
-     * as well as <b>file:///home/...</b> and <b>http://acme.com/...</b>.
-     * <p>
-     * Throws exception if not found, using the context parameter passed into the constructor.
-     * <p>
-     * TODO may want OSGi, or typed object; should consider pax url
-     * 
-     * @return a stream, or throws exception (never returns null)
-     */
-    public InputStream getResourceFromUrl(String url) {
-        try {
-            if (url==null) throw new NullPointerException("Cannot read from null");
-            if (url=="") throw new NullPointerException("Cannot read from empty string");
-            String orig = url;
-            String protocol = Urls.getProtocol(url);
-            if (protocol!=null) {
-                if ("classpath".equals(protocol)) {
-                    try {
-                        return getResourceViaClasspath(url);
-                    } catch (IOException e) {
-                        //catch the above because both orig and modified url may be interesting
-                        throw new IOException("Error accessing "+orig+": "+e, e);
-                    }
-                }
-                if ("sftp".equals(protocol)) {
-                    try {
-                        return getResourceViaSftp(url);
-                    } catch (IOException e) {
-                        throw new IOException("Error accessing "+orig+": "+e, e);
-                    }
-                }
-
-                if ("file".equals(protocol))
-                    url = tidyFileUrl(url);
-                
-                if ("data".equals(protocol)) {
-                    return new DataUriSchemeParser(url).lax().parse().getDataAsInputStream();
-                }
-
-                if ("http".equals(protocol) || "https".equals(protocol)) {
-                    return getResourceViaHttp(url);
-                }
-
-                return new URL(url).openStream();
-            }
-
-            try {
-                //try as classpath reference, then as file
-                try {
-                    URL u = getLoader().getResource(url);
-                    if (u!=null) return u.openStream();
-                } catch (IllegalArgumentException e) {
-                    //Felix installs an additional URL to the system classloader
-                    //which throws an IllegalArgumentException when passed a
-                    //windows path. See ExtensionManager.java static initializer.
-
-                    //ignore, not a classpath resource
-                }
-                if (url.startsWith("/")) {
-                    //some getResource calls fail if argument starts with /
-                    String urlNoSlash = url;
-                    while (urlNoSlash.startsWith("/")) urlNoSlash = urlNoSlash.substring(1);
-                    URL u = getLoader().getResource(urlNoSlash);
-                    if (u!=null) return u.openStream();
-//                    //Class.getResource can require a /  (else it attempts to be relative) but Class.getClassLoader doesn't
-//                    u = getLoader().getResource("/"+urlNoSlash);
-//                    if (u!=null) return u.openStream();
-                }
-                File f;
-                // but first, if it starts with tilde, treat specially
-                if (url.startsWith("~/")) {
-                    f = new File(Os.home(), url.substring(2));
-                } else if (url.startsWith("~\\")) {
-                    f = new File(Os.home(), url.substring(2));
-                } else {
-                    f = new File(url);
-                }
-                if (f.exists()) return new FileInputStream(f);
-            } catch (IOException e) {
-                //catch the above because both u and modified url will be interesting
-                throw new IOException("Error accessing "+orig+": "+e, e);
-            }
-            throw new IOException("'"+orig+"' not found on classpath or filesystem");
-        } catch (Exception e) {
-            if (context!=null) {
-                throw new RuntimeException("Error getting resource '"+url+"' for "+context+": "+e, e);
-            } else {
-                throw Exceptions.propagate(e);
-            }
-        }
-    }
-    
-    private final static Pattern pattern = Pattern.compile("^file:/*~/+(.*)$");
-
-    public static URL tidy(URL url) {
-        // File class has helpful methods for URIs but not URLs. So we convert.
-        URI in;
-        try {
-            in = url.toURI();
-        } catch (URISyntaxException e) {
-            throw Exceptions.propagate(e);
-        }
-        URI out;
-
-        Matcher matcher = pattern.matcher(in.toString());
-        if (matcher.matches()) {
-            // home-relative
-            File home = new File(Os.home());
-            File file = new File(home, matcher.group(1));
-            out = file.toURI();
-        } else if (in.getScheme().equals("file:")) {
-            // some other file, so canonicalize
-            File file = new File(in);
-            out = file.toURI();
-        } else {
-            // some other scheme, so no-op
-            out = in;
-        }
-
-        URL urlOut;
-        try {
-            urlOut = out.toURL();
-        } catch (MalformedURLException e) {
-            throw Exceptions.propagate(e);
-        }
-        if (!urlOut.equals(url) && log.isDebugEnabled()) {
-            log.debug("quietly changing " + url + " to " + urlOut);
-        }
-        return urlOut;
-    }
-    
-    public static String tidyFileUrl(String url) {
-        try {
-            return tidy(new URL(url)).toString();
-        } catch (MalformedURLException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    /** @deprecated since 0.7.0; use method {@link Os#mergePaths(String...)} */ @Deprecated
-    public static String mergeFilePaths(String... items) {
-        return Os.mergePaths(items);
-    }
-    
-    /** @deprecated since 0.7.0; use method {@link Os#tidyPath(String)} */ @Deprecated
-    public static String tidyFilePath(String path) {
-        return Os.tidyPath(path);
-    }
-    
-    /** @deprecated since 0.7.0; use method {@link Urls#getProtocol(String)} */ @Deprecated
-    public static String getProtocol(String url) {
-        return Urls.getProtocol(url);
-    }
-    
-    private InputStream getResourceViaClasspath(String url) throws IOException {
-        assert url.startsWith("classpath:");
-        String subUrl = url.substring("classpath:".length());
-        while (subUrl.startsWith("/")) subUrl = subUrl.substring(1);
-        URL u = getLoader().getResource(subUrl);
-        if (u!=null) return u.openStream();
-        else throw new IOException(subUrl+" not found on classpath");
-    }
-    
-    private InputStream getResourceViaSftp(String url) throws IOException {
-        assert url.startsWith("sftp://");
-        String subUrl = url.substring("sftp://".length());
-        String user;
-        String address;
-        String path;
-        int atIndex = subUrl.indexOf("@");
-        int colonIndex = subUrl.indexOf(":", (atIndex > 0 ? atIndex : 0));
-        if (colonIndex <= 0 || colonIndex <= atIndex) {
-            throw new IllegalArgumentException("Invalid sftp url ("+url+"); IP or hostname must be specified, such as sftp://localhost:/path/to/file");
-        }
-        if (subUrl.length() <= (colonIndex+1)) {
-            throw new IllegalArgumentException("Invalid sftp url ("+url+"); must specify path of remote file, such as sftp://localhost:/path/to/file");
-        }
-        if (atIndex >= 0) {
-            user = subUrl.substring(0, atIndex);
-        } else {
-            user = null;
-        }
-        address = subUrl.substring(atIndex + 1, colonIndex);
-        path = subUrl.substring(colonIndex+1);
-        
-        // TODO messy way to get an SCP session 
-        SshMachineLocation machine = new SshMachineLocation(MutableMap.builder()
-                .putIfNotNull("user", user)
-                .put("address", InetAddress.getByName(address))
-                .build());
-        try {
-            final File tempFile = Os.newTempFile("brooklyn-sftp", "tmp");
-            tempFile.setReadable(true, true);
-            machine.copyFrom(path, tempFile.getAbsolutePath());
-            return new FileInputStream(tempFile) {
-                @Override
-                public void close() throws IOException {
-                    super.close();
-                    tempFile.delete();
-                }
-            };
-        } finally {
-            Streams.closeQuietly(machine);
-        }
-    }
-    
-    //For HTTP(S) targets use HttpClient so
-    //we can do authentication
-    private InputStream getResourceViaHttp(String resource) throws IOException {
-        URI uri = URI.create(resource);
-        HttpClientBuilder builder = HttpTool.httpClientBuilder()
-                .laxRedirect(true)
-                .uri(uri);
-        Credentials credentials = getUrlCredentials(uri.getRawUserInfo());
-        if (credentials != null) {
-            builder.credentials(credentials);
-        }
-        HttpClient client = builder.build();
-        HttpResponse result = client.execute(new HttpGet(resource));
-        int statusCode = result.getStatusLine().getStatusCode();
-        if (HttpTool.isStatusCodeHealthy(statusCode)) {
-            HttpEntity entity = result.getEntity();
-            if (entity != null) {
-                return entity.getContent();
-            } else {
-                return new ByteArrayInputStream(new byte[0]);
-            }
-        } else {
-            EntityUtils.consume(result.getEntity());
-            throw new IllegalStateException("Invalid response invoking " + resource + ": response code " + statusCode);
-        }
-    }
-
-    private Credentials getUrlCredentials(String userInfo) {
-        if (userInfo != null) {
-            String[] arr = userInfo.split(":");
-            String username;
-            String password = null;
-            if (arr.length == 1) {
-                username = urlDecode(arr[0]);
-            } else if (arr.length == 2) {
-                username = urlDecode(arr[0]);
-                password = urlDecode(arr[1]);
-            } else {
-                return null;
-            }
-            return new UsernamePasswordCredentials(username, password);
-        } else {
-            return null;
-        }
-    }
-
-    private String urlDecode(String str) {
-        try {
-            return URLDecoder.decode(str, "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    /** takes {@link #getResourceFromUrl(String)} and reads fully, into a string */
-    public String getResourceAsString(String url) {
-        try {
-            return readFullyString(getResourceFromUrl(url));
-        } catch (Exception e) {
-            log.debug("ResourceUtils got error reading "+url+(context==null?"":" "+context)+" (rethrowing): "+e);
-            throw Throwables.propagate(e);
-        }
-    }
-
-    /** allows failing-fast if URL cannot be read */
-    public String checkUrlExists(String url) {
-        return checkUrlExists(url, null);
-    }
-    
-    public String checkUrlExists(String url, String message) {
-        if (url==null) throw new NullPointerException("URL "+(message!=null ? message+" " : "")+"must not be null");
-        InputStream s;
-        try {
-            s = getResourceFromUrl(url);
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            throw new IllegalArgumentException("Unable to access URL "+(message!=null ? message : "")+": "+url, e);
-        }
-        Streams.closeQuietly(s); 
-        return url;
-    }
-
-    /** tests whether the url exists, returning true or false */
-    public boolean doesUrlExist(String url) {
-        InputStream s = null;
-        try {
-            s = getResourceFromUrl(url);
-            return true;
-        } catch (Exception e) {
-            return false;
-        } finally {
-            Streams.closeQuietly(s);
-        }
-    }
-    
-    /** returns the first available URL */
-    public Optional<String> firstAvailableUrl(String ...urls) {
-        for (String url: urls) {
-            if (doesUrlExist(url)) return Optional.of(url);
-        }
-        return Optional.absent();
-    }
-    
-    /** returns the base directory or JAR from which the context is class-loaded, if possible;
-     * throws exception if not found */
-    public String getClassLoaderDir() {
-        if (contextObject==null) throw new IllegalArgumentException("No suitable context ("+context+") to auto-detect classloader dir");
-        Class<?> cc = contextObject instanceof Class ? (Class<?>)contextObject : contextObject.getClass();
-        return getClassLoaderDir(cc.getCanonicalName().replace('.', '/')+".class");
-    }
-    
-    public String getClassLoaderDir(String resourceInThatDir) {
-        resourceInThatDir = Strings.removeFromStart(resourceInThatDir, "/");
-        URL resourceUrl = getLoader().getResource(resourceInThatDir);
-        if (resourceUrl==null) throw new NoSuchElementException("Resource ("+resourceInThatDir+") not found");
-
-        URL containerUrl = getContainerUrl(resourceUrl, resourceInThatDir);
-
-        if (!"file".equals(containerUrl.getProtocol())) throw new IllegalStateException("Resource ("+resourceInThatDir+") not on file system (at "+containerUrl+")");
-
-        //convert from file: URL to File
-        File file;
-        try {
-            file = new File(containerUrl.toURI());
-        } catch (URISyntaxException e) {
-            throw new IllegalStateException("Resource ("+resourceInThatDir+") found at invalid URI (" + containerUrl + ")", e);
-        }
-        
-        if (!file.exists()) throw new IllegalStateException("Context class url substring ("+containerUrl+") not found on filesystem");
-        return file.getPath();
-        
-    }
-
-    public static URL getContainerUrl(URL url, String resourceInThatDir) {
-        //Switching from manual parsing of jar: and file: URLs to java provided functionality.
-        //The old code was breaking on any Windows path and instead of fixing it, using
-        //the provided Java APIs seemed like the better option since they are already tested
-        //on multiple platforms.
-        boolean isJar = "jar".equals(url.getProtocol());
-        if(isJar) {
-            try {
-                //let java handle the parsing of jar URL, no network connection is established.
-                //Strips the jar protocol:
-                //  jar:file:/<path to jar>!<resourceInThatDir>
-                //  becomes
-                //  file:/<path to jar>
-                JarURLConnection connection = (JarURLConnection) url.openConnection();
-                url = connection.getJarFileURL();
-            } catch (IOException e) {
-                throw new IllegalStateException(e);
-            }
-        } else {
-            //Remove the trailing resouceInThatDir path from the URL, thus getting the parent folder.
-            String path = url.toString();
-            int i = path.indexOf(resourceInThatDir);
-            if (i==-1) throw new IllegalStateException("Resource path ("+resourceInThatDir+") not in url substring ("+url+")");
-            String parent = path.substring(0, i);
-            try {
-                url = new URL(parent);
-            } catch (MalformedURLException e) {
-                throw new IllegalStateException("Resource ("+resourceInThatDir+") found at invalid URL parent (" + parent + ")", e);
-            }
-        }
-        return url;
-    }
-    
-    /** @deprecated since 0.7.0 use {@link Streams#readFullyString(InputStream) */ @Deprecated
-    public static String readFullyString(InputStream is) throws IOException {
-        return Streams.readFullyString(is);
-    }
-
-    /** @deprecated since 0.7.0 use {@link Streams#readFully(InputStream) */ @Deprecated
-    public static byte[] readFullyBytes(InputStream is) throws IOException {
-        return Streams.readFully(is);
-    }
-    
-    /** @deprecated since 0.7.0 use {@link Streams#copy(InputStream, OutputStream)} */ @Deprecated
-    public static void copy(InputStream input, OutputStream output) throws IOException {
-        Streams.copy(input, output);
-    }
-
-    /** @deprecated since 0.7.0; use same method in {@link Os} */ @Deprecated
-    public static File mkdirs(File dir) {
-        return Os.mkdirs(dir);
-    }
-
-    /** @deprecated since 0.7.0; use same method in {@link Os} */ @Deprecated
-    public static File writeToTempFile(InputStream is, String prefix, String suffix) {
-        return Os.writeToTempFile(is, prefix, suffix);
-    }
-    
-    /** @deprecated since 0.7.0; use same method in {@link Os} */ @Deprecated
-    public static File writeToTempFile(InputStream is, File tempDir, String prefix, String suffix) {
-        return Os.writeToTempFile(is, tempDir, prefix, suffix);
-    }
-
-    /** @deprecated since 0.7.0; use method {@link Os#writePropertiesToTempFile(Properties, String, String)} */ @Deprecated
-    public static File writeToTempFile(Properties props, String prefix, String suffix) {
-        return Os.writePropertiesToTempFile(props, prefix, suffix);
-    }
-    
-    /** @deprecated since 0.7.0; use method {@link Os#writePropertiesToTempFile(Properties, File, String, String)} */ @Deprecated
-    public static File writeToTempFile(Properties props, File tempDir, String prefix, String suffix) {
-        return Os.writePropertiesToTempFile(props, tempDir, prefix, suffix);
-    }
-
-    /** @deprecated since 0.7.0; use method {@link Threads#addShutdownHook(Runnable)} */ @Deprecated
-    public static Thread addShutdownHook(final Runnable task) {
-        return Threads.addShutdownHook(task);
-    }
-    /** @deprecated since 0.7.0; use method {@link Threads#removeShutdownHook(Thread)} */ @Deprecated
-    public static boolean removeShutdownHook(Thread hook) {
-        return Threads.removeShutdownHook(hook);
-    }
-
-    /** returns the items with exactly one "/" between items (whether or not the individual items start or end with /),
-     * except where character before the / is a : (url syntax) in which case it will permit multiple (will not remove any) 
-     * @deprecated since 0.7.0 use either {@link Os#mergePathsUnix(String...)} {@link Urls#mergePaths(String...) */ @Deprecated
-    public static String mergePaths(String ...items) {
-        return Urls.mergePaths(items);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/config/ConfigBag.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/config/ConfigBag.java b/core/src/main/java/brooklyn/util/config/ConfigBag.java
deleted file mode 100644
index 2f17748..0000000
--- a/core/src/main/java/brooklyn/util/config/ConfigBag.java
+++ /dev/null
@@ -1,588 +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 brooklyn.util.config;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.ConcurrentModificationException;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.config.ConfigKey.HasConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.javalang.JavaClassNames;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Objects;
-import com.google.common.collect.Sets;
-
-/**
- * Stores config in such a way that usage can be tracked.
- * Either {@link ConfigKey} or {@link String} keys can be inserted;
- * they will be stored internally as strings.
- * It is recommended to use {@link ConfigKey} instances to access,
- * although in some cases (such as setting fields from flags, or copying a map)
- * it may be necessary to mark things as used, or put, when only a string key is available.
- * <p>
- * This bag is order-preserving and thread-safe except where otherwise indicated,
- * currently by synching on this instance (but that behaviour may change).
- * <p>
- * @author alex
- */
-public class ConfigBag {
-
-    private static final Logger log = LoggerFactory.getLogger(ConfigBag.class);
-
-    /** an immutable, empty ConfigBag */
-    public static final ConfigBag EMPTY = new ConfigBag().setDescription("immutable empty config bag").seal();
-    
-    protected String description;
-    
-    private Map<String,Object> config;
-    private final Map<String,Object> unusedConfig;
-    private final boolean live;
-    private boolean sealed = false;
-
-    /** creates a new ConfigBag instance, empty and ready for population */
-    public static ConfigBag newInstance() {
-        return new ConfigBag();
-    }
-
-    /**
-     * Creates an instance that is backed by a "live map" (e.g. storage in a datagrid).
-     * The order-preserving nature of this class is only guaranteed if the
-     * provided storage has those properties. External modifications to the store can cause
-     * {@link ConcurrentModificationException} to be thrown, here or elsewhere. 
-     */
-    public static ConfigBag newLiveInstance(Map<String,Object> storage) {
-        return new ConfigBag(checkNotNull(storage, "storage map must be specified"));
-    }
-
-    public static ConfigBag newInstance(Map<?, ?> config) {
-        ConfigBag result = new ConfigBag();
-        result.putAll(config);
-        return result;
-    }
-
-    /** creates a new ConfigBag instance which includes all of the supplied ConfigBag's values,
-     * but which tracks usage separately (already used values are marked as such,
-     * but uses in the original set will not be marked here, and vice versa) */
-    public static ConfigBag newInstanceCopying(final ConfigBag configBag) {
-        return new ConfigBag().copy(configBag).setDescription(configBag.getDescription());
-    }
-    
-    /** creates a new ConfigBag instance which includes all of the supplied ConfigBag's values,
-     * plus an additional set of &lt;ConfigKey,Object&gt; or &lt;String,Object&gt; pairs
-     * <p>
-     * values from the original set which are used here will be marked as used in the original set
-     * (note: this applies even for values which are overridden and the overridden value is used);
-     * however subsequent uses in the original set will not be marked here
-     */
-    @Beta
-    public static ConfigBag newInstanceExtending(final ConfigBag parentBag) {
-        return new ConfigBagExtendingParent(parentBag);
-    }
-
-    /** @see #newInstanceExtending(ConfigBag) */
-    private static class ConfigBagExtendingParent extends ConfigBag {
-        ConfigBag parentBag;
-        private ConfigBagExtendingParent(ConfigBag parentBag) {
-            this.parentBag = parentBag;
-            copy(parentBag);
-        }
-        @Override
-        public void markUsed(String key) {
-            super.markUsed(key);
-            if (parentBag!=null)
-                parentBag.markUsed(key);
-        }
-    }
-    
-    /** As {@link #newInstanceExtending(ConfigBag)} but also putting the supplied values. */
-    @Beta
-    public static ConfigBag newInstanceExtending(final ConfigBag configBag, Map<?,?> optionalAdditionalValues) {
-        return newInstanceExtending(configBag).putAll(optionalAdditionalValues);
-    }
-
-    /** @deprecated since 0.7.0, not used; kept only for rebind compatibility where the inner class is used 
-     * (now replaced by a static class above) */
-    @Beta @Deprecated
-    public static ConfigBag newInstanceWithInnerClass(final ConfigBag configBag, Map<?,?> optionalAdditionalValues) {
-        return new ConfigBag() {
-            @Override
-            public void markUsed(String key) {
-                super.markUsed(key);
-                configBag.markUsed(key);
-            }
-        }.copy(configBag).putAll(optionalAdditionalValues);
-    }
-
-    public ConfigBag() {
-        config = new LinkedHashMap<String,Object>();
-        unusedConfig = new LinkedHashMap<String,Object>();
-        live = false;
-    }
-    
-    private ConfigBag(Map<String,Object> storage) {
-        this.config = storage;
-        unusedConfig = new LinkedHashMap<String,Object>();
-        live = true;
-    }
-    
-    public ConfigBag setDescription(String description) {
-        if (sealed) 
-            throw new IllegalStateException("Cannot set description to '"+description+"': this config bag has been sealed and is now immutable.");
-        this.description = description;
-        return this;
-    }
-    
-    /** optional description used to provide context for operations */
-    public String getDescription() {
-        return description;
-    }
-    
-    /** current values for all entries 
-     * @return non-modifiable map of strings to object */
-    public synchronized Map<String,Object> getAllConfig() {
-        return MutableMap.copyOf(config).asUnmodifiable();
-    }
-
-    /** current values for all entries in a map where the keys are converted to {@link ConfigKey} instances */
-    public synchronized Map<ConfigKey<?>, ?> getAllConfigAsConfigKeyMap() {
-        Map<ConfigKey<?>,Object> result = MutableMap.of();
-        for (Map.Entry<String,Object> entry: config.entrySet()) {
-            result.put(ConfigKeys.newConfigKey(Object.class, entry.getKey()), entry.getValue());
-        }
-        return result;
-    }
-
-    /** Returns the internal map containing the current values for all entries;
-     * for use where the caller wants to modify this directly and knows it is safe to do so 
-     * <p>
-     * Accesses to the returned map must be synchronized on this bag if the 
-     * thread-safe behaviour is required. */ 
-    public Map<String,Object> getAllConfigMutable() {
-        if (live) {
-            // TODO sealed no longer works as before, because `config` is the backing storage map.
-            // Therefore returning it is dangerous! Even if we were to replace our field with an immutable copy,
-            // the underlying datagrid's map would still be modifiable. We need a way to switch the returned
-            // value's behaviour to sealable (i.e. wrapping the returned map).
-            return (sealed) ? MutableMap.copyOf(config).asUnmodifiable() : config;
-        } else {
-            return config;
-        }
-    }
-
-    /** current values for all entries which have not yet been used 
-     * @return non-modifiable map of strings to object */
-    public synchronized Map<String,Object> getUnusedConfig() {
-        return MutableMap.copyOf(unusedConfig).asUnmodifiable();
-    }
-
-    /** Returns the internal map containing the current values for all entries which have not yet been used;
-     * for use where the caller wants to modify this directly and knows it is safe to do so 
-     * <p>
-     * Accesses to the returned map must be synchronized on this bag if the 
-     * thread-safe behaviour is required. */ 
-    public Map<String,Object> getUnusedConfigMutable() {
-        return unusedConfig;
-    }
-
-    public ConfigBag putAll(Map<?,?> addlConfig) {
-        if (addlConfig==null) return this;
-        for (Map.Entry<?,?> e: addlConfig.entrySet()) {
-            putAsStringKey(e.getKey(), e.getValue());
-        }
-        return this;
-    }
-    
-    public ConfigBag putAll(ConfigBag addlConfig) {
-        return putAll(addlConfig.getAllConfig());
-    }
-    
-    public <T> ConfigBag putIfAbsent(ConfigKey<T> key, T value) {
-        return putIfAbsent(MutableMap.of(key, value));
-    }
-
-    public ConfigBag putAsStringKeyIfAbsent(Object key, Object value) {
-        return putIfAbsent(MutableMap.of(key, value));
-    }
-
-    public synchronized ConfigBag putIfAbsent(Map<?, ?> propertiesToSet) {
-        if (propertiesToSet==null)
-            return this;
-        for (Map.Entry<?, ?> entry: propertiesToSet.entrySet()) {
-            Object key = entry.getKey();
-            if (key instanceof HasConfigKey<?>)
-                key = ((HasConfigKey<?>)key).getConfigKey();
-            if (key instanceof ConfigKey<?>) {
-                if (!containsKey((ConfigKey<?>)key))
-                    putAsStringKey(key, entry.getValue());
-            } else if (key instanceof String) {
-                if (!containsKey((String)key))
-                    putAsStringKey(key, entry.getValue());
-            } else {
-                logInvalidKey(key);
-            }
-        }
-        return this;
-    }
-
-    public ConfigBag putIfAbsent(ConfigBag addlConfig) {
-        return putIfAbsent(addlConfig.getAllConfig());
-    }
-
-
-    @SuppressWarnings("unchecked")
-    public <T> T put(ConfigKey<T> key, T value) {
-        return (T) putStringKey(key.getName(), value);
-    }
-    
-    public <T> ConfigBag putIfNotNull(ConfigKey<T> key, T value) {
-        if (value!=null) put(key, value);
-        return this;
-    }
-
-    public <T> ConfigBag putIfAbsentAndNotNull(ConfigKey<T> key, T value) {
-        if (value!=null) putIfAbsent(key, value);
-        return this;
-    }
-
-    /** as {@link #put(ConfigKey, Object)} but returning this ConfigBag for fluent-style coding */
-    public <T> ConfigBag configure(ConfigKey<T> key, T value) {
-        putStringKey(key.getName(), value);
-        return this;
-    }
-    
-    public <T> ConfigBag configureStringKey(String key, T value) {
-        putStringKey(key, value);
-        return this;
-    }
-    
-    protected synchronized void putAsStringKey(Object key, Object value) {
-        if (key instanceof HasConfigKey<?>) key = ((HasConfigKey<?>)key).getConfigKey();
-        if (key instanceof ConfigKey<?>) key = ((ConfigKey<?>)key).getName();
-        if (key instanceof String) {
-            putStringKey((String)key, value);
-        } else {
-            logInvalidKey(key);
-        }
-    }
-
-    protected void logInvalidKey(Object key) {
-        String message = (key == null ? "Invalid key 'null'" : "Invalid key type "+key.getClass().getCanonicalName()+" ("+key+")") +
-                " being used for configuration, ignoring";
-        log.debug(message, new Throwable("Source of "+message));
-        log.warn(message);
-    }
-    
-    /** recommended to use {@link #put(ConfigKey, Object)} but there are times
-     * (e.g. when copying a map) where we want to put a string key directly 
-     */
-    public synchronized Object putStringKey(String key, Object value) {
-        if (sealed) 
-            throw new IllegalStateException("Cannot insert "+key+"="+value+": this config bag has been sealed and is now immutable.");
-        boolean isNew = !config.containsKey(key);
-        boolean isUsed = !isNew && !unusedConfig.containsKey(key);
-        Object old = config.put(key, value);
-        if (!isUsed) 
-            unusedConfig.put(key, value);
-        //if (!isNew && !isUsed) log.debug("updating config value which has already been used");
-        return old;
-    }
-    public Object putStringKeyIfHasValue(String key, Maybe<?> value) {
-        if (value.isPresent())
-            return putStringKey(key, value.get());
-        return null;
-    }
-    public Object putStringKeyIfNotNull(String key, Object value) {
-        if (value!=null)
-            return putStringKey(key, value);
-        return null;
-    }
-
-    public boolean containsKey(HasConfigKey<?> key) {
-        return containsKey(key.getConfigKey());
-    }
-
-    public boolean containsKey(ConfigKey<?> key) {
-        return containsKey(key.getName());
-    }
-
-    public synchronized boolean containsKey(String key) {
-        return config.containsKey(key);
-    }
-
-    /** returns the value of this config key, falling back to its default (use containsKey to see whether it was contained);
-     * also marks it as having been used (use peek to prevent marking as used)
-     */
-    public <T> T get(ConfigKey<T> key) {
-        return get(key, true);
-    }
-
-    /** gets a value from a string-valued key or null; ConfigKey is preferred, but this is useful in some contexts (e.g. setting from flags) */
-    public Object getStringKey(String key) {
-        return getStringKeyMaybe(key).orNull();
-    }
-    /** gets a {@link Maybe}-wrapped value from a string-valued key; ConfigKey is preferred, but this is useful in some contexts (e.g. setting from flags) */
-    public @Nonnull Maybe<Object> getStringKeyMaybe(String key) {
-        return getStringKeyMaybe(key, true);
-    }
-
-    /** gets a {@link Maybe}-wrapped value from a key, inferring the type of that key (e.g. {@link ConfigKey} or {@link String}) */
-    @Beta
-    public Maybe<Object> getObjKeyMaybe(Object key) {
-        if (key instanceof HasConfigKey<?>) key = ((HasConfigKey<?>)key).getConfigKey();
-        if (key instanceof ConfigKey<?>) key = ((ConfigKey<?>)key).getName();
-        if (key instanceof String) {
-            return getStringKeyMaybe((String)key, true);
-        } else {
-            logInvalidKey(key);
-            return Maybe.absent();
-        }
-    }
-
-    /** like get, but without marking it as used */
-    public <T> T peek(ConfigKey<T> key) {
-        return get(key, false);
-    }
-
-    /** returns the first key in the list for which a value is explicitly set, then defaulting to defaulting value of preferred key */
-    public synchronized <T> T getFirst(ConfigKey<T> preferredKey, ConfigKey<T> ...otherCurrentKeysInOrderOfPreference) {
-        if (containsKey(preferredKey)) 
-            return get(preferredKey);
-        for (ConfigKey<T> key: otherCurrentKeysInOrderOfPreference) {
-            if (containsKey(key)) 
-                return get(key);
-        }
-        return get(preferredKey);
-    }
-
-    /** convenience for @see #getWithDeprecation(ConfigKey[], ConfigKey...) */
-    public Object getWithDeprecation(ConfigKey<?> key, ConfigKey<?> ...deprecatedKeys) {
-        return getWithDeprecation(new ConfigKey[] { key }, deprecatedKeys);
-    }
-
-    /** returns the value for the first key in the list for which a value is set,
-     * warning if any of the deprecated keys have a value which is different to that set on the first set current key
-     * (including warning if a deprecated key has a value but no current key does) */
-    public synchronized Object getWithDeprecation(ConfigKey<?>[] currentKeysInOrderOfPreference, ConfigKey<?> ...deprecatedKeys) {
-        // Get preferred key (or null)
-        ConfigKey<?> preferredKeyProvidingValue = null;
-        Object result = null;
-        boolean found = false;
-        for (ConfigKey<?> key: currentKeysInOrderOfPreference) {
-            if (containsKey(key)) {
-                preferredKeyProvidingValue = key;
-                result = get(preferredKeyProvidingValue);
-                found = true;
-                break;
-            }
-        }
-        
-        // Check if any deprecated keys are set
-        ConfigKey<?> deprecatedKeyProvidingValue = null;
-        Object deprecatedResult = null;
-        boolean foundDeprecated = false;
-        for (ConfigKey<?> deprecatedKey: deprecatedKeys) {
-            Object x = null;
-            boolean foundX = false;
-            if (containsKey(deprecatedKey)) {
-                x = get(deprecatedKey);
-                foundX = true;
-            }
-            if (foundX) {
-                if (found) {
-                    if (!Objects.equal(result, x)) {
-                        log.warn("Conflicting value from deprecated key " +deprecatedKey+", value "+x+
-                                "; using preferred key "+preferredKeyProvidingValue+" value "+result);
-                    } else {
-                        log.info("Deprecated key " +deprecatedKey+" ignored; has same value as preferred key "+preferredKeyProvidingValue+" ("+result+")");
-                    }
-                } else if (foundDeprecated) {
-                    if (!Objects.equal(result, x)) {
-                        log.warn("Conflicting values from deprecated keys: using " +deprecatedKeyProvidingValue+" instead of "+deprecatedKey+
-                                " (value "+deprecatedResult+" instead of "+x+")");
-                    } else {
-                        log.info("Deprecated key " +deprecatedKey+" ignored; has same value as other deprecated key "+preferredKeyProvidingValue+" ("+deprecatedResult+")");
-                    }
-                } else {
-                    // new value, from deprecated key
-                    log.warn("Deprecated key " +deprecatedKey+" detected (supplying value "+x+"), "+
-                            "; recommend changing to preferred key '"+currentKeysInOrderOfPreference[0]+"'; this will not be supported in future versions");
-                    deprecatedResult = x;
-                    deprecatedKeyProvidingValue = deprecatedKey;
-                    foundDeprecated = true;
-                }
-            }
-        }
-        
-        if (found) {
-            return result;
-        } else if (foundDeprecated) {
-            return deprecatedResult;
-        } else {
-            return currentKeysInOrderOfPreference[0].getDefaultValue();
-        }
-    }
-
-    protected <T> T get(ConfigKey<T> key, boolean markUsed) {
-        // TODO for now, no evaluation -- maps / closure content / other smart (self-extracting) keys are NOT supported
-        // (need a clean way to inject that behaviour, as well as desired TypeCoercions)
-        // this method, and the coercion, is not synchronized, nor does it need to be, because the "get" is synchronized. 
-        return coerceFirstNonNullKeyValue(key, getStringKey(key.getName(), markUsed));
-    }
-
-    /** returns the first non-null value to be the type indicated by the key, or the keys default value if no non-null values are supplied */
-    public static <T> T coerceFirstNonNullKeyValue(ConfigKey<T> key, Object ...values) {
-        for (Object o: values)
-            if (o!=null) return TypeCoercions.coerce(o, key.getTypeToken());
-        return TypeCoercions.coerce(key.getDefaultValue(), key.getTypeToken());
-    }
-
-    protected Object getStringKey(String key, boolean markUsed) {
-        return getStringKeyMaybe(key, markUsed).orNull();
-    }
-    protected synchronized Maybe<Object> getStringKeyMaybe(String key, boolean markUsed) {
-        if (config.containsKey(key)) {
-            if (markUsed) markUsed(key);
-            return Maybe.of(config.get(key));
-        }
-        return Maybe.absent();
-    }
-
-    /** indicates that a string key in the config map has been accessed */
-    public synchronized void markUsed(String key) {
-        unusedConfig.remove(key);
-    }
-
-    public synchronized void clear() {
-        if (sealed) 
-            throw new IllegalStateException("Cannot clear this config bag has been sealed and is now immutable.");
-        config.clear();
-        unusedConfig.clear();
-    }
-    
-    public ConfigBag removeAll(ConfigKey<?> ...keys) {
-        for (ConfigKey<?> key: keys) remove(key);
-        return this;
-    }
-
-    public synchronized void remove(ConfigKey<?> key) {
-        remove(key.getName());
-    }
-
-    public ConfigBag removeAll(Iterable<String> keys) {
-        for (String key: keys) remove(key);
-        return this;
-    }
-
-    public synchronized void remove(String key) {
-        if (sealed) 
-            throw new IllegalStateException("Cannot remove "+key+": this config bag has been sealed and is now immutable.");
-        config.remove(key);
-        unusedConfig.remove(key);
-    }
-
-    public ConfigBag copy(ConfigBag other) {
-        // ensure locks are taken in a canonical order to prevent deadlock
-        if (other==null) {
-            synchronized (this) {
-                return copyWhileSynched(other);
-            }
-        }
-        if (System.identityHashCode(other) < System.identityHashCode(this)) {
-            synchronized (other) {
-                synchronized (this) {
-                    return copyWhileSynched(other);
-                }
-            }
-        } else {
-            synchronized (this) {
-                synchronized (other) {
-                    return copyWhileSynched(other);
-                }
-            }
-        }
-    }
-    
-    protected ConfigBag copyWhileSynched(ConfigBag other) {
-        if (sealed) 
-            throw new IllegalStateException("Cannot copy "+other+" to "+this+": this config bag has been sealed and is now immutable.");
-        putAll(other.getAllConfig());
-        markAll(Sets.difference(other.getAllConfig().keySet(), other.getUnusedConfig().keySet()));
-        setDescription(other.getDescription());
-        return this;
-    }
-
-    public synchronized int size() {
-        return config.size();
-    }
-    
-    public synchronized boolean isEmpty() {
-        return config.isEmpty();
-    }
-    
-    public ConfigBag markAll(Iterable<String> usedFlags) {
-        for (String flag: usedFlags)
-            markUsed(flag);
-        return this;
-    }
-
-    public synchronized boolean isUnused(ConfigKey<?> key) {
-        return unusedConfig.containsKey(key.getName());
-    }
-    
-    /** makes this config bag immutable; any attempts to change subsequently 
-     * (apart from marking fields as used) will throw an exception
-     * <p>
-     * copies will be unsealed however
-     * <p>
-     * returns this for convenience (fluent usage) */
-    public ConfigBag seal() {
-        sealed = true;
-        if (live) {
-            // TODO How to ensure sealed?!
-        } else {
-            config = getAllConfig();
-        }
-        return this;
-    }
-
-    // TODO why have both this and mutable
-    /** @see #getAllConfigMutable() */
-    public Map<String, Object> getAllConfigRaw() {
-        return getAllConfigMutable();
-    }
-    
-    @Override
-    public String toString() {
-        return JavaClassNames.simpleClassName(this)+"["+getAllConfigRaw()+"]";
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/crypto/FluentKeySigner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/crypto/FluentKeySigner.java b/core/src/main/java/brooklyn/util/crypto/FluentKeySigner.java
deleted file mode 100644
index a1bc125..0000000
--- a/core/src/main/java/brooklyn/util/crypto/FluentKeySigner.java
+++ /dev/null
@@ -1,192 +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 brooklyn.util.crypto;
-
-import java.math.BigInteger;
-import java.security.KeyPair;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.cert.CertificateParsingException;
-import java.security.cert.X509Certificate;
-import java.util.Date;
-
-import javax.security.auth.x500.X500Principal;
-
-import org.apache.brooklyn.core.internal.BrooklynInitialization;
-import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
-import org.bouncycastle.asn1.x509.X509Extension;
-import org.bouncycastle.jce.X509Principal;
-
-import brooklyn.util.exceptions.Exceptions;
-
-/** A fluent API which simplifies generating certificates (signed keys) */
-/* NB - re deprecation - we use deprecated X509V3CertificateGenerator still
- * because the official replacement, X509v3CertificateBuilder, 
- * drags in an add'l dependency (bcmail) and is harder to use. */
-public class FluentKeySigner {
-
-    static { BrooklynInitialization.initSecureKeysBouncyCastleProvider(); }
-
-    protected X500Principal issuerPrincipal;
-    protected KeyPair issuerKey;
-
-    protected SecureRandom srand = new SecureRandom();
-    
-    protected Date validityStartDate, validityEndDate;
-    protected BigInteger serialNumber;
-    
-    protected String signatureAlgorithm = "MD5WithRSAEncryption";
-    protected AuthorityKeyIdentifier authorityKeyIdentifier;
-    protected X509Certificate authorityCertificate;
-
-    public FluentKeySigner(X500Principal issuerPrincipal, KeyPair issuerKey) {
-        this.issuerPrincipal = issuerPrincipal;
-        this.issuerKey = issuerKey;
-        validFromDaysAgo(7);
-        validForYears(10);
-    }
-    public FluentKeySigner(String issuerCommonName, KeyPair issuerKey) {
-        this(SecureKeys.getX500PrincipalWithCommonName(issuerCommonName), issuerKey);
-    }
-    
-    public FluentKeySigner(String issuerCommonName) {
-        this(issuerCommonName, SecureKeys.newKeyPair());
-    }
-
-    public FluentKeySigner(X509Certificate caCert, KeyPair caKey) {
-        this(caCert.getIssuerX500Principal(), caKey);
-        authorityCertificate(caCert);
-    }
-    
-    public KeyPair getKey() {
-        return issuerKey;
-    }
-    
-    public X500Principal getPrincipal() {
-        return issuerPrincipal;
-    }
-    
-    @SuppressWarnings("deprecation")
-    public String getCommonName() {
-//        TODO see deprecation note at top of file
-        // for modernising, would RFC4519Style.cn work ?
-        return (String) new X509Principal(issuerPrincipal.getName()).getValues(org.bouncycastle.asn1.x509.X509Name.CN).elementAt(0);
-    }
-    
-    public X509Certificate getAuthorityCertificate() {
-        return authorityCertificate;
-    }
-    
-    public FluentKeySigner validFromDaysAgo(long days) {
-        return validFrom(new Date( (System.currentTimeMillis() / (1000L*60*60*24) - days) * 1000L*60*60*24));            
-    }
-
-    public FluentKeySigner validFrom(Date d) {
-        validityStartDate = d;
-        return this;
-    }
-
-    public FluentKeySigner validForYears(long years) {
-        return validUntil(new Date( (System.currentTimeMillis() / (1000L*60*60*24) + 365*years) * 1000L*60*60*24));            
-    }
-
-    public FluentKeySigner validUntil(Date d) {
-        validityEndDate = d;
-        return this;
-    }
-
-    /** use a hard-coded serial number; or make one up, if null */
-    public FluentKeySigner serialNumber(BigInteger serialNumber) {
-        this.serialNumber = serialNumber;
-        return this;
-    }
-
-    public FluentKeySigner signatureAlgorithm(String signatureAlgorithm) {
-        this.signatureAlgorithm = signatureAlgorithm;
-        return this;
-    }
-
-    @SuppressWarnings("deprecation")
-    public FluentKeySigner authorityCertificate(X509Certificate certificate) {
-        try {
-            authorityKeyIdentifier(new org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure(certificate));
-            this.authorityCertificate = certificate;
-            return this;
-        } catch (CertificateParsingException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    public FluentKeySigner authorityKeyIdentifier(AuthorityKeyIdentifier authorityKeyIdentifier) {
-        this.authorityKeyIdentifier = authorityKeyIdentifier;
-        return this;
-    }
-    
-    public FluentKeySigner selfsign() {
-        if (authorityCertificate!=null) throw new IllegalStateException("Signer already has certificate");
-        authorityCertificate(newCertificateFor(getCommonName(), getKey()));
-        return this;
-    }
-
-    // TODO see note re deprecation at start of file
-    @SuppressWarnings("deprecation")
-    public X509Certificate newCertificateFor(X500Principal subject, PublicKey keyToCertify) {
-        try {
-            org.bouncycastle.x509.X509V3CertificateGenerator v3CertGen = new org.bouncycastle.x509.X509V3CertificateGenerator();
-
-            v3CertGen.setSerialNumber(
-                    serialNumber != null ? serialNumber :
-                        // must be positive
-                        BigInteger.valueOf(srand.nextLong()).abs().add(BigInteger.ONE));  
-            v3CertGen.setIssuerDN(issuerPrincipal);  
-            v3CertGen.setNotBefore(validityStartDate);  
-            v3CertGen.setNotAfter(validityEndDate);
-            v3CertGen.setSignatureAlgorithm(signatureAlgorithm);   
-
-            v3CertGen.setSubjectDN(subject);  
-            v3CertGen.setPublicKey(keyToCertify);  
-
-            v3CertGen.addExtension(X509Extension.subjectKeyIdentifier, false,
-                    new org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure(keyToCertify));
-
-            if (authorityKeyIdentifier!=null)
-                v3CertGen.addExtension(X509Extension.authorityKeyIdentifier, false,
-                        authorityKeyIdentifier);
-
-            X509Certificate pkCertificate = v3CertGen.generate(issuerKey.getPrivate(), "BC");
-            return pkCertificate;
-            
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    public X509Certificate newCertificateFor(String commonName, PublicKey key) {
-//        SecureKeys.getX509PrincipalWithCommonName(commonName)
-        return newCertificateFor(
-                SecureKeys.getX500PrincipalWithCommonName(commonName)
-//                new X509Principal("CN=" + commonName + ", OU=None, O=None, L=None, C=None")
-                , key);
-    }
-
-    public X509Certificate newCertificateFor(String commonName, KeyPair key) {
-        return newCertificateFor(commonName, key.getPublic());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/crypto/SecureKeys.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/crypto/SecureKeys.java b/core/src/main/java/brooklyn/util/crypto/SecureKeys.java
deleted file mode 100644
index 29fcf32..0000000
--- a/core/src/main/java/brooklyn/util/crypto/SecureKeys.java
+++ /dev/null
@@ -1,184 +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 brooklyn.util.crypto;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.StringWriter;
-import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.Security;
-
-import org.apache.brooklyn.core.internal.BrooklynInitialization;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.jce.X509Principal;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openssl.PEMDecryptorProvider;
-import org.bouncycastle.openssl.PEMEncryptedKeyPair;
-import org.bouncycastle.openssl.PEMKeyPair;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.PEMWriter;
-import org.bouncycastle.openssl.PasswordFinder;
-import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
-import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.stream.Streams;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Throwables;
-
-/**
- * Utility methods for generating and working with keys,
- * extending the parent class with useful things provided by BouncyCastle crypto library.
- * (Parent class is in a different project where BC is not included as a dependency.)
- */
-public class SecureKeys extends SecureKeysWithoutBouncyCastle {
-
-    private static final Logger log = LoggerFactory.getLogger(SecureKeys.class);
-    
-    static { BrooklynInitialization.initSecureKeysBouncyCastleProvider(); }
-    
-    public static void initBouncyCastleProvider() {
-        Security.addProvider(new BouncyCastleProvider());
-    }
-    
-    public static class PassphraseProblem extends IllegalStateException {
-        private static final long serialVersionUID = -3382824813899223447L;
-        public PassphraseProblem(String message) { super("Passphrase problem with this key: "+message); }
-        public PassphraseProblem(String message, Exception cause) { super("Passphrase problem with this key: "+message, cause); }
-    }
-    
-    private SecureKeys() {}
-    
-    /** RFC1773 order, with None for other values. Normally prefer X500Principal. */
-    public static X509Principal getX509PrincipalWithCommonName(String commonName) {
-        return new X509Principal("" + "C=None," + "L=None," + "O=None," + "OU=None," + "CN=" + commonName);
-    }
-
-    /** reads RSA or DSA / pem style private key files (viz {@link #toPem(KeyPair)}), extracting also the public key if possible
-     * @throws IllegalStateException on errors, in particular {@link PassphraseProblem} if that is the problem */
-    public static KeyPair readPem(InputStream input, final String passphrase) {
-        // TODO cache is only for fallback "reader" strategy (2015-01); delete when Parser confirmed working
-        byte[] cache = Streams.readFully(input);
-        input = new ByteArrayInputStream(cache);
-
-        try {
-            PEMParser pemParser = new PEMParser(new InputStreamReader(input));
-
-            Object object = pemParser.readObject();
-            pemParser.close();
-
-            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
-            KeyPair kp = null;
-            if (object==null) {
-                throw new IllegalStateException("PEM parsing failed: missing or invalid data");
-            } else if (object instanceof PEMEncryptedKeyPair) {
-                if (passphrase==null) throw new PassphraseProblem("passphrase required");
-                try {
-                    PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(passphrase.toCharArray());
-                    kp = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv));
-                } catch (Exception e) {
-                    Exceptions.propagateIfFatal(e);
-                    throw new PassphraseProblem("wrong passphrase", e);
-                }
-            } else  if (object instanceof PEMKeyPair) {
-                kp = converter.getKeyPair((PEMKeyPair) object);
-            } else if (object instanceof PrivateKeyInfo) {
-                PrivateKey privKey = converter.getPrivateKey((PrivateKeyInfo) object);
-                kp = new KeyPair(null, privKey);
-            } else {
-                throw new IllegalStateException("PEM parser support missing for: "+object);
-            }
-
-            return kp;
-
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-
-            // older code relied on PEMReader, now deprecated
-            // replaced with above based on http://stackoverflow.com/questions/14919048/bouncy-castle-pemreader-pemparser
-            // passes the same tests (Jan 2015) but leaving the old code as a fallback for the time being 
-
-            input = new ByteArrayInputStream(cache);
-            try {
-                Security.addProvider(new BouncyCastleProvider());
-                @SuppressWarnings("deprecation")
-                org.bouncycastle.openssl.PEMReader pr = new org.bouncycastle.openssl.PEMReader(new InputStreamReader(input), new PasswordFinder() {
-                    public char[] getPassword() {
-                        return passphrase!=null ? passphrase.toCharArray() : new char[0];
-                    }
-                });
-                @SuppressWarnings("deprecation")
-                KeyPair result = (KeyPair) pr.readObject();
-                pr.close();
-                if (result==null)
-                    throw Exceptions.propagate(e);
-                
-                log.warn("PEMParser failed when deprecated PEMReader succeeded, with "+result+"; had: "+e);
-
-                return result;
-
-            } catch (Exception e2) {
-                Exceptions.propagateIfFatal(e2);
-                throw Exceptions.propagate(e);
-            }
-        }
-    }
-
-    /** because KeyPair.equals is not implemented :( */
-    public static boolean equal(KeyPair k1, KeyPair k2) {
-        return Objects.equal(k2.getPrivate(), k1.getPrivate()) && Objects.equal(k2.getPublic(), k1.getPublic());
-    }
-
-    /** returns the PEM (base64, ie for id_rsa) string for the private key / key pair;
-     * this starts -----BEGIN PRIVATE KEY----- and ends similarly, like id_rsa.
-     * also see {@link #readPem(InputStream, String)} */
-    public static String toPem(KeyPair key) {
-        return stringPem(key);
-    }
-
-    /** returns id_rsa.pub style file, of public key */
-    public static String toPub(KeyPair key) {
-        return AuthorizedKeysParser.encodePublicKey(key.getPublic());
-    }
-    
-    /** opposite of {@link #toPub(KeyPair)}, given text */
-    public static PublicKey fromPub(String pubText) {
-        return AuthorizedKeysParser.decodePublicKey(pubText);
-    }
-
-    /** @deprecated since 0.7.0, use {@link #toPem(KeyPair)} */ @Deprecated
-    public static String stringPem(KeyPair key) {
-        try {
-            StringWriter sw = new StringWriter();
-            PEMWriter w = new PEMWriter(sw);
-            w.writeObject(key);
-            w.close();
-            return sw.toString();
-        } catch (IOException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/file/ArchiveBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/file/ArchiveBuilder.java b/core/src/main/java/brooklyn/util/file/ArchiveBuilder.java
deleted file mode 100644
index 6985406..0000000
--- a/core/src/main/java/brooklyn/util/file/ArchiveBuilder.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 brooklyn.util.file;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Collections;
-import java.util.Map;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
-import java.util.zip.ZipOutputStream;
-
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.file.ArchiveUtils.ArchiveType;
-import brooklyn.util.os.Os;
-
-import com.google.common.annotations.Beta;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.LinkedHashMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.io.Files;
-
-/**
- * Build a Zip or Jar archive.
- * <p>
- * Supports creating temporary archives that will be deleted on exit, if no name is
- * specified. The created file must be a Java archive type, with the extension {@code .zip},
- * {@code .jar}, {@code .war} or {@code .ear}.
- * <p>
- * Example:
- * <pre> File zip = ArchiveBuilder.archive("data/archive.zip")
- *         .addAt(new File("./pom.xml"), "")
- *         .addDirContentsAt(new File("./src"), "src/")
- *         .addAt(new File("/tmp/Extra.java"), "src/main/java/")
- *         .addDirContentsAt(new File("/tmp/overlay/"), "")
- *         .create();
- * </pre>
- * <p>
- */
-@Beta
-public class ArchiveBuilder {
-
-    /**
-     * Create an {@link ArchiveBuilder} for an archive with the given name.
-     */
-    public static ArchiveBuilder archive(String archive) {
-        return new ArchiveBuilder(archive);
-    }
-
-    /**
-     * Create an {@link ArchiveBuilder} for a {@link ArchiveType#ZIP Zip} format archive.
-     */
-    public static ArchiveBuilder zip() {
-        return new ArchiveBuilder(ArchiveType.ZIP);
-    }
-
-    /**
-     * Create an {@link ArchiveBuilder} for a {@link ArchiveType#JAR Jar} format archive.
-     */
-    public static ArchiveBuilder jar() {
-        return new ArchiveBuilder(ArchiveType.JAR);
-    }
-
-    // TODO would be nice to support TAR and TGZ
-    // e.g. using commons-compress
-    // TarArchiveOutputStream out = new TarArchiveOutputStream(new GZIPOutputStream(bytes));
-    // but I think the way entries are done is slightly different so we'd need a bit of refactoring
-    
-    private final ArchiveType type;
-    private File archive;
-    private Manifest manifest;
-    private Multimap<String, File> entries = LinkedHashMultimap.create();
-
-    private ArchiveBuilder() {
-        this(ArchiveType.ZIP);
-    }
-
-    private ArchiveBuilder(String filename) {
-        this(ArchiveType.of(filename));
-
-        named(filename);
-    }
-
-    private ArchiveBuilder(ArchiveType type) {
-        checkNotNull(type);
-        checkArgument(ArchiveType.ZIP_ARCHIVES.contains(type));
-
-        this.type = type;
-        this.manifest = new Manifest();
-    }
-
-    /**
-     * Set the location of the generated archive file.
-     */
-    public ArchiveBuilder named(String name) {
-        checkNotNull(name);
-        String ext = Files.getFileExtension(name);
-        if (ext.isEmpty()) {
-            name = name + "." + type.toString();
-        } else if (type != ArchiveType.of(name)) {
-            throw new IllegalArgumentException(String.format("Extension for '%s' did not match archive type of %s", ext, type));
-        }
-        this.archive = new File(Os.tidyPath(name));
-        return this;
-    }
-
-    /**
-     * @see #named(String)
-     */
-    public ArchiveBuilder named(File file) {
-        checkNotNull(file);
-        return named(file.getPath());
-    }
-
-    /**
-     * Add a manifest entry with the given {@code key} and {@code value}.
-     */
-    public ArchiveBuilder manifest(Object key, Object value) {
-        checkNotNull(key, "key");
-        checkNotNull(value, "value");
-        manifest.getMainAttributes().put(key, value);
-        return this;
-    }
-
-    /**
-     * Add the file located at the {@code filePath} to the archive, 
-     * with some complicated base-name strategies.
-     *
-     * @deprecated since 0.7.0 use one of the other add methods which makes the strategy explicit */ @Deprecated
-    public ArchiveBuilder add(String filePath) {
-        checkNotNull(filePath, "filePath");
-        return add(new File(Os.tidyPath(filePath)));
-    }
-
-    /**
-     * Add the {@code file} to the archive.
-     * <p>
-     * If the file path is absolute, or points to a file above the current directory,
-     * the file is added to the archive as a top-level entry, using the file name only.
-     * For relative {@code filePath}s below the current directory, the file is added
-     * using the path given and is assumed to be located relative to the current
-     * working directory.
-     * <p>
-     * No checks for file existence are made at this stage.
-     *
-     * @see #entry(String, File)
-     * @deprecated since 0.7.0 use one of the other add methods which makes the strategy explicit */ @Deprecated
-    public ArchiveBuilder add(File file) {
-        checkNotNull(file, "file");
-        String filePath = Os.tidyPath(file.getPath());
-        if (file.isAbsolute() || filePath.startsWith("../")) {
-            return entry(Os.mergePaths(".", file.getName()), file);
-        } else {
-            return entry(Os.mergePaths(".", filePath), file);
-        }
-    }
-
-    /**
-     * Add the file located at the {@code fileSubPath}, relative to the {@code baseDir} on the local system,
-     * to the archive.
-     * <p>
-     * Uses the {@code fileSubPath} as the name of the file in the archive. Note that the
-     * file is found by concatenating the two path components using {@link Os#mergePaths(String...)},
-     * thus {@code fileSubPath} should not be absolute or point to a location above the current directory.
-     * <p>
-     * Use {@link #entry(String, String)} directly or {@link #entries(Map)} for complete
-     * control over file locations and names in the archive.
-     *
-     * @see #entry(String, String)
-     */
-    public ArchiveBuilder addFromLocalBaseDir(File baseDir, String fileSubPath) {
-        checkNotNull(baseDir, "baseDir");
-        checkNotNull(fileSubPath, "filePath");
-        return entry(Os.mergePaths(".", fileSubPath), Os.mergePaths(baseDir.getPath(), fileSubPath));
-    }
-    /** @deprecated since 0.7.0 use {@link #addFromLocalBaseDir(File, String)}, or
-     * one of the other add methods if adding relative to baseDir was not intended */ @Deprecated
-    public ArchiveBuilder addFromLocalBaseDir(String baseDir, String fileSubPath) {
-        return addFromLocalBaseDir(new File(baseDir), fileSubPath);
-    }
-    /** @deprecated since 0.7.0 use {@link #addFromLocalBaseDir(File, String)}, or
-     * one of the other add methods if adding relative to baseDir was not intended */ @Deprecated
-    public ArchiveBuilder add(String baseDir, String fileSubPath) {
-        return addFromLocalBaseDir(baseDir, fileSubPath);
-    }
-     
-    /** adds the given file to the archive, preserving its name but putting under the given directory in the archive (may be <code>""</code> or <code>"./"</code>) */
-    public ArchiveBuilder addAt(File file, String archiveParentDir) {
-        checkNotNull(archiveParentDir, "archiveParentDir");
-        checkNotNull(file, "file");
-        return entry(Os.mergePaths(archiveParentDir, file.getName()), file);
-    }
-
-    /**
-     * Add the contents of the directory named {@code dirName} to the archive.
-     *
-     * @see #addDir(File)
-     * @deprecated since 0.7.0 use {@link #addDirContentsAt(File, String) */ @Deprecated
-    public ArchiveBuilder addDir(String dirName) {
-        checkNotNull(dirName, "dirName");
-        return addDir(new File(Os.tidyPath(dirName)));
-    }
-
-    /**
-     * Add the contents of the directory {@code dir} to the archive.
-     * The directory's name is not included; use {@link #addAtRoot(File)} if you want that behaviour. 
-     * <p>
-     * Uses {@literal .} as the parent directory name for the contents.
-     *
-     * @see #entry(String, File)
-     */
-    public ArchiveBuilder addDirContentsAt(File dir, String archiveParentDir) {
-        checkNotNull(dir, "dir");
-        if (!dir.isDirectory()) throw new IllegalArgumentException(dir+" is not a directory; cannot add contents to archive");
-        return entry(archiveParentDir, dir);
-    }
-    /**
-     * As {@link #addDirContentsAt(File, String)}, 
-     * using {@literal .} as the parent directory name for the contents.
-     * 
-     * @deprecated since 0.7.0 use {@link #addDirContentsAt(File, String)
-     * to clarify API, argument types, and be explicit about where it should be installed,
-     * because JARs seem to require <code>""<code> whereas ZIPs might want <code>"./"</code>. */ @Deprecated
-    public ArchiveBuilder addDir(File dir) {
-        return addDirContentsAt(dir, ".");
-    }
-
-    /**
-     * Add the collection of {@code files} to the archive.
-     *
-     * @see #add(String)
-     * @deprecated since 0.7.0 use one of the other add methods if keeping this file's path was not intended */ @Deprecated
-    public ArchiveBuilder add(Iterable<String> files) {
-        checkNotNull(files, "files");
-        for (String filePath : files) {
-            add(filePath);
-        }
-        return this;
-    }
-
-    /**
-     * Add the collection of {@code files}, relative to the {@code baseDir}, to
-     * the archive.
-     *
-     * @see #add(String, String)
-     * @deprecated since 0.7.0 use one of the other add methods if keeping this file's path was not intended */ @Deprecated
-    public ArchiveBuilder add(String baseDir, Iterable<String> files) {
-        checkNotNull(baseDir, "baseDir");
-        checkNotNull(files, "files");
-        for (String filePath : files) {
-            add(baseDir, filePath);
-        }
-        return this;
-    }
-
-    /**
-     * Add the {@code file} to the archive with the path {@code entryPath}.
-     *
-     * @see #entry(String, File)
-     */
-    public ArchiveBuilder entry(String entryPath, String filePath) {
-        checkNotNull(entryPath, "entryPath");
-        checkNotNull(filePath, "filePath");
-        return entry(entryPath, new File(filePath));
-    }
-
-    /**
-     * Add the {@code file} to the archive with the path {@code entryPath}.
-     */
-    public ArchiveBuilder entry(String entryPath, File file) {
-        checkNotNull(entryPath, "entryPath");
-        checkNotNull(file, "file");
-        this.entries.put(entryPath, file);
-        return this;
-    }
-
-    /**
-     * Add a {@link Map} of entries to the archive.
-     * <p>
-     * The keys should be the names of the file entries to be added to the archive and
-     * the value should point to the actual {@link File} to be added.
-     * <p>
-     * This allows complete control over the directory structure of the eventual archive,
-     * as the entry names do not need to bear any relationship to the name or location
-     * of the files on the filesystem.
-     */
-    public ArchiveBuilder entries(Map<String, File> entries) {
-        checkNotNull(entries, "entries");
-        for (Map.Entry<String, File> entry: entries.entrySet())
-            this.entries.put(entry.getKey(), entry.getValue());
-        return this;
-    }
-
-    /**
-     * Generates the archive and outputs it to the given stream, ignoring any file name.
-     * <p>
-     * This will add a manifest file if the type is a Jar archive.
-     */
-    public void stream(OutputStream output) {
-        try {
-            ZipOutputStream target;
-            if (type == ArchiveType.ZIP) {
-                target = new ZipOutputStream(output);
-            } else {
-                manifest(Attributes.Name.MANIFEST_VERSION, "1.0");
-                target = new JarOutputStream(output, manifest);
-            }
-            for (String entry : entries.keySet()) {
-                addToArchive(entry, entries.get(entry), target);
-            }
-            target.close();
-        } catch (IOException ioe) {
-            throw Exceptions.propagate(ioe);
-        }
-    }
-
-    /**
-     * Generates the archive, saving it with the given name.
-     */
-    public File create(String archiveFile) {
-        return named(archiveFile).create();
-    }
-
-    /**
-     * Generates the archive.
-     * <p>
-     * If no name has been specified, the archive will be created as a temporary file with
-     * a unique name, that is deleted on exit. Otherwise, the given name will be used.
-     */
-    public File create() {
-        if (archive == null) {
-            File temp = Os.newTempFile("brooklyn-archive", type.toString());
-            temp.deleteOnExit();
-            named(temp);
-        }
-        try {
-            OutputStream output = new FileOutputStream(archive);
-            stream(output);
-            output.close();
-        } catch (IOException ioe) {
-            throw Exceptions.propagate(ioe);
-        }
-        return archive;
-    }
-
-    /**
-     * Recursively add files to the archive.
-     * <p>
-     * Code adapted from this <a href="http://stackoverflow.com/questions/1281229/how-to-use-jaroutputstream-to-create-a-jar-file">example</a>
-     * <p>
-     * <strong>Note</strong> {@link File} provides no support for symbolic links, and as such there is
-     * no way to ensure that a symbolic link to a directory is not followed when traversing the
-     * tree. In this case, iterables created by this traverser could contain files that are
-     * outside of the given directory or even be infinite if there is a symbolic link loop.
-     */
-    private void addToArchive(String path, Iterable<File> sources, ZipOutputStream target) throws IOException {
-        int size = Iterables.size(sources);
-        if (size==0) return;
-        boolean isDirectory;
-        if (size>1) {
-            // it must be directories if we are putting multiple things here 
-            isDirectory = true;
-        } else {
-            isDirectory = Iterables.getOnlyElement(sources).isDirectory();
-        }
-        
-        String name = path.replace("\\", "/");
-        if (isDirectory) {
-            name += "/";
-            JarEntry entry = new JarEntry(name);
-            
-            long lastModified=-1;
-            for (File source: sources)
-                if (source.lastModified()>lastModified)
-                    lastModified = source.lastModified();
-            
-            entry.setTime(lastModified);
-            target.putNextEntry(entry);
-            target.closeEntry();
-
-            for (File source: sources) {
-                if (!source.isDirectory()) {
-                    throw new IllegalStateException("Cannot add multiple items at a path in archive unless they are directories: "+sources+" at "+path+" is not valid.");
-                }
-                Iterable<File> children = Files.fileTreeTraverser().children(source);
-                for (File child : children) {
-                    addToArchive(Os.mergePaths(path, child.getName()), Collections.singleton(child), target);
-                }
-            }
-            return;
-        }
-
-        File source = Iterables.getOnlyElement(sources);
-        JarEntry entry = new JarEntry(name);
-        entry.setTime(source.lastModified());
-        target.putNextEntry(entry);
-        Files.asByteSource(source).copyTo(target);
-        target.closeEntry();
-    }
-}


[11/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/system/SystemTasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/system/SystemTasksTest.java b/core/src/test/java/brooklyn/util/task/system/SystemTasksTest.java
deleted file mode 100644
index e60310d..0000000
--- a/core/src/test/java/brooklyn/util/task/system/SystemTasksTest.java
+++ /dev/null
@@ -1,134 +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 brooklyn.util.task.system;
-
-import java.io.File;
-
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.apache.brooklyn.core.management.internal.LocalManagementContext;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.util.os.Os;
-import brooklyn.util.task.ssh.SshTasks;
-
-/**
- * Some tests for {@link SystemTasks}. See {@link SshTasks}.
- */
-public class SystemTasksTest {
-
-    ManagementContext mgmt;
-    File tempDir;
-    
-    boolean failureExpected;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setup() throws Exception {
-        mgmt = new LocalManagementContext();
-        
-        clearExpectedFailure();
-        tempDir = Os.newTempDir(getClass());
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (mgmt != null) Entities.destroyAll(mgmt);
-        mgmt = null;
-        tempDir = Os.deleteRecursively(tempDir).asNullOrThrowing();
-        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;
-    }
-
-
-    protected <T> ProcessTaskWrapper<T> submit(final ProcessTaskFactory<T> tf) {
-        ProcessTaskWrapper<T> t = tf.newTask();
-        mgmt.getExecutionManager().submit(t);
-        return t;
-    }
-
-    @Test(groups="Integration")
-    public void testExecEchoHello() {
-        ProcessTaskWrapper<Integer> t = submit(SystemTasks.exec("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");
-    }
-
-    // FIXME Behaviour of Bash shell changes from 3.x to 4.x so test is disabled
-    @Test(groups="Integration", enabled=false)
-    public void testSubshellExitScriptDoesNotExit() {
-        checkSubshellExitDoesNotExit(taskSubshellExit().runAsScript());
-    }
-
-    @Test(groups="Integration")
-    public void testSubshellExitCommandDoesNotExit() {
-        checkSubshellExitDoesNotExit(taskSubshellExit().runAsCommand());
-    }
-
-    public ProcessTaskFactory<Integer> taskSubshellExit() {
-        return SystemTasks.exec("echo hello", "( exit 1 )", "echo bye code $?");
-    }
-
-    public void checkSubshellExitDoesNotExit(ProcessTaskFactory<Integer> task) {
-        ProcessTaskWrapper<Integer> t = submit(task);
-        t.block();
-        Assert.assertEquals(t.get(), (Integer)0);
-        Assert.assertTrue(t.getStdout().contains("bye code 1"), "stdout is: "+t.getStdout());
-    }
-
-    @Test(groups="Integration")
-    public void testGroupExitScriptDoesNotExit() {
-        checkGroupExitDoesExit(taskGroupExit().runAsScript());
-    }
-
-    @Test(groups="Integration")
-    public void testGroupExitCommandDoesNotExit() {
-        checkGroupExitDoesExit(taskGroupExit().runAsCommand());
-    }
-
-    public ProcessTaskFactory<Integer> taskGroupExit() {
-        return SystemTasks.exec("echo hello", "{ exit 1 ; }", "echo bye code $?");
-    }
-
-    public void checkGroupExitDoesExit(ProcessTaskFactory<Integer> task) {
-        ProcessTaskWrapper<Integer> t = submit(task);
-        t.block();
-        Assert.assertEquals(t.get(), (Integer)1);
-        Assert.assertFalse(t.getStdout().contains("bye"), "stdout is: "+t.getStdout());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/text/DataUriSchemeParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/text/DataUriSchemeParserTest.java b/core/src/test/java/brooklyn/util/text/DataUriSchemeParserTest.java
deleted file mode 100644
index ff2dc9b..0000000
--- a/core/src/test/java/brooklyn/util/text/DataUriSchemeParserTest.java
+++ /dev/null
@@ -1,52 +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 brooklyn.util.text;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-
-import org.bouncycastle.util.encoders.Base64;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-public class DataUriSchemeParserTest {
-
-    @Test
-    public void testSimple() {
-        Assert.assertEquals(new DataUriSchemeParser("data:,hello").parse().getDataAsString(), "hello");
-        Assert.assertEquals(DataUriSchemeParser.toString("data:,hello"), "hello");
-    }
-
-    @Test
-    public void testMimeType() throws UnsupportedEncodingException {
-        DataUriSchemeParser p = new DataUriSchemeParser("data:application/json,"+URLEncoder.encode("{ }", "US-ASCII")).parse();
-        Assert.assertEquals(p.getMimeType(), "application/json");
-        Assert.assertEquals(p.getData(), "{ }".getBytes());
-    }
-
-    @Test
-    public void testBase64() {
-        Assert.assertEquals(DataUriSchemeParser.toString(
-                "data:;base64,"+new String(Base64.encode("hello".getBytes()))), 
-            "hello");
-    }
-
-    // TODO test pictures, etc
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/text/TemplateProcessorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/text/TemplateProcessorTest.java b/core/src/test/java/brooklyn/util/text/TemplateProcessorTest.java
deleted file mode 100644
index bd8ef87..0000000
--- a/core/src/test/java/brooklyn/util/text/TemplateProcessorTest.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 brooklyn.util.text;
-
-import static org.testng.Assert.assertEquals;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
-import org.apache.brooklyn.test.entity.TestApplication;
-import org.apache.brooklyn.test.entity.TestEntity;
-import org.testng.Assert;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.BrooklynAppUnitTestSupport;
-import brooklyn.event.basic.DependentConfiguration;
-import brooklyn.test.FixedLocaleTest;
-
-import com.google.common.collect.ImmutableMap;
-
-public class TemplateProcessorTest extends BrooklynAppUnitTestSupport {
-    private FixedLocaleTest localeFix = new FixedLocaleTest();
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        super.setUp();
-        localeFix.setUp();
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        super.tearDown();
-        localeFix.tearDown();
-    }
-
-    @Test
-    public void testAdditionalArgs() {
-        String templateContents = "${mykey}";
-        String result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.of("mykey", "myval"));
-        assertEquals(result, "myval");
-    }
-    
-    @Test
-    public void testEntityConfig() {
-        TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
-                .configure(TestEntity.CONF_NAME, "myval"));
-        String templateContents = "${config['"+TestEntity.CONF_NAME.getName()+"']}";
-        String result = TemplateProcessor.processTemplateContents(templateContents, entity, ImmutableMap.<String,Object>of());
-        assertEquals(result, "myval");
-    }
-    
-    @Test
-    public void testEntityConfigNumber() {
-        TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
-                .configure(TestEntity.CONF_OBJECT, 123456));
-        String templateContents = "${config['"+TestEntity.CONF_OBJECT.getName()+"']}";
-        String result = TemplateProcessor.processTemplateContents(templateContents, entity, ImmutableMap.<String,Object>of());
-        assertEquals(result, "123,456");
-    }
-    
-    @Test
-    public void testEntityConfigNumberUnadorned() {
-        // ?c is needed to avoid commas (i always forget this!)
-        TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
-                .configure(TestEntity.CONF_OBJECT, 123456));
-        String templateContents = "${config['"+TestEntity.CONF_OBJECT.getName()+"']?c}";
-        String result = TemplateProcessor.processTemplateContents(templateContents, entity, ImmutableMap.<String,Object>of());
-        assertEquals(result, "123456");
-    }
-    
-    @Test
-    public void testGetSysProp() {
-        System.setProperty("testGetSysProp", "myval");
-        
-        String templateContents = "${javaSysProps['testGetSysProp']}";
-        String result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
-        assertEquals(result, "myval");
-    }
-    
-    @Test
-    public void testEntityGetterMethod() {
-        String templateContents = "${entity.id}";
-        String result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
-        assertEquals(result, app.getId());
-    }
-    
-    @Test
-    public void testManagementContextConfig() {
-        mgmt.getBrooklynProperties().put("globalmykey", "myval");
-        String templateContents = "${mgmt.globalmykey}";
-        String result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
-        assertEquals(result, "myval");
-    }
-    
-    @Test
-    public void testManagementContextDefaultValue() {
-        String templateContents = "${(missing)!\"defval\"}";
-        Object result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
-        assertEquals(result, "defval");
-    }
-    
-    @Test
-    public void testManagementContextDefaultValueInDotMissingValue() {
-        String templateContents = "${(mgmt.missing.more_missing)!\"defval\"}";
-        Object result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
-        assertEquals(result, "defval");
-    }
-    
-    @Test
-    public void testManagementContextConfigWithDot() {
-        mgmt.getBrooklynProperties().put("global.mykey", "myval");
-        String templateContents = "${mgmt['global.mykey']}";
-        String result = TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
-        assertEquals(result, "myval");
-    }
-    
-    @Test
-    public void testManagementContextErrors() {
-        try {
-            // NB: dot has special meaning so this should fail; must be accessed using bracket notation as above
-            mgmt.getBrooklynProperties().put("global.mykey", "myval");
-            String templateContents = "${mgmt.global.mykey}";
-            TemplateProcessor.processTemplateContents(templateContents, app, ImmutableMap.<String,Object>of());
-            Assert.fail("Should not have found value with intermediate dot");
-        } catch (Exception e) {
-            Assert.assertTrue(e.toString().contains("global"), "Should have mentioned missing key 'global' in error");
-        }
-    }
-    
-    @Test
-    public void testApplyTemplatedConfigWithAttributeWhenReady() {
-        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
-
-        TestEntity entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)
-                .configure(TestEntity.CONF_NAME, DependentConfiguration.attributeWhenReady(app, TestApplication.MY_ATTRIBUTE)));
-        
-        String templateContents = "${config['"+TestEntity.CONF_NAME.getName()+"']}";
-        String result = TemplateProcessor.processTemplateContents(templateContents, entity, ImmutableMap.<String,Object>of());
-        assertEquals(result, "myval");
-    }
-    
-    @Test
-    public void testDotSeparatedKey() {
-        String templateContents = "${a.b}";
-        String result = TemplateProcessor.processTemplateContents(templateContents, (ManagementContextInternal)null, 
-            ImmutableMap.<String,Object>of("a.b", "myval"));
-        assertEquals(result, "myval");
-    }
-    
-    @Test
-    public void testDotSeparatedKeyCollisionFailure() {
-        String templateContents = "${aaa.bbb}";
-        try {
-            TemplateProcessor.processTemplateContents(templateContents, (ManagementContextInternal)null, 
-                ImmutableMap.<String,Object>of("aaa.bbb", "myval", "aaa", "blocker"));
-            Assert.fail("Should not have found value with intermediate dot where prefix is overridden");
-        } catch (Exception e) {
-            Assert.assertTrue(e.toString().contains("aaa"), "Should have mentioned missing key 'aaa' in error");
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/xstream/CompilerCompatibilityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/xstream/CompilerCompatibilityTest.java b/core/src/test/java/brooklyn/util/xstream/CompilerCompatibilityTest.java
deleted file mode 100644
index 5a1f844..0000000
--- a/core/src/test/java/brooklyn/util/xstream/CompilerCompatibilityTest.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 brooklyn.util.xstream;
-
-import static org.testng.Assert.assertTrue;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Field;
-
-import org.testng.annotations.Test;
-
-import brooklyn.util.xstream.CompilerCompatibilityTest.EnclosingClass.DynamicClass;
-import brooklyn.util.xstream.CompilerCompatibilityTest.EnclosingClass.DynamicExtendingClass;
-import brooklyn.util.xstream.CompilerCompatibilityTest.EnclosingClass.EnclosingDynamicClass;
-import brooklyn.util.xstream.CompilerCompatibilityTest.EnclosingClass.EnclosingDynamicClass.NestedDynamicClass;
-
-import com.thoughtworks.xstream.XStream;
-import com.thoughtworks.xstream.mapper.MapperWrapper;
-
-// To get the generated synthetic fields use the command:
-/*
-   find core/target/test-classes -name CompilerCompatibilityTest\$EnclosingClass\$* | \
-   sed s@core/target/test-classes/@@ | sed 's@.class$@@' | sed s@/@.@g | \
-   xargs javap -classpath core/target/test-classes/ | grep -B1 this
-*/
-@SuppressWarnings("unused")
-public class CompilerCompatibilityTest {
-    private EnclosingClass enclosingClass = new EnclosingClass();
-    private DynamicClass dynamicClass = enclosingClass.new DynamicClass();
-    private DynamicExtendingClass dynamicExtendingClass = enclosingClass.new DynamicExtendingClass();
-    private EnclosingDynamicClass enclosingDynamicClass = enclosingClass.new EnclosingDynamicClass();
-    private NestedDynamicClass nestedDynamicClass = enclosingDynamicClass.new NestedDynamicClass();
-//  NOT SUPPORTED
-//    private DynamicExtendingClassWithDifferentScope dynamicExtendingClassWithDifferentScope =
-//                enclosingClass.new DynamicExtendingClassWithDifferentScope(enclosingDynamicClass);
-
-    public static class EnclosingClass {
-        public class DynamicClass {
-            //Oracle/OpenJDK/IBM generates
-            //final EnclosingClass this$0;
-
-            //eclipse-[groovy-]compiler generates
-            //final EnclosingClass this$1;
-        }
-
-        public class DynamicExtendingClass extends DynamicClass {
-            //The field here masks the parent field
-
-            //Oracle/OpenJDK/IBM generates
-            //final EnclosingClass this$0;
-
-            //eclipse-[groovy-]compiler generates
-            //final EnclosingClass this$1;
-        }
-
-        public class EnclosingDynamicClass {
-            //Oracle/OpenJDK/IBM generates
-            //final EnclosingClass this$0;
-
-            //eclipse-[groovy-]compiler generates
-            //final EnclosingClass this$1;
-
-            public class NestedDynamicClass {
-                //Oracle/OpenJDK/IBM generates
-                //final EnclosingClass this$1;
-
-                //eclipse-[groovy-]compiler generates
-                //final EnclosingClass this$2;
-            }
-        }
-
-//        WARNING: Combination NOT SUPPORTED. Not enough information in XML to deserialize reliably,
-//        having in mind that different compilers could be used for parent/child classes.
-//        If we really need to, we can extend the heuristic to check for field types or assume that
-//        only one compiler was used for the whole class hierarchy covering some more cases.
-//
-//        The problem is that we have two fields with different names, without relation between the
-//        indexes in each one. Changing compilers (or combination of compilers) could change the 
-//        indexes independently in each field. This makes it impossible to infer which field in the xml
-//        maps to which field in the object.
-//        When having identical field names with parent classes XStream will put a defined-in attribute
-//        which makes it possible to deserialize, but it can't be forced to put it in each element.
-//
-        public class DynamicExtendingClassWithDifferentScope extends NestedDynamicClass {
-            //Oracle/OpenJDK/IBM generates
-            //final EnclosingClass this$0;
-
-            //eclipse-[groovy-]compiler generates
-            //final EnclosingClass this$1;
-
-            //constructor required to compile
-            public DynamicExtendingClassWithDifferentScope(EnclosingDynamicClass superEnclosingScope) {
-                superEnclosingScope.super();
-            }
-        }
-    }
-
-    @Test
-    public void testXStreamDeserialize() throws Exception {
-        deserialize("/brooklyn/entity/rebind/compiler_compatibility_eclipse.xml");
-        deserialize("/brooklyn/entity/rebind/compiler_compatibility_oracle.xml");
-    }
-
-    private void deserialize(String inputUrl) throws Exception {
-        XStream xstream = new XStream() {
-            @Override
-            protected MapperWrapper wrapMapper(MapperWrapper next) {
-                return new CompilerIndependentOuterClassFieldMapper(super.wrapMapper(next));
-            }
-        };
-
-        InputStream in = this.getClass().getResourceAsStream(inputUrl);
-        try {
-            Object obj = xstream.fromXML(in);
-            assertNonNullOuterFields(obj);
-        } finally {
-            in.close();
-        }
-    }
-
-    private void assertNonNullOuterFields(Object obj) throws Exception {
-        Field[] testInstances = obj.getClass().getDeclaredFields();
-        for (Field instanceField : testInstances) {
-            Object instance = instanceField.get(obj);
-            Class<?> type = instance.getClass();
-            do {
-                for (Field field : type.getDeclaredFields()) {
-                    if (field.getName().startsWith("this$")) {
-                        Object value = field.get(instance);
-                        assertTrue(value != null, field + " should not be null");
-                    }
-                }
-                type = type.getSuperclass();
-            } while (type != null);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/xstream/ConverterTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/xstream/ConverterTestFixture.java b/core/src/test/java/brooklyn/util/xstream/ConverterTestFixture.java
deleted file mode 100644
index bf566ba..0000000
--- a/core/src/test/java/brooklyn/util/xstream/ConverterTestFixture.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 brooklyn.util.xstream;
-
-import org.testng.Assert;
-
-import com.thoughtworks.xstream.XStream;
-
-public class ConverterTestFixture {
-
-    protected Object assertX(Object obj, String fmt) {
-        XStream xstream = new XStream();
-        registerConverters(xstream);
-        String s1 = xstream.toXML(obj);
-        Assert.assertEquals(s1, fmt);
-        Object out = xstream.fromXML(s1);
-        Assert.assertEquals(out, obj);
-        return out;
-    }
-
-    protected void registerConverters(XStream xstream) {
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/xstream/EnumCaseForgivingConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/xstream/EnumCaseForgivingConverterTest.java b/core/src/test/java/brooklyn/util/xstream/EnumCaseForgivingConverterTest.java
deleted file mode 100644
index f22f91b..0000000
--- a/core/src/test/java/brooklyn/util/xstream/EnumCaseForgivingConverterTest.java
+++ /dev/null
@@ -1,52 +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 brooklyn.util.xstream;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.fail;
-
-import org.testng.annotations.Test;
-
-public class EnumCaseForgivingConverterTest {
-
-    public enum MyEnum {
-        FOO,
-        BaR;
-    }
-    
-    @Test
-    public void testFindsCaseInsensitive() throws Exception {
-        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "FOO"), MyEnum.FOO);
-        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "foo"), MyEnum.FOO);
-        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "Foo"), MyEnum.FOO);
-        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "BAR"), MyEnum.BaR);
-        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "bar"), MyEnum.BaR);
-        assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "Bar"), MyEnum.BaR);
-    }
-    
-    @Test
-    public void testFailsIfNoMatch() throws Exception {
-        try {
-            assertEquals(EnumCaseForgivingConverter.resolve(MyEnum.class, "DoesNotExist"), MyEnum.BaR);
-            fail();
-        } catch (IllegalArgumentException e) {
-            if (!e.toString().matches(".*No enum.*MyEnum.DOESNOTEXIST")) throw e;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/xstream/ImmutableListConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/xstream/ImmutableListConverterTest.java b/core/src/test/java/brooklyn/util/xstream/ImmutableListConverterTest.java
deleted file mode 100644
index f8d8855..0000000
--- a/core/src/test/java/brooklyn/util/xstream/ImmutableListConverterTest.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 brooklyn.util.xstream;
-
-import java.net.UnknownHostException;
-
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-import com.thoughtworks.xstream.XStream;
-
-@Test
-public class ImmutableListConverterTest extends ConverterTestFixture {
-
-    protected void registerConverters(XStream xstream) {
-        super.registerConverters(xstream);
-        xstream.aliasType("ImmutableList", ImmutableList.class);
-        xstream.registerConverter(new ImmutableListConverter(xstream.getMapper()));
-    }
-
-    @Test
-    public void testImmutableEmptyList() throws UnknownHostException {
-        assertX(ImmutableList.of(), "<ImmutableList/>");
-    }
-
-    @Test
-    public void testImmutableSingletonDoubleList() throws UnknownHostException {
-        assertX(ImmutableList.of(1.2d), "<ImmutableList>\n  <double>1.2</double>\n</ImmutableList>");
-    }
-
-    @Test
-    public void testImmutableTwoValStringList() throws UnknownHostException {
-        assertX(ImmutableList.of("a","b"), "<ImmutableList>\n  <string>a</string>\n  <string>b</string>\n</ImmutableList>");
-    }
-
-    @Test
-    public void testImmutableEmptyListStaysImmutable() throws UnknownHostException {
-        Object x = assertX(ImmutableList.of(), "<ImmutableList/>");
-        Assert.assertTrue(x instanceof ImmutableList);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/xstream/InetAddressConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/xstream/InetAddressConverterTest.java b/core/src/test/java/brooklyn/util/xstream/InetAddressConverterTest.java
deleted file mode 100644
index 237c670..0000000
--- a/core/src/test/java/brooklyn/util/xstream/InetAddressConverterTest.java
+++ /dev/null
@@ -1,41 +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 brooklyn.util.xstream;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-import org.testng.annotations.Test;
-
-import com.thoughtworks.xstream.XStream;
-
-@Test
-public class InetAddressConverterTest extends ConverterTestFixture {
-
-    protected void registerConverters(XStream xstream) {
-        super.registerConverters(xstream);
-        xstream.registerConverter(new Inet4AddressConverter());
-    }
-
-    public void testFoo1234() throws UnknownHostException {
-        assertX(InetAddress.getByAddress("foo", new byte[] { 1, 2, 3, 4 }), 
-                "<java.net.Inet4Address>foo/1.2.3.4</java.net.Inet4Address>");
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/xstream/StringKeyMapConverterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/xstream/StringKeyMapConverterTest.java b/core/src/test/java/brooklyn/util/xstream/StringKeyMapConverterTest.java
deleted file mode 100644
index 7d30bc2..0000000
--- a/core/src/test/java/brooklyn/util/xstream/StringKeyMapConverterTest.java
+++ /dev/null
@@ -1,77 +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 brooklyn.util.xstream;
-
-import java.net.UnknownHostException;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.testng.annotations.Test;
-
-import brooklyn.util.collections.MutableMap;
-
-import com.google.common.collect.Maps;
-import com.thoughtworks.xstream.XStream;
-
-@SuppressWarnings({ "rawtypes", "unchecked" })
-@Test
-public class StringKeyMapConverterTest extends ConverterTestFixture {
-
-    protected void registerConverters(XStream xstream) {
-        super.registerConverters(xstream);
-        xstream.alias("map", Map.class, LinkedHashMap.class);
-        xstream.alias("MutableMap", MutableMap.class);
-        xstream.registerConverter(new StringKeyMapConverter(xstream.getMapper()), /* priority */ 10);
-    }
-
-    @Test
-    public void testSimple() throws UnknownHostException {
-        Map m = Maps.newLinkedHashMap();
-        m.put("a", "v");
-        assertX(m, "<map>\n  <a>v</a>\n</map>");
-    }
-    
-    @Test
-    public void testDouble() throws UnknownHostException {
-        Map m = Maps.newLinkedHashMap();
-        m.put("a", "v");
-        m.put("x", 1.0d);
-        assertX(m, "<map>\n  <a>v</a>\n  <x type=\"double\">1.0</x>\n</map>");
-    }
-    
-    @Test
-    public void testEmpty() throws UnknownHostException {
-        Map m = Maps.newLinkedHashMap();
-        assertX(m, "<map/>");
-    }
-    
-    @Test
-    public void testBigSpacedKeyInMutableMap() throws UnknownHostException {
-        Map m = MutableMap.of("a b", "x");
-        assertX(m, "<MutableMap>\n  <entry key=\"a b\">x</entry>\n</MutableMap>");
-    }
-
-    @Test
-    public void testWithNumericKey() throws UnknownHostException {
-        Map m = Maps.newLinkedHashMap();
-        m.put("123", "v");
-        m.put("a", "v2");
-        assertX(m, "<map>\n  <entry key=\"123\">v</entry>\n  <a>v2</a>\n</map>");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/xstream/XmlUtilTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/xstream/XmlUtilTest.java b/core/src/test/java/brooklyn/util/xstream/XmlUtilTest.java
deleted file mode 100644
index a81e299..0000000
--- a/core/src/test/java/brooklyn/util/xstream/XmlUtilTest.java
+++ /dev/null
@@ -1,33 +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 brooklyn.util.xstream;
-
-import static org.testng.Assert.assertEquals;
-
-import org.testng.annotations.Test;
-
-
-public class XmlUtilTest {
-
-    @Test
-    public void testXpath() throws Exception {
-        String xml = "<a><b>myb</b></a>";
-        assertEquals(XmlUtil.xpath(xml, "/a/b[text()]"), "myb");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogDtoTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogDtoTest.java b/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogDtoTest.java
index 90e039d..3229aac 100644
--- a/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogDtoTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogDtoTest.java
@@ -39,12 +39,12 @@ import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.catalog.internal.CatalogXmlSerializer;
 import org.apache.brooklyn.core.catalog.internal.CatalogClasspathDo.CatalogScanningModes;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.BrooklynMavenArtifacts;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
 
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.BrooklynMavenArtifacts;
 import brooklyn.util.maven.MavenRetriever;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogLoadTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogLoadTest.java b/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogLoadTest.java
index eea4933..fb28780 100644
--- a/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogLoadTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogLoadTest.java
@@ -28,8 +28,7 @@ import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
 import org.apache.brooklyn.core.catalog.internal.CatalogDto;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemDtoAbstract;
 import org.apache.brooklyn.core.catalog.internal.CatalogXmlSerializer;
-
-import brooklyn.util.ResourceUtils;
+import org.apache.brooklyn.core.util.ResourceUtils;
 
 import com.google.common.base.Joiner;
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogScanTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogScanTest.java b/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogScanTest.java
index 2d5abad..0ccb709 100644
--- a/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogScanTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogScanTest.java
@@ -34,11 +34,11 @@ import org.apache.brooklyn.core.catalog.CatalogPredicates;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
 import org.apache.brooklyn.core.catalog.internal.MyCatalogItems.MySillyAppTemplate;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
 
 import brooklyn.config.BrooklynProperties;
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.net.Urls;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/management/entitlement/AcmeEntitlementManagerTestFixture.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/management/entitlement/AcmeEntitlementManagerTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/management/entitlement/AcmeEntitlementManagerTestFixture.java
index 5689da2..24b1a1d 100644
--- a/core/src/test/java/org/apache/brooklyn/core/management/entitlement/AcmeEntitlementManagerTestFixture.java
+++ b/core/src/test/java/org/apache/brooklyn/core/management/entitlement/AcmeEntitlementManagerTestFixture.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.core.management.entitlement.NotEntitledException;
 import org.apache.brooklyn.core.management.entitlement.WebEntitlementContext;
 import org.apache.brooklyn.core.management.entitlement.Entitlements.EntityAndItem;
 import org.apache.brooklyn.core.management.entitlement.Entitlements.StringAndArgument;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
@@ -42,7 +43,6 @@ import brooklyn.config.BrooklynProperties;
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.BasicApplication;
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 
 public abstract class AcmeEntitlementManagerTestFixture {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/management/entitlement/EntityEntitlementTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/management/entitlement/EntityEntitlementTest.java b/core/src/test/java/org/apache/brooklyn/core/management/entitlement/EntityEntitlementTest.java
index bb25740..7181c99 100644
--- a/core/src/test/java/org/apache/brooklyn/core/management/entitlement/EntityEntitlementTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/management/entitlement/EntityEntitlementTest.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.core.management.entitlement.NotEntitledException;
 import org.apache.brooklyn.core.management.entitlement.Entitlements.EntityAndItem;
 import org.apache.brooklyn.core.management.entitlement.Entitlements.StringAndArgument;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,7 +41,6 @@ import brooklyn.config.BrooklynProperties;
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.BasicApplication;
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 
 public class EntityEntitlementTest {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/management/internal/EntityExecutionManagerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/management/internal/EntityExecutionManagerTest.java b/core/src/test/java/org/apache/brooklyn/core/management/internal/EntityExecutionManagerTest.java
index 7f35bba..721057d 100644
--- a/core/src/test/java/org/apache/brooklyn/core/management/internal/EntityExecutionManagerTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/management/internal/EntityExecutionManagerTest.java
@@ -37,6 +37,10 @@ import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.core.management.internal.BrooklynGarbageCollector;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.ExecutionListener;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -58,10 +62,6 @@ import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.repeat.Repeater;
-import brooklyn.util.task.BasicExecutionManager;
-import brooklyn.util.task.ExecutionListener;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/management/osgi/OsgiStandaloneTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/management/osgi/OsgiStandaloneTest.java b/core/src/test/java/org/apache/brooklyn/core/management/osgi/OsgiStandaloneTest.java
index 7f1cc48..7180b1b 100644
--- a/core/src/test/java/org/apache/brooklyn/core/management/osgi/OsgiStandaloneTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/management/osgi/OsgiStandaloneTest.java
@@ -27,6 +27,9 @@ import java.util.List;
 import java.util.jar.JarInputStream;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.osgi.Osgis;
+import org.apache.brooklyn.core.util.osgi.Osgis.ManifestHelper;
 import org.apache.brooklyn.test.TestResourceUnavailableException;
 
 import brooklyn.util.exceptions.Exceptions;
@@ -43,14 +46,11 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.maven.MavenArtifact;
 import brooklyn.util.maven.MavenRetriever;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
-import brooklyn.util.osgi.Osgis;
-import brooklyn.util.osgi.Osgis.ManifestHelper;
 import brooklyn.util.stream.Streams;
 
 /** 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/management/osgi/OsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/management/osgi/OsgiVersionMoreEntityTest.java b/core/src/test/java/org/apache/brooklyn/core/management/osgi/OsgiVersionMoreEntityTest.java
index 7220e47..edc73d6 100644
--- a/core/src/test/java/org/apache/brooklyn/core/management/osgi/OsgiVersionMoreEntityTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/management/osgi/OsgiVersionMoreEntityTest.java
@@ -45,6 +45,7 @@ import org.apache.brooklyn.core.catalog.internal.CatalogTestUtils;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.osgi.Osgis;
 
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.effector.Effectors;
@@ -57,7 +58,6 @@ import org.apache.brooklyn.test.entity.TestApplication;
 
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.os.Os;
-import brooklyn.util.osgi.Osgis;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/BrooklynMavenArtifactsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/BrooklynMavenArtifactsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/BrooklynMavenArtifactsTest.java
new file mode 100644
index 0000000..a86d1e0
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/BrooklynMavenArtifactsTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.util;
+
+import org.apache.brooklyn.core.util.BrooklynMavenArtifacts;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.test.Asserts;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.maven.MavenArtifact;
+import brooklyn.util.maven.MavenRetriever;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+@Test
+public class BrooklynMavenArtifactsTest {
+
+    private static final Logger log = LoggerFactory.getLogger(BrooklynMavenArtifactsTest.class);
+    
+    @Test(groups="Integration")
+    public void testUtilsCommon() {
+        ResourceUtils.create(this).checkUrlExists(BrooklynMavenArtifacts.localUrlForJar("brooklyn-utils-common"));
+    }
+
+    @Test(groups="Integration")
+    public void testExampleWar() {
+        String url = BrooklynMavenArtifacts.localUrl("example", "brooklyn-example-hello-world-sql-webapp", "war");
+        ResourceUtils.create(this).checkUrlExists(url);
+        log.info("found example war at: "+url);
+    }
+
+    @Test(groups="Integration")
+    // runs without internet but doesn't assert what it should, and can take a long time, so integration
+    public void testBadExampleWar() {
+        String url = BrooklynMavenArtifacts.localUrl("example", "brooklyn-example-GOODBYE-world-sql-webapp", "war");
+        Assert.assertFalse(ResourceUtils.create(this).doesUrlExist(url), "should not exist: "+url);
+    }
+
+    public void testHostedIsHttp() {
+        String common = BrooklynMavenArtifacts.hostedUrlForJar("brooklyn-utils-common");
+        log.info("online should be at: "+common);
+        Assert.assertTrue(common.startsWith("http"));
+    }
+
+    @Test(groups="Integration")
+    public void testHistoricHosted() {
+        // NB: this should be a version known to be up at sonatype or maven central, NOT necessarily the current version!
+        String snapshot = MavenRetriever.hostedUrl(MavenArtifact.fromCoordinate("org.apache.brooklyn:brooklyn-utils-common:jar:0.7.0-SNAPSHOT"));
+        log.info("Sample snapshot URL is: "+snapshot);
+        checkValidArchive(snapshot);
+        ResourceUtils.create(this).checkUrlExists(snapshot);
+        
+        // NB: this should be a version known to be up at sonatype or maven central, NOT necessarily the current version!
+        String release = MavenRetriever.hostedUrl(MavenArtifact.fromCoordinate("io.brooklyn:brooklyn-utils-common:jar:0.6.0"));
+        log.info("Sample release URL is: "+release);
+        checkValidArchive(release);
+    }
+
+    private void checkValidArchive(final String url) {
+        // Note have seen response code 500 from repository.apache.org, for
+        //   https://repository.apache.org/service/local/artifact/maven/redirect?r=snapshots&v=0.7.0-SNAPSHOT&g=org.apache.brooklyn&a=brooklyn-utils-common&e=jar
+        // Therefore willing to retry, rather than failing immediately.
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                try {
+                    byte[] bytes = Streams.readFully(ResourceUtils.create(this).getResourceFromUrl(url));
+                    // confirm this follow redirects!
+                    Assert.assertTrue(bytes.length > 100*1000, "download of "+url+" is suspect ("+Strings.makeSizeString(bytes.length)+")");
+                    // (could also check it is a zip etc)
+                } catch (Exception e) {
+                    throw Exceptions.propagate(e);
+                }
+            }});
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/ResourceUtilsHttpTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/ResourceUtilsHttpTest.java b/core/src/test/java/org/apache/brooklyn/core/util/ResourceUtilsHttpTest.java
new file mode 100644
index 0000000..6ea434d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/ResourceUtilsHttpTest.java
@@ -0,0 +1,197 @@
+/*
+ * 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.util;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.localserver.RequestBasicAuth;
+import org.apache.http.localserver.ResponseBasicUnauthorized;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.protocol.ResponseServer;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import brooklyn.test.TestHttpRequestHandler;
+import brooklyn.test.TestHttpServer;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Strings;
+
+public class ResourceUtilsHttpTest {
+    private ResourceUtils utils;
+    private TestHttpServer server;
+    private String baseUrl;
+
+    @BeforeClass(alwaysRun=true)
+    public void setUp() throws Exception {
+        utils = ResourceUtils.create(this, "mycontext");
+        server = new TestHttpServer()
+            .interceptor(new ResponseServer())
+            .interceptor(new ResponseBasicUnauthorized())
+            .interceptor(new RequestBasicAuth())
+            .handler("/simple", new TestHttpRequestHandler().response("OK"))
+            .handler("/empty", new TestHttpRequestHandler().code(HttpStatus.SC_NO_CONTENT))
+            .handler("/missing", new TestHttpRequestHandler().code(HttpStatus.SC_NOT_FOUND).response("Missing"))
+            .handler("/redirect", new TestHttpRequestHandler().code(HttpStatus.SC_MOVED_TEMPORARILY).response("Redirect").header("Location", "/simple"))
+            .handler("/cycle", new TestHttpRequestHandler().code(HttpStatus.SC_MOVED_TEMPORARILY).response("Redirect").header("Location", "/cycle"))
+            .handler("/secure", new TestHttpRequestHandler().code(HttpStatus.SC_MOVED_TEMPORARILY).response("Redirect").header("Location", "https://0.0.0.0/"))
+            .handler("/auth", new AuthHandler("test", "test", "OK"))
+            .handler("/auth_escape", new AuthHandler("test@me:/", "test", "OK"))
+            .handler("/auth_escape2", new AuthHandler("test@me:test", "", "OK"))
+            .handler("/no_credentials", new CheckNoCredentials())
+            .start();
+        baseUrl = server.getUrl();
+    }
+
+    @AfterClass(alwaysRun=true)
+    public void tearDown() throws Exception {
+        server.stop();
+    }
+
+    @Test
+    public void testGet() throws Exception {
+        InputStream stream = utils.getResourceFromUrl(baseUrl + "/simple");
+        assertEquals(Streams.readFullyString(stream), "OK");
+    }
+
+    @Test
+    public void testGetEmpty() throws Exception {
+        InputStream stream = utils.getResourceFromUrl(baseUrl + "/empty");
+        assertEquals(Streams.readFullyString(stream), "");
+    }
+
+    @Test
+    public void testGetProtected() throws Exception {
+        String url = baseUrl.replace("http://", "http://test:test@") + "/auth";
+        InputStream stream = utils.getResourceFromUrl(url);
+        assertEquals(Streams.readFullyString(stream), "OK");
+    }
+
+    @Test
+    public void testGetProtectedEscape() throws Exception {
+        String url = baseUrl.replace("http://", "http://test%40me%3A%2F:test@") + "/auth_escape";
+        InputStream stream = utils.getResourceFromUrl(url);
+        assertEquals(Streams.readFullyString(stream), "OK");
+    }
+
+    @Test
+    public void testGetProtectedEscape2() throws Exception {
+        String url = baseUrl.replace("http://", "http://test%40me%3Atest@") + "/auth_escape2";
+        InputStream stream = utils.getResourceFromUrl(url);
+        assertEquals(Streams.readFullyString(stream), "OK");
+    }
+
+    @Test(expectedExceptions = RuntimeException.class)
+    public void testProtectedFailsWithoutCredentials() throws Exception {
+        utils.getResourceFromUrl(baseUrl + "/auth");
+    }
+
+    @Test
+    public void testInvalidCredentialsNotPassed() throws Exception {
+        String url = baseUrl + "/no_credentials?no:auth@needed";
+        InputStream stream = utils.getResourceFromUrl(url);
+        assertEquals(Streams.readFullyString(stream), "OK");
+    }
+
+    @Test
+    public void testRedirect() throws Exception {
+        InputStream stream = utils.getResourceFromUrl(baseUrl + "/redirect");
+        assertEquals(Streams.readFullyString(stream), "OK");
+    }
+
+    @Test(expectedExceptions = RuntimeException.class)
+    public void testCycleRedirect() throws Exception {
+        InputStream stream = utils.getResourceFromUrl(baseUrl + "/cycle");
+        assertEquals(Streams.readFullyString(stream), "OK");
+    }
+
+    @Test(expectedExceptions = RuntimeException.class)
+    public void testGetMissing() throws Exception {
+        utils.getResourceFromUrl(baseUrl + "/missing");
+    }
+
+    @Test(expectedExceptions = RuntimeException.class)
+    public void testFollowsProtoChange() throws Exception {
+        utils.getResourceFromUrl(baseUrl + "/secure");
+    }
+
+    // See https://github.com/brooklyncentral/brooklyn/issues/1338
+    @Test(groups={"Integration"})
+    public void testResourceFromUrlFollowsRedirect() throws Exception {
+        String contents = new ResourceUtils(this).getResourceAsString("http://bit.ly/brooklyn-visitors-creation-script");
+        assertFalse(contents.contains("bit.ly"), "contents="+contents);
+    }
+
+    private static class AuthHandler implements HttpRequestHandler {
+        private String username;
+        private String password;
+        private String responseBody;
+
+        public AuthHandler(String username, String password, String response) {
+            this.username = username;
+            this.password = password;
+            this.responseBody = response;
+        }
+
+        @Override
+        public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
+            String creds = (String) context.getAttribute("creds");
+            if (creds == null || !creds.equals(getExpectedCredentials())) {
+                response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
+            } else {
+                response.setEntity(new StringEntity(responseBody));
+            }
+        }
+
+        private String getExpectedCredentials() {
+            if (Strings.isEmpty(password)) {
+                return username;
+            } else {
+                return username + ":" + password;
+            }
+        }
+
+    }
+
+    private static class CheckNoCredentials implements HttpRequestHandler {
+
+        @Override
+        public void handle(HttpRequest request, HttpResponse response,
+                HttpContext context) throws HttpException, IOException {
+            String creds = (String) context.getAttribute("creds");
+            if (creds == null) {
+                response.setEntity(new StringEntity("OK"));
+            } else {
+                response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
+            }
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/ResourceUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/ResourceUtilsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/ResourceUtilsTest.java
new file mode 100644
index 0000000..10cf455
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/ResourceUtilsTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.util;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Identifiers;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+
+public class ResourceUtilsTest {
+
+    private static final Logger log = LoggerFactory.getLogger(ResourceUtilsTest.class);
+    
+    private String tempFileContents = "abc";
+    private ResourceUtils utils;
+    private File tempFile;
+    
+    @BeforeClass(alwaysRun=true)
+    public void setUp() throws Exception {
+        utils = ResourceUtils.create(this, "mycontext");
+        tempFile = Os.writeToTempFile(new ByteArrayInputStream(tempFileContents.getBytes()), "resourceutils-test", ".txt");
+    }
+    
+    @AfterClass(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (tempFile != null) tempFile.delete();
+    }
+
+    @Test
+    public void testWriteStreamToTempFile() throws Exception {
+        File tempFileLocal = Os.writeToTempFile(new ByteArrayInputStream("mycontents".getBytes()), "resourceutils-test", ".txt");
+        try {
+            List<String> lines = Files.readLines(tempFileLocal, Charsets.UTF_8);
+            assertEquals(lines, ImmutableList.of("mycontents"));
+        } finally {
+            tempFileLocal.delete();
+        }
+    }
+
+    @Test
+    public void testPropertiesStreamToTempFile() throws Exception {
+        Properties props = new Properties();
+        props.setProperty("mykey", "myval");
+        File tempFileLocal = Os.writePropertiesToTempFile(props, "resourceutils-test", ".txt");
+        FileInputStream fis = null;
+        try {
+            fis = new FileInputStream(tempFileLocal);
+            Properties props2 = new Properties();
+            props2.load(fis);
+            assertEquals(props2.getProperty("mykey"), "myval");
+        } finally {
+            Streams.closeQuietly(fis);
+            tempFileLocal.delete();
+        }
+    }
+
+    @Test
+    public void testGetResourceViaClasspathWithPrefix() throws Exception {
+        InputStream stream = utils.getResourceFromUrl("classpath://brooklyn/config/sample.properties");
+        assertNotNull(stream);
+    }
+    
+    @Test
+    public void testGetResourceViaClasspathWithoutPrefix() throws Exception {
+        InputStream stream = utils.getResourceFromUrl("/brooklyn/config/sample.properties");
+        assertNotNull(stream);
+    }
+
+    @Test
+    public void testGetResourceViaFileWithPrefix() throws Exception {
+        // The correct format for file URLs is file:///<absolute path>.
+        // On UNIX file:///tmp.
+        // On Windows both file:/C:/temp and file:///C:/temp are supported by Java, 
+        // while Windows itself supports the latter only. 
+        // Note that file://C:/temp is *wrong*, because C: is interpreted as the host
+        InputStream stream = utils.getResourceFromUrl(tempFile.toURI().toURL().toString());
+        assertEquals(Streams.readFullyString(stream), tempFileContents);
+    }
+    
+    @Test
+    public void testGetResourceViaFileWithoutPrefix() throws Exception {
+        InputStream stream = utils.getResourceFromUrl(tempFile.getAbsolutePath());
+        assertEquals(Streams.readFullyString(stream), tempFileContents);
+    }
+
+    @Test
+    public void testClassLoaderDir() throws Exception {
+        String d = utils.getClassLoaderDir();
+        log.info("Found resource "+this+" in: "+d);
+        assertTrue(new File(d, "brooklyn/util/").exists());
+    }
+
+    @Test
+    public void testClassLoaderDirFromJar() throws Exception {
+        String d = utils.getClassLoaderDir("java/lang/Object.class");
+        log.info("Found Object in: "+d);
+        assertTrue(d.toLowerCase().endsWith(".jar"));
+    }
+
+    @Test
+    public void testClassLoaderDirFromJarWithSlash() throws Exception {
+        String d = utils.getClassLoaderDir("/java/lang/Object.class");
+        log.info("Found Object in: "+d);
+        assertTrue(d.toLowerCase().endsWith(".jar"));
+    }
+
+    @Test(expectedExceptions={NoSuchElementException.class})
+    public void testClassLoaderDirNotFound() throws Exception {
+        String d = utils.getClassLoaderDir("/somewhere/not/found/XXX.xxx");
+        // above should fail
+        log.warn("Uh oh found imaginary resource in: "+d);
+    }
+
+    @Test(groups="Integration")
+    public void testGetResourceViaSftp() throws Exception {
+        InputStream stream = utils.getResourceFromUrl("sftp://localhost:"+tempFile.getAbsolutePath());
+        assertEquals(Streams.readFullyString(stream), tempFileContents);
+    }
+    
+    @Test(groups="Integration")
+    public void testGetResourceViaSftpWithUsername() throws Exception {
+        String user = System.getProperty("user.name");
+        InputStream stream = utils.getResourceFromUrl("sftp://"+user+"@localhost:"+tempFile.getAbsolutePath());
+        assertEquals(Streams.readFullyString(stream), tempFileContents);
+    }
+
+    @Test
+    public void testDataUrl() throws Exception {
+        assertEquals(utils.getResourceAsString("data:,hello"), "hello");
+        assertEquals(utils.getResourceAsString("data:,hello%20world"), "hello world");
+        // above is correct. below are not valid ... but we accept them anyway
+        assertEquals(utils.getResourceAsString("data:hello"), "hello");
+        assertEquals(utils.getResourceAsString("data://hello"), "hello");
+        assertEquals(utils.getResourceAsString("data:hello world"), "hello world");
+        assertEquals(utils.getResourceAsString(Urls.asDataUrlBase64("hello world")), "hello world");
+        
+        String longString = Identifiers.makeRandomId(256);
+        for (int a=32; a<128; a++) longString += (char)a;
+        assertEquals(utils.getResourceAsString(Urls.asDataUrlBase64(longString)), longString);
+    }
+
+    @Test
+    public void testGetResources() {
+        Iterable<URL> manifests = ResourceUtils.create().getResources("META-INF/MANIFEST.MF");
+        assertFalse(Iterables.isEmpty(manifests));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/config/ConfigBagTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/config/ConfigBagTest.java b/core/src/test/java/org/apache/brooklyn/core/util/config/ConfigBagTest.java
new file mode 100644
index 0000000..f4db6c2
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/config/ConfigBagTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.util.config;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.config.ConfigBagTest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.time.Duration;
+
+public class ConfigBagTest {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(ConfigBagTest.class);
+    
+    private static final ConfigKey<String> K1 = ConfigKeys.newStringConfigKey("k1");
+    private static final ConfigKey<String> K2 = ConfigKeys.newStringConfigKey("k2");
+    private static final ConfigKey<String> K3 = ConfigKeys.newStringConfigKey("k3");
+    
+    @Test
+    public void testPutAndGet() {
+        ConfigBag bag = ConfigBag.newInstance();
+        bag.put(K1, "v1");
+        assertEquals(bag.get(K1), "v1");
+    }
+    
+    @Test
+    public void testPutStringAndGet() {
+        ConfigBag bag = ConfigBag.newInstance();
+        bag.putAsStringKey(K1.getName(), "v1");
+        assertEquals(bag.get(K1), "v1");
+    }
+    
+    @Test
+    public void testUnused() {
+        ConfigBag bag = ConfigBag.newInstance();
+        bag.put(K1, "v1");
+        bag.put(K2, "v2a");
+        assertEquals(bag.get(K1), "v1");
+        assertEquals(bag.getUnusedConfig().size(), 1);
+        assertEquals(bag.peek(K2), "v2a");
+        assertEquals(bag.getUnusedConfig().size(), 1);
+        assertEquals(bag.get(K2), "v2a");
+        Assert.assertTrue(bag.getUnusedConfig().isEmpty());
+    }
+
+    @Test
+    public void testOrder() {
+        ConfigBag bag = ConfigBag.newInstance();
+        bag.put(K1, "v1");
+        bag.put(K2, "v2");
+        bag.put(K3, "v3");
+        Assert.assertEquals(MutableList.copyOf(bag.getAllConfig().keySet()), MutableList.of(K1.getName(), K2.getName(), K3.getName()));
+        Assert.assertEquals(MutableList.copyOf(bag.getAllConfig().values()), MutableList.of("v1", "v2", "v3"));
+    }
+        
+    @Test
+    public void testCopyOverwriteAndGet() {
+        ConfigBag bag1 = ConfigBag.newInstance();
+        bag1.put(K1, "v1");
+        bag1.put(K2, "v2a");
+        bag1.put(K3, "v3");
+        assertEquals(bag1.get(K1), "v1");
+        
+        ConfigBag bag2 = ConfigBag.newInstanceCopying(bag1).putAll(MutableMap.of(K2, "v2b"));
+        assertEquals(bag1.getUnusedConfig().size(), 2);
+        assertEquals(bag2.getUnusedConfig().size(), 2);
+        
+        assertEquals(bag2.get(K1), "v1");
+        assertEquals(bag1.get(K2), "v2a");
+        assertEquals(bag1.getUnusedConfig().size(), 1);
+        assertEquals(bag2.getUnusedConfig().size(), 2);
+        
+        assertEquals(bag2.get(K2), "v2b");
+        assertEquals(bag2.getUnusedConfig().size(), 1);
+        
+        assertEquals(bag2.get(K3), "v3");
+        assertEquals(bag2.getUnusedConfig().size(), 0);
+        assertEquals(bag1.getUnusedConfig().size(), 1);
+    }
+    
+    @Test
+    public void testCopyExtendingAndGet() {
+        ConfigBag bag1 = ConfigBag.newInstance();
+        bag1.put(K1, "v1");
+        bag1.put(K2, "v2a");
+        bag1.put(K3, "v3");
+        assertEquals(bag1.get(K1), "v1");
+        
+        ConfigBag bag2 = ConfigBag.newInstanceExtending(bag1, null).putAll(MutableMap.of(K2, "v2b"));
+        assertEquals(bag1.getUnusedConfig().size(), 2);
+        assertEquals(bag2.getUnusedConfig().size(), 2, "unused are: "+bag2.getUnusedConfig());
+        
+        assertEquals(bag2.get(K1), "v1");
+        assertEquals(bag1.get(K2), "v2a");
+        assertEquals(bag1.getUnusedConfig().size(), 1);
+        assertEquals(bag2.getUnusedConfig().size(), 2);
+        
+        assertEquals(bag2.get(K2), "v2b");
+        assertEquals(bag2.getUnusedConfig().size(), 1);
+        
+        assertEquals(bag2.get(K3), "v3");
+        assertEquals(bag2.getUnusedConfig().size(), 0);
+        // when extended, the difference is that parent is also marked
+        assertEquals(bag1.getUnusedConfig().size(), 0);
+    }
+
+    @Test
+    public void testConcurrent() throws InterruptedException {
+        ConfigBag bag = ConfigBag.newInstance();
+        bag.put(K1, "v1");
+        bag.put(K2, "v2");
+        bag.put(K3, "v3");
+        runConcurrentTest(bag, 10, Duration.millis(50));
+    }
+    
+    @Test(groups="Integration")
+    public void testConcurrentBig() throws InterruptedException {
+        ConfigBag bag = ConfigBag.newInstance();
+        bag.put(K1, "v1");
+        bag.put(K2, "v2");
+        bag.put(K3, "v3");
+        runConcurrentTest(bag, 20, Duration.seconds(5));
+    }
+    
+    private void runConcurrentTest(final ConfigBag bag, int numThreads, Duration time) throws InterruptedException {
+        List<Thread> threads = MutableList.of();
+        final Map<Thread,Exception> exceptions = new ConcurrentHashMap<Thread,Exception>();
+        final AtomicInteger successes = new AtomicInteger();
+        for (int i=0; i<numThreads; i++) {
+            Thread t = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        while (!interrupted()) {
+                            if (Math.random()<0.9)
+                                bag.put(ConfigKeys.newStringConfigKey("k"+((int)(10*Math.random()))), "v"+((int)(10*Math.random())));
+                            if (Math.random()<0.8)
+                                bag.get(ConfigKeys.newStringConfigKey("k"+((int)(10*Math.random()))));
+                            if (Math.random()<0.2)
+                                bag.copy(bag);
+                            if (Math.random()<0.6)
+                                bag.remove(ConfigKeys.newStringConfigKey("k"+((int)(10*Math.random()))));
+                            successes.incrementAndGet();
+                        }
+                    } catch (Exception e) {
+                        exceptions.put(Thread.currentThread(), e);
+                        Exceptions.propagateIfFatal(e);
+                    }
+                }
+            };
+            t.setName("ConfigBagTest-concurrent-thread-"+i);
+            threads.add(t);
+        }
+        for (Thread t: threads) t.start();
+        time.countdownTimer().waitForExpiry();
+        for (Thread t: threads) t.interrupt();
+        for (Thread t: threads) t.join();
+        Assert.assertTrue(exceptions.isEmpty(), "Got "+exceptions.size()+"/"+numThreads+" exceptions ("+successes.get()+" successful): "+exceptions);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/crypto/SecureKeysAndSignerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/crypto/SecureKeysAndSignerTest.java b/core/src/test/java/org/apache/brooklyn/core/util/crypto/SecureKeysAndSignerTest.java
new file mode 100644
index 0000000..d681b0f
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/crypto/SecureKeysAndSignerTest.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.core.util.crypto;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.nio.charset.Charset;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.crypto.FluentKeySigner;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+import org.apache.brooklyn.core.util.crypto.SecureKeys.PassphraseProblem;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.util.crypto.AuthorizedKeysParser;
+import brooklyn.util.os.Os;
+
+import com.google.common.io.Files;
+
+public class SecureKeysAndSignerTest {
+
+    // a bit slow, so marked as integration (but possibly due to leftover rebind-cleanup, benign failures writing to /tmp/xx)
+    @Test(groups="Integration")
+    public void testGenerateSignedKeys() throws Exception {
+        FluentKeySigner signer = new FluentKeySigner("the-root").
+            validForYears(2).
+            selfsign();
+        X509Certificate signerCert = signer.getAuthorityCertificate();
+
+        KeyPair aKey = SecureKeys.newKeyPair();
+        X509Certificate aCert = signer.newCertificateFor("A", aKey);
+        
+        KeyPair bKey = SecureKeys.newKeyPair();
+        X509Certificate bCert = signer.newCertificateFor("B", bKey);
+
+        FluentKeySigner selfSigner1 = new FluentKeySigner("self1").selfsign();
+        X509Certificate selfCert1 = selfSigner1.getAuthorityCertificate();
+
+        SecureKeys.getTrustManager(aCert).checkClientTrusted(new X509Certificate[] { aCert }, "RSA");
+        SecureKeys.getTrustManager(signerCert).checkClientTrusted(new X509Certificate[] { signerCert }, "RSA");
+        
+        try {
+            SecureKeys.getTrustManager(aCert).checkClientTrusted(new X509Certificate[] { bCert }, "RSA");
+            Assert.fail("Trust manager for A should not accept B");
+        } catch (CertificateException e) { /* expected */ }
+        
+//        SecureKeys.getTrustManager(signerCert).checkClientTrusted(new X509Certificate[] { aCert }, "RSA");
+        // NB, the above failes; we have to convert to a canonical implementation, handled by the following
+        
+        Assert.assertTrue(SecureKeys.isCertificateAuthorizedBy(signerCert, signerCert));
+        Assert.assertTrue(SecureKeys.isCertificateAuthorizedBy(aCert, signerCert));
+        Assert.assertTrue(SecureKeys.isCertificateAuthorizedBy(bCert, signerCert));
+        Assert.assertFalse(SecureKeys.isCertificateAuthorizedBy(signerCert, aCert));
+        Assert.assertFalse(SecureKeys.isCertificateAuthorizedBy(bCert, aCert));
+        
+        Assert.assertTrue(SecureKeys.isCertificateAuthorizedBy(selfCert1, selfCert1));
+        Assert.assertFalse(SecureKeys.isCertificateAuthorizedBy(selfCert1, signerCert));
+    }
+
+    @Test
+    public void testInjectCertificateAuthority() throws Exception {
+        KeyPair caKey = SecureKeys.newKeyPair();
+        X509Certificate caCert = new FluentKeySigner("the-root", caKey).selfsign().getAuthorityCertificate();
+
+        FluentKeySigner signer = new FluentKeySigner(caCert, caKey);
+        Assert.assertEquals("the-root", signer.getCommonName());
+        
+        KeyPair aKey = SecureKeys.newKeyPair();
+        X509Certificate aCert = signer.newCertificateFor("A", aKey);
+        
+        Assert.assertTrue(SecureKeys.isCertificateAuthorizedBy(aCert, caCert));
+    }
+
+    @Test
+    public void testReadRsaKey() throws Exception {
+        KeyPair key = SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa.pem"), null);
+        checkNonTrivial(key);
+    }
+
+    @Test(expectedExceptions=IllegalStateException.class)
+    public void testReadRsaPublicKeyAsPemFails() throws Exception {
+        // should fail; see next test
+        SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa.pem.pub"), null);
+    }
+    
+    @Test
+    public void testReadRsaPublicKeyAsAuthKeysWorks() throws Exception {
+        PublicKey key = AuthorizedKeysParser.decodePublicKey(
+            ResourceUtils.create(this).getResourceAsString("classpath://brooklyn/util/crypto/sample_rsa.pem.pub"));
+        KeyPair fromPem = SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa.pem"), null);        
+        Assert.assertEquals(key, fromPem.getPublic());
+    }
+
+    @Test
+    public void testEncodeDecodeRsaPublicKey() throws Exception {
+        String data = ResourceUtils.create(this).getResourceAsString("classpath://brooklyn/util/crypto/sample_rsa.pem.pub");
+        PublicKey key = AuthorizedKeysParser.decodePublicKey(data);
+        String data2 = AuthorizedKeysParser.encodePublicKey(key);
+        Assert.assertTrue(data.contains(data2), "Expected to find '"+data2+"' in '"+data+"'");
+        PublicKey key2 = AuthorizedKeysParser.decodePublicKey(data2);
+        Assert.assertEquals(key2, key);
+    }
+
+    @Test
+    public void testEncodeDecodeDsaPublicKey() throws Exception {
+        String data = ResourceUtils.create(this).getResourceAsString("classpath://brooklyn/util/crypto/sample_dsa.pem.pub");
+        PublicKey key = AuthorizedKeysParser.decodePublicKey(data);
+        String data2 = AuthorizedKeysParser.encodePublicKey(key);
+        Assert.assertTrue(data.contains(data2), "Expected to find '"+data2+"' in '"+data+"'");
+        PublicKey key2 = AuthorizedKeysParser.decodePublicKey(data2);
+        Assert.assertEquals(key2, key);
+    }
+
+    @Test
+    public void testReadDsaKey() throws Exception {
+        KeyPair key = SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_dsa.pem"), null);
+        checkNonTrivial(key);
+    }
+
+    @Test(expectedExceptions=Exception.class)
+    public void testCantReadRsaPassphraseKeyWithoutPassphrase() throws Exception {
+        KeyPair key = SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa_passphrase.pem"), null);
+        checkNonTrivial(key);
+    }
+
+    @Test(expectedExceptions=PassphraseProblem.class)
+    public void testReadRsaPassphraseWithoutKeyFails() throws Exception {
+        SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa_passphrase.pem"), null);
+    }
+    
+    @Test
+    public void testReadRsaPassphraseKeyAndWriteWithoutPassphrase() throws Exception {
+        KeyPair key = SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa_passphrase.pem"), "passphrase");
+        checkNonTrivial(key);
+        File f = Os.newTempFile(getClass(), "brooklyn-sample_rsa_passphrase_without_passphrase.pem");
+        Files.write(SecureKeys.stringPem(key), f, Charset.defaultCharset());
+        KeyPair key2 = SecureKeys.readPem(new FileInputStream(f), null);
+        checkNonTrivial(key2);
+        Assert.assertEquals(key2.getPrivate().getEncoded(), key.getPrivate().getEncoded());
+        Assert.assertEquals(key2.getPublic().getEncoded(), key.getPublic().getEncoded());
+    }
+
+    private void checkNonTrivial(KeyPair key) {
+        Assert.assertNotEquals(key.getPrivate().getEncoded().length, 0);
+        Assert.assertNotEquals(key.getPublic().getEncoded().length, 0);
+    }
+
+}



[54/64] incubator-brooklyn git commit: brooklyn-software-database: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlIntegrationTest.java b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlIntegrationTest.java
deleted file mode 100644
index 523cbda..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlIntegrationTest.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 brooklyn.entity.database.mysql;
-
-import java.io.File;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.BrooklynAppLiveTestSupport;
-import brooklyn.entity.database.VogellaExampleAccess;
-import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.net.Networking;
-import brooklyn.util.os.Os;
-
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.io.Files;
-
-/**
- * Runs a slightly modified version of the popular Vogella MySQL tutorial,
- * from
- * http://www.vogella.de/articles/MySQLJava/article.html
- */
-public class MySqlIntegrationTest extends BrooklynAppLiveTestSupport {
-
-    public static final Logger log = LoggerFactory.getLogger(MySqlIntegrationTest.class);
-    
-    // can start in AWS by running this -- or use brooklyn CLI/REST for most clouds, or programmatic/config for set of fixed IP machines
-    static String hostname = Networking.getLocalHost().getHostName();
-
-    // From http://www.vogella.de/articles/MySQLJava/article.html
-    // Expects COMMENTS to be injected as the test.table.name config value, for VogellaExampleAccess to work.
-    public static final String CREATION_SCRIPT = Joiner.on("\n").join(ImmutableList.of(
-            "CREATE DATABASE feedback;",
-            "CREATE USER 'sqluser'@'localhost' IDENTIFIED BY 'sqluserpw';",
-            "GRANT USAGE ON *.* TO 'sqluser'@'localhost';",
-            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'localhost';",
-            "CREATE USER 'sqluser'@'%' IDENTIFIED BY 'sqluserpw';",
-            "GRANT USAGE ON *.* TO 'sqluser'@'%';",
-            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'%';",
-            "CREATE USER 'sqluser'@'$hostname' IDENTIFIED BY 'sqluserpw';",
-            "GRANT USAGE ON *.* TO 'sqluser'@'$hostname';",
-            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'$hostname';",
-            "FLUSH PRIVILEGES;",
-            "USE feedback;",
-            "CREATE TABLE ${config['test.table.name']} (",
-            "        id INT NOT NULL AUTO_INCREMENT,", 
-            "        MYUSER VARCHAR(30) NOT NULL,",
-            "        EMAIL VARCHAR(30), ",
-            "        WEBPAGE VARCHAR(100) NOT NULL,", 
-            "        DATUM DATE NOT NULL, ",
-            "        SUMMARY VARCHAR(40) NOT NULL,",
-            "        COMMENTS VARCHAR(400) NOT NULL,",
-            "        PRIMARY KEY (ID)",
-            "    );",
-            "",
-            "INSERT INTO ${config['test.table.name']} values (default, 'lars', 'myemail@gmail.com','http://www.vogella.de', '2009-09-14 10:33:11', 'Summary','My first comment' );"
-            ));
-
-    @Test(groups = {"Integration"})
-    public void test_localhost() throws Exception {
-        File dataDir = Files.createTempDir();
-        try {
-            MySqlNode mysql = app.createAndManageChild(EntitySpec.create(MySqlNode.class)
-                    .configure("mysql.server.conf", MutableMap.of("skip-name-resolve",""))
-                    .configure("creationScriptContents", CREATION_SCRIPT)
-                    .configure("dataDir", dataDir.getAbsolutePath())
-                    .configure("test.table.name", "COMMENTS")); // to ensure creation script is templated
-            LocalhostMachineProvisioningLocation location = new LocalhostMachineProvisioningLocation();
-            
-            app.start(ImmutableList.of(location));;
-            log.info("MySQL started");
-    
-            new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(MySqlNode.DATASTORE_URL)).readModifyAndRevertDataBase();
-    
-            log.info("Ran vogella MySQL example -- SUCCESS");
-    
-            // Ensure the data directory was successfully overridden.
-            File mysqlSubdirFile = new File(dataDir, "mysql");
-            Assert.assertTrue(mysqlSubdirFile.exists());
-        } finally {
-            Os.deleteRecursively(dataDir);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveEc2Test.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveEc2Test.java b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveEc2Test.java
deleted file mode 100644
index c9d5e97..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveEc2Test.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 brooklyn.entity.database.mysql;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-
-import com.google.common.collect.ImmutableList;
-
-@Test(groups = { "Live" })
-public class MySqlLiveEc2Test extends AbstractEc2LiveTest {
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        MySqlNode mysql = app.createAndManageChild(EntitySpec.create(MySqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
-                .configure("test.table.name", "COMMENTS"));
-
-        app.start(ImmutableList.of(loc));
-
-        new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
-    }
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_Debian_7_2() throws Exception { } // Disabled because MySQl not available
-
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveGceTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveGceTest.java b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveGceTest.java
deleted file mode 100644
index f6322bd..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveGceTest.java
+++ /dev/null
@@ -1,49 +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 brooklyn.entity.database.mysql;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractGoogleComputeLiveTest;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-
-import com.google.common.collect.ImmutableList;
-
-@Test(groups = { "Live" })
-public class MySqlLiveGceTest extends AbstractGoogleComputeLiveTest {
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        MySqlNode mysql = app.createAndManageChild(EntitySpec.create(MySqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
-                .configure("test.table.name", "COMMENTS"));
-
-        app.start(ImmutableList.of(loc));
-
-        new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
-    }
-
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveRackspaceTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveRackspaceTest.java b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveRackspaceTest.java
deleted file mode 100644
index 4175a7e..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlLiveRackspaceTest.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 brooklyn.entity.database.mysql;
-
-import java.util.Arrays;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.testng.annotations.Test;
-
-import brooklyn.config.BrooklynProperties;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import org.apache.brooklyn.location.jclouds.JcloudsLocation;
-import brooklyn.util.net.Protocol;
-import brooklyn.util.ssh.IptablesCommands;
-import brooklyn.util.ssh.IptablesCommands.Chain;
-import brooklyn.util.ssh.IptablesCommands.Policy;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * The MySqlLiveTest installs MySQL on various operating systems like Ubuntu, CentOS, Red Hat etc. To make sure that
- * MySQL works like expected on these Operating Systems.
- */
-public class MySqlLiveRackspaceTest extends MySqlIntegrationTest {
-    @Test(groups = {"Live"})
-    public void test_Debian_6() throws Exception {
-        test("Debian 6");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_Ubuntu_10_0() throws Exception {
-        test("Ubuntu 10.0");
-    }
-
-    @Test(groups = {"Live", "Live-sanity"})
-    public void test_Ubuntu_12_0() throws Exception {
-        test("Ubuntu 12.0");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_Ubuntu_13() throws Exception {
-        test("Ubuntu 13");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_CentOS_6() throws Exception {
-        test("CentOS 6");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_CentOS_5() throws Exception {
-        test("CentOS 5");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_Fedora() throws Exception {
-        test("Fedora ");
-    }
-
-    @Test(groups = {"Live"})
-    public void test_Red_Hat_Enterprise_Linux_6() throws Exception {
-        test("Red Hat Enterprise Linux 6");
-    }
-
-    @Test(enabled=false, groups = {"Live"}) // only run this in MySqlIntegrationTest
-    public void test_localhost() throws Exception {
-        super.test_localhost();
-    }
-
-    public void test(String osRegex) throws Exception {
-        MySqlNode mysql = app.createAndManageChild(EntitySpec.create(MySqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, CREATION_SCRIPT)
-                .configure("test.table.name", "COMMENTS"));
-
-        BrooklynProperties brooklynProperties = mgmt.getBrooklynProperties();
-        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageNameRegex", osRegex);
-        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.image-id");
-        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageId");
-        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.inboundPorts", Arrays.asList(22, 3306));
-        JcloudsLocation jcloudsLocation = (JcloudsLocation) mgmt.getLocationRegistry().resolve("jclouds:rackspace-cloudservers-uk");
-
-        app.start(ImmutableList.of(jcloudsLocation));
-
-        SshMachineLocation l = (SshMachineLocation) mysql.getLocations().iterator().next();
-        l.execCommands("add iptables rule", ImmutableList.of(IptablesCommands.insertIptablesRule(Chain.INPUT, Protocol.TCP, 3306, Policy.ACCEPT)));
-
-        new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
-    } 
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlRestartIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlRestartIntegrationTest.java b/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlRestartIntegrationTest.java
deleted file mode 100644
index ccc0e19..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MySqlRestartIntegrationTest.java
+++ /dev/null
@@ -1,42 +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 brooklyn.entity.database.mysql;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.AbstractSoftwareProcessRestartIntegrationTest;
-import brooklyn.entity.basic.SoftwareProcess;
-
-/**
- * Tests restart of the software *process* (as opposed to the VM).
- */
-@Test(groups="Integration")
-public class MySqlRestartIntegrationTest extends AbstractSoftwareProcessRestartIntegrationTest {
-    
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(MySqlRestartIntegrationTest.class);
-
-    @Override
-    protected EntitySpec<? extends SoftwareProcess> newEntitySpec() {
-        return EntitySpec.create(MySqlNode.class);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/mysql/MysqlDockerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/mysql/MysqlDockerLiveTest.java b/software/database/src/test/java/brooklyn/entity/database/mysql/MysqlDockerLiveTest.java
deleted file mode 100644
index 0642dd6..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/mysql/MysqlDockerLiveTest.java
+++ /dev/null
@@ -1,48 +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 brooklyn.entity.database.mysql;
-
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-import brooklyn.entity.software.AbstractDockerLiveTest;
-
-import com.google.common.collect.ImmutableList;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.testng.annotations.Test;
-
-public class MysqlDockerLiveTest extends AbstractDockerLiveTest {
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-       MySqlNode mysql = app.createAndManageChild(EntitySpec.create(MySqlNode.class)
-               .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
-               .configure("test.table.name", "COMMENTS"));
-
-       app.start(ImmutableList.of(loc));
-
-       new VogellaExampleAccess("com.mysql.jdbc.Driver", mysql.getAttribute(DatastoreCommon.DATASTORE_URL))
-               .readModifyAndRevertDataBase();
-    }
-
-    @Test(enabled=false)
-    public void testDummy() { } // Convince testng IDE integration that this really does have test methods
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqDockerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqDockerLiveTest.java b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqDockerLiveTest.java
deleted file mode 100644
index 8b23415..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqDockerLiveTest.java
+++ /dev/null
@@ -1,46 +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 brooklyn.entity.database.postgresql;
-
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-import brooklyn.entity.software.AbstractDockerLiveTest;
-
-import com.google.common.collect.ImmutableList;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.testng.annotations.Test;
-
-public class PostgreSqDockerLiveTest extends AbstractDockerLiveTest {
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        PostgreSqlNode psql = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT));
-
-        app.start(ImmutableList.of(loc));
-
-        new VogellaExampleAccess("org.postgresql.Driver", psql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
-    }
-
-    @Test(enabled=false)
-    public void testDummy() { } // Convince testng IDE integration that this really does have test methods
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
deleted file mode 100644
index 36eb963..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
+++ /dev/null
@@ -1,105 +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 brooklyn.entity.database.postgresql;
-
-import java.util.Random;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.chef.ChefLiveTestSupport;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-import brooklyn.entity.effector.EffectorTasks;
-import brooklyn.entity.software.SshEffectorTasks;
-
-import org.apache.brooklyn.api.location.PortRange;
-import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.location.basic.PortRanges;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.time.Duration;
-
-import com.google.common.collect.ImmutableList;
-
-/** 
- * Tests Chef installation of PostgreSql. Requires chef-server (knife).
- * <p> 
- * To be able to run repeatedly on the same box, you will need the patched version of the postgresql library,
- * at https://github.com/opscode-cookbooks/postgresql/pull/73 .
- *  
- * @author alex
- *
- */
-public class PostgreSqlChefTest extends ChefLiveTestSupport {
-
-    private static final Logger log = LoggerFactory.getLogger(PostgreSqlChefTest.class);
-    
-    PostgreSqlNode psql;
-    
-    @Test(groups="Live")
-    public void testPostgresStartsAndStops() throws Exception {
-        ChefLiveTestSupport.installBrooklynChefHostedConfig(app);
-        psql = app.createAndManageChild(PostgreSqlSpecs.specChef());
-
-        app.start(ImmutableList.of(targetLocation));
-        
-        Entities.submit(psql, SshEffectorTasks.ssh("ps aux | grep [p]ostgres").requiringExitCodeZero());
-        SshMachineLocation targetMachine = EffectorTasks.getSshMachine(psql);
-        
-        psql.stop();
-        
-        try {
-            // if host is still contactable ensure postgres is not running
-            ProcessTaskWrapper<Integer> t = Entities.submit(app, SshEffectorTasks.ssh("ps aux | grep [p]ostgres").machine(targetMachine).allowingNonZeroExitCode());
-            t.getTask().blockUntilEnded(Duration.TEN_SECONDS);
-            if (!t.isDone())
-                Assert.fail("Task not finished yet: "+t.getTask());
-            Assert.assertNotEquals(t.get(), (Integer)0, "Task ended with code "+t.get()+"; output: "+t.getStdout() );
-        } catch (Exception e) {
-            // host has been killed, that is fine
-            log.info("Machine "+targetMachine+" destroyed on stop (expected - "+e+")");
-        }
-    }
-    
-    @Test(groups="Live")
-    public void testPostgresScriptAndAccess() throws Exception {
-        ChefLiveTestSupport.installBrooklynChefHostedConfig(app);
-        PortRange randomPort = PortRanges.fromString(String.format("%d+", 5420 + new Random().nextInt(10)));
-        psql = app.createAndManageChild(PostgreSqlSpecs.specChef()
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
-                .configure(PostgreSqlNode.POSTGRESQL_PORT, randomPort)
-                .configure(PostgreSqlNode.SHARED_MEMORY, "8MB")
-            );
-
-        app.start(ImmutableList.of(targetLocation));
-
-        String url = psql.getAttribute(DatastoreCommon.DATASTORE_URL);
-        log.info("Trying to connect to "+psql+" at "+url);
-        Assert.assertNotNull(url);
-        Assert.assertTrue(url.contains("542"));
-        
-        new VogellaExampleAccess("org.postgresql.Driver", url).readModifyAndRevertDataBase();
-    }
-
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlEc2LiveTest.java b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlEc2LiveTest.java
deleted file mode 100644
index 5eda573..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlEc2LiveTest.java
+++ /dev/null
@@ -1,54 +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 brooklyn.entity.database.postgresql;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-
-import com.google.common.collect.ImmutableList;
-
-public class PostgreSqlEc2LiveTest extends AbstractEc2LiveTest {
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        PostgreSqlNode psql = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT));
-
-        app.start(ImmutableList.of(loc));
-
-        new VogellaExampleAccess("org.postgresql.Driver", psql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
-    }
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_Debian_6() throws Exception { } // Disabled because PostgreSql 9.1 not available
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_Ubuntu_10_0() throws Exception { } // Disabled because PostgreSql 9.1 not available
-
-    @Test(enabled=false)
-    public void testDummy() { } // Convince testng IDE integration that this really does have test methods
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlGceLiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlGceLiveTest.java b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlGceLiveTest.java
deleted file mode 100644
index 70e44e0..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlGceLiveTest.java
+++ /dev/null
@@ -1,46 +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 brooklyn.entity.database.postgresql;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractGoogleComputeLiveTest;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-
-import com.google.common.collect.ImmutableList;
-
-public class PostgreSqlGceLiveTest extends AbstractGoogleComputeLiveTest {
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        PostgreSqlNode psql = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT));
-
-        app.start(ImmutableList.of(loc));
-
-        new VogellaExampleAccess("org.postgresql.Driver", psql.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
-    }
-
-    @Test(enabled=false)
-    public void testDummy() { } // Convince testng IDE integration that this really does have test methods
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.java b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.java
deleted file mode 100644
index 7cb5863..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlIntegrationTest.java
+++ /dev/null
@@ -1,97 +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 brooklyn.entity.database.postgresql;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.apache.brooklyn.core.management.internal.LocalManagementContext;
-import org.apache.brooklyn.test.entity.TestApplication;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.config.BrooklynProperties;
-import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-
-import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Runs the popular Vogella MySQL tutorial against PostgreSQL
- * from
- * http://www.vogella.de/articles/MySQLJava/article.html
- */
-public class PostgreSqlIntegrationTest {
-
-    public static final Logger log = LoggerFactory.getLogger(PostgreSqlIntegrationTest.class);
-    
-    protected BrooklynProperties brooklynProperties;
-    protected ManagementContext managementContext;
-    protected TestApplication tapp;
-    
-    @BeforeMethod(alwaysRun = true)
-    public void setUp() {
-        brooklynProperties = BrooklynProperties.Factory.newDefault();
-        managementContext = new LocalManagementContext(brooklynProperties);
-        tapp = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void ensureShutDown() {
-        Entities.destroyAllCatching(managementContext);
-    }
-
-    //from http://www.vogella.de/articles/MySQLJava/article.html
-    public static final String CREATION_SCRIPT =
-            "CREATE USER sqluser WITH PASSWORD 'sqluserpw';\n" +
-            "CREATE DATABASE feedback OWNER sqluser;\n" +
-            "\\c feedback;\n" +
-            "CREATE TABLE COMMENTS ( " +
-                    "id INT8 NOT NULL,  " +
-                    "MYUSER VARCHAR(30) NOT NULL, " +
-                    "EMAIL VARCHAR(30),  " +
-                    "WEBPAGE VARCHAR(100) NOT NULL,  " +
-                    "DATUM DATE NOT NULL,  " +
-                    "SUMMARY VARCHAR(40) NOT NULL, " +
-                    "COMMENTS VARCHAR(400) NOT NULL, " +
-                    "PRIMARY KEY (ID) " +
-                ");\n" +
-            "GRANT ALL ON comments TO sqluser;\n" +
-            "INSERT INTO COMMENTS values (1, 'lars', 'myemail@gmail.com','http://www.vogella.de', '2009-09-14 10:33:11', 'Summary','My first comment' );";
-
-    @Test(groups = "Integration")
-    public void test_localhost() throws Exception {
-        PostgreSqlNode pgsql = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, CREATION_SCRIPT)
-                .configure(PostgreSqlNode.MAX_CONNECTIONS, 10)
-                .configure(PostgreSqlNode.SHARED_MEMORY, "512kB")); // Very low so kernel configuration not needed
-
-        tapp.start(ImmutableList.of(new LocalhostMachineProvisioningLocation()));
-        String url = pgsql.getAttribute(DatastoreCommon.DATASTORE_URL);
-        log.info("PostgreSql started on "+url);
-        new VogellaExampleAccess("org.postgresql.Driver", url).readModifyAndRevertDataBase();
-        log.info("Ran vogella PostgreSql example -- SUCCESS");
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRackspaceLiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRackspaceLiveTest.java b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRackspaceLiveTest.java
deleted file mode 100644
index bd6abbf..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRackspaceLiveTest.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 brooklyn.entity.database.postgresql;
-
-import java.util.Arrays;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-import org.apache.brooklyn.location.basic.PortRanges;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import org.apache.brooklyn.location.jclouds.JcloudsLocation;
-import brooklyn.util.net.Protocol;
-import brooklyn.util.ssh.IptablesCommands;
-import brooklyn.util.ssh.IptablesCommands.Chain;
-import brooklyn.util.ssh.IptablesCommands.Policy;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * The PostgreSqlRackspaceLiveTest installs Postgresql on various operating systems like Ubuntu, CentOS, Red Hat etc. To
- * make sure that PostgreSql works like expected on these Operating Systems.
- */
-public class PostgreSqlRackspaceLiveTest extends PostgreSqlIntegrationTest {
-    @Test(groups = "Live")
-    public void test_Debian_6() throws Exception {
-        test("Debian 6");
-    }
-
-    @Test(groups = "Live")
-    public void test_Ubuntu_10_0() throws Exception {
-        test("Ubuntu 10.0");
-    }
-
-    @Test(groups = "Live")
-    public void test_Ubuntu_11_0() throws Exception {
-        test("Ubuntu 11.0");
-    }
-
-    @Test(groups = "Live")
-    public void test_Ubuntu_12_0() throws Exception {
-        test("Ubuntu 12.0");
-    }
-
-    @Test(groups = "Live")
-    public void test_CentOS_6_0() throws Exception {
-        test("CentOS 6.0");
-    }
-
-    @Test(groups = "Live")
-    public void test_CentOS_5_6() throws Exception {
-        test("CentOS 5.6");
-    }
-
-    @Test(groups = "Live")
-    public void test_Fedora_17() throws Exception {
-        test("Fedora 17");
-    }
-
-    @Test(groups = "Live")
-    public void test_Red_Hat_Enterprise_Linux_6() throws Exception {
-        test("Red Hat Enterprise Linux 6");
-    }
-
-    @Test(groups = "Live")
-    public void test_localhost() throws Exception {
-        super.test_localhost();
-    }
-    
-    public void test(String osRegex) throws Exception {
-        PostgreSqlNode psql = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, CREATION_SCRIPT)
-                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(5432))
-                .configure(PostgreSqlNode.SHARED_MEMORY, "32MB"));
-
-        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageNameRegex", osRegex);
-        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.image-id");
-        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageId");
-        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.inboundPorts", Arrays.asList(22, 5432));
-        JcloudsLocation jcloudsLocation = (JcloudsLocation) managementContext.getLocationRegistry().resolve("jclouds:rackspace-cloudservers-uk");
-
-        tapp.start(ImmutableList.of(jcloudsLocation));
-
-        SshMachineLocation l = (SshMachineLocation) psql.getLocations().iterator().next();
-        l.execCommands("add iptables rule", ImmutableList.of(IptablesCommands.insertIptablesRule(Chain.INPUT, Protocol.TCP, 5432, Policy.ACCEPT)));
-
-        String url = psql.getAttribute(DatastoreCommon.DATASTORE_URL);
-        new VogellaExampleAccess("org.postgresql.Driver", url).readModifyAndRevertDataBase();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRebindIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRebindIntegrationTest.java b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRebindIntegrationTest.java
deleted file mode 100644
index 8a00587..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRebindIntegrationTest.java
+++ /dev/null
@@ -1,58 +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 brooklyn.entity.database.postgresql;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.rebind.RebindTestFixtureWithApp;
-import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
-public class PostgreSqlRebindIntegrationTest extends RebindTestFixtureWithApp {
-
-    private LocalhostMachineProvisioningLocation loc;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        loc = origApp.newLocalhostProvisioningLocation();
-    }
-
-    @Test(groups = {"Integration"})
-    public void testRebind() throws Exception {
-        origApp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class));
-        origApp.start(ImmutableList.of(loc));
-
-        // rebind
-        rebind();
-        final PostgreSqlNode newEntity = (PostgreSqlNode) Iterables.find(newApp.getChildren(), Predicates.instanceOf(PostgreSqlNode.class));
-
-        // confirm effectors still work on entity
-        EntityTestUtils.assertAttributeEqualsEventually(newEntity, PostgreSqlNode.SERVICE_UP, true);
-        newEntity.stop();
-        EntityTestUtils.assertAttributeEqualsEventually(newEntity, PostgreSqlNode.SERVICE_UP, false);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRestartIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRestartIntegrationTest.java b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRestartIntegrationTest.java
deleted file mode 100644
index ba2ff29..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlRestartIntegrationTest.java
+++ /dev/null
@@ -1,50 +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 brooklyn.entity.database.postgresql;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.AbstractSoftwareProcessRestartIntegrationTest;
-import brooklyn.entity.basic.SoftwareProcess;
-
-/**
- * Tests restart of the software *process* (as opposed to the VM).
- */
-@Test(groups="Integration")
-public class PostgreSqlRestartIntegrationTest extends AbstractSoftwareProcessRestartIntegrationTest {
-    
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(PostgreSqlRestartIntegrationTest.class);
-
-    @Override
-    protected EntitySpec<? extends SoftwareProcess> newEntitySpec() {
-        return EntitySpec.create(PostgreSqlNode.class);
-    }
-    
-    // TODO The second start() will fail because customize operations forbidden while there is existing data:
-    //      "If you want to create a new database system, either remove or empty".
-    // I haven't checked whether it damaged the data in the database though!
-    @Test(enabled=false, groups={"Integration", "WIP"})
-    public void testStopProcessAndStart() throws Exception {
-        super.testStopProcessAndStart();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepEc2LiveTest.java b/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepEc2LiveTest.java
deleted file mode 100644
index c53db06..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepEc2LiveTest.java
+++ /dev/null
@@ -1,75 +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 brooklyn.entity.database.rubyrep;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
-import brooklyn.entity.database.postgresql.PostgreSqlNode;
-
-import org.apache.brooklyn.location.basic.PortRanges;
-
-public class RubyRepEc2LiveTest extends AbstractEc2LiveTest {
-
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        PostgreSqlNode db1 = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
-                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9111)));
-
-        PostgreSqlNode db2 = app.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
-                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9111)));
-
-        RubyRepIntegrationTest.startInLocation(app, db1, db2, loc);
-        RubyRepIntegrationTest.testReplication(db1, db2);
-    }
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_Debian_6() throws Exception { } // Disabled because PostgreSql 9.1 not available
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_Ubuntu_10_0() throws Exception { } // Disabled because PostgreSql 9.1 not available
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_Debian_7_2() throws Exception { } // Diabling all except Ubuntu 12.0 temporarily
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_CentOS_6_3() throws Exception { } // Diabling all except Ubuntu 12.0 temporarily
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_CentOS_5() throws Exception { } // Diabling all except Ubuntu 12.0 temporarily
-
-    @Override
-    @Test(enabled=false, groups = "Live")
-    public void test_Red_Hat_Enterprise_Linux_6() throws Exception { } // Diabling all except Ubuntu 12.0 temporarily
-
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepIntegrationTest.java b/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepIntegrationTest.java
deleted file mode 100644
index 7028d1b..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepIntegrationTest.java
+++ /dev/null
@@ -1,191 +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 brooklyn.entity.database.rubyrep;
-
-import static org.testng.Assert.assertEquals;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.apache.brooklyn.core.management.internal.LocalManagementContext;
-import org.apache.brooklyn.test.entity.TestApplication;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.config.BrooklynProperties;
-import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.VogellaExampleAccess;
-import brooklyn.entity.database.mysql.MySqlIntegrationTest;
-import brooklyn.entity.database.mysql.MySqlNode;
-import brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
-import brooklyn.entity.database.postgresql.PostgreSqlNode;
-
-import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.location.basic.PortRanges;
-
-public class RubyRepIntegrationTest {
-
-    public static final Logger log = LoggerFactory.getLogger(RubyRepIntegrationTest.class);
-    protected BrooklynProperties brooklynProperties;
-    protected ManagementContext managementContext;
-    protected TestApplication tapp;
-    
-    @BeforeMethod(alwaysRun = true)
-    public void setUp() {
-        brooklynProperties = BrooklynProperties.Factory.newDefault();
-        managementContext = new LocalManagementContext(brooklynProperties);
-        tapp = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
-    }
-
-    @AfterMethod(alwaysRun = true)
-    public void tearDown() {
-        Entities.destroyAllCatching(managementContext);
-    }
-
-    @Test(groups = "Integration")
-    public void test_localhost_mysql() throws Exception {
-        MySqlNode db1 = tapp.createAndManageChild(EntitySpec.create(MySqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
-                .configure("test.table.name", "COMMENTS")
-                .configure(MySqlNode.MYSQL_PORT, PortRanges.fromInteger(9111)));
-
-        MySqlNode db2 = tapp.createAndManageChild(EntitySpec.create(MySqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
-                .configure("test.table.name", "COMMENTS")
-                .configure(MySqlNode.MYSQL_PORT, PortRanges.fromInteger(9112)));
-
-
-        startInLocation(tapp, db1, db2, new LocalhostMachineProvisioningLocation());
-        testReplication(db1, db2);
-    }
-
-    /**
-     * Altered to use a single postgresql server to avoid issues with shared memory limits
-     */
-    @Test(groups = {"Integration"})
-    public void test_localhost_postgres() throws Exception {
-        String createTwoDbsScript = PostgreSqlIntegrationTest.CREATION_SCRIPT +
-                PostgreSqlIntegrationTest.CREATION_SCRIPT.replaceAll("CREATE USER.*", "").replaceAll(" feedback", " feedback1");
-
-        PostgreSqlNode db1 = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, createTwoDbsScript)
-                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9113))
-                .configure(PostgreSqlNode.MAX_CONNECTIONS, 10)
-                .configure(PostgreSqlNode.SHARED_MEMORY, "512kB")); // Very low so kernel configuration not needed
-
-        startInLocation(tapp, db1, "feedback", db1, "feedback1", new LocalhostMachineProvisioningLocation());
-        testReplication(db1, "feedback", db1, "feedback1");
-    }
-
-    @Test(enabled = false, groups = "Integration") // TODO this doesn't appear to be supported by RubyRep
-    public void test_localhost_postgres_mysql() throws Exception {
-        PostgreSqlNode db1 = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
-                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9115))
-                .configure(PostgreSqlNode.MAX_CONNECTIONS, 10)
-                .configure(PostgreSqlNode.SHARED_MEMORY, "512kB")); // Very low so kernel configuration not needed
-
-        MySqlNode db2 = tapp.createAndManageChild(EntitySpec.create(MySqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MySqlIntegrationTest.CREATION_SCRIPT)
-                .configure(MySqlNode.MYSQL_PORT, PortRanges.fromInteger(9116)));
-
-        startInLocation(tapp, db1, db2, new LocalhostMachineProvisioningLocation());
-        testReplication(db1, db2);
-    }
-
-    public static void startInLocation(TestApplication tapp, DatastoreCommon db1, DatastoreCommon db2, Location... locations) throws Exception {
-        startInLocation(tapp, db1, "feedback", db2, "feedback", locations);
-    }
-
-    /**
-     * Configures rubyrep to connect to the two databases and starts the app
-     */
-    public static void startInLocation(TestApplication tapp, DatastoreCommon db1, String dbName1, DatastoreCommon db2, String dbName2, Location... locations) throws Exception {
-        tapp.createAndManageChild(EntitySpec.create(RubyRepNode.class)
-                .configure("startupTimeout", 300)
-                .configure("leftDatabase", db1)
-                .configure("rightDatabase", db2)
-                .configure("leftUsername", "sqluser")
-                .configure("rightUsername", "sqluser")
-                .configure("rightPassword", "sqluserpw")
-                .configure("leftPassword", "sqluserpw")
-                .configure("leftDatabaseName", dbName1)
-                .configure("rightDatabaseName", dbName2)
-                .configure("replicationInterval", 1)
-        );
-
-        tapp.start(Arrays.asList(locations));
-    }
-
-    public static void testReplication(DatastoreCommon db1, DatastoreCommon db2) throws Exception {
-        testReplication(db1, "feedback", db2, "feedback");
-    }
-
-    /**
-     * Tests replication between the two databases by altering the first and checking the change is applied to the second
-     */
-    public static void testReplication(DatastoreCommon db1, String dbName1, DatastoreCommon db2, String dbName2) throws Exception {
-        String db1Url = db1.getAttribute(DatastoreCommon.DATASTORE_URL);
-        String db2Url = db2.getAttribute(DatastoreCommon.DATASTORE_URL);
-
-        log.info("Testing replication between " + db1Url + " and " + db2Url);
-
-        VogellaExampleAccess vea1 = new VogellaExampleAccess(db1 instanceof MySqlNode ? "com.mysql.jdbc.Driver" : "org.postgresql.Driver", db1Url, dbName1);
-        VogellaExampleAccess vea2 = new VogellaExampleAccess(db2 instanceof MySqlNode ? "com.mysql.jdbc.Driver" : "org.postgresql.Driver", db2Url, dbName2);
-
-        try {
-            vea1.connect();
-            List<List<String>> rs = vea1.readDataBase();
-            assertEquals(rs.size(), 1);
-
-            vea2.connect();
-            rs = vea2.readDataBase();
-            assertEquals(rs.size(), 1);
-
-            log.info("Modifying left database");
-            vea1.modifyDataBase();
-
-            log.info("Reading left database");
-            rs = vea1.readDataBase();
-            assertEquals(rs.size(), 2);
-
-            log.info("Reading right database");
-            rs = vea2.readDataBase();
-
-            for (int i = 0; i < 60 && rs.size() != 2; i++) {
-                log.info("Sleeping for a second");
-                Thread.sleep(1000);
-                rs = vea2.readDataBase();
-            }
-
-            assertEquals(rs.size(), 2);
-        } finally {
-            vea1.close();
-            vea2.close();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepRackspaceLiveTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepRackspaceLiveTest.java b/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepRackspaceLiveTest.java
deleted file mode 100644
index 845dce7..0000000
--- a/software/database/src/test/java/brooklyn/entity/database/rubyrep/RubyRepRackspaceLiveTest.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 brooklyn.entity.database.rubyrep;
-
-import java.util.Arrays;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
-import brooklyn.entity.database.postgresql.PostgreSqlNode;
-
-import org.apache.brooklyn.location.basic.PortRanges;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.net.Protocol;
-import brooklyn.util.ssh.IptablesCommands;
-import brooklyn.util.ssh.IptablesCommands.Chain;
-import brooklyn.util.ssh.IptablesCommands.Policy;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-/**
- * The RubyRepRackspaceLiveTest installs RubyRep on various operating systems like Ubuntu, CentOS, Red Hat etc. To make sure that
- * RubyRep and PostgreSql works like expected on these Operating Systems.
- */
-public class RubyRepRackspaceLiveTest extends RubyRepIntegrationTest {
-    
-    @Test(groups = "Live")
-    public void test_Debian_6() throws Exception {
-        test("Debian 6");
-    }
-
-    @Test(groups = "Live")
-    public void test_Ubuntu_10_0() throws Exception {
-        test("Ubuntu 10.0");
-    }
-
-    @Test(groups = "Live")
-    public void test_Ubuntu_12_0() throws Exception {
-        test("Ubuntu 12.0");
-    }
-
-    @Test(groups = "Live")
-    public void test_Ubuntu_13() throws Exception {
-        test("Ubuntu 13");
-    }
-
-    @Test(groups = "Live")
-    public void test_CentOS_6() throws Exception {
-        test("CentOS 6");
-    }
-
-    @Test(groups = "Live")
-    public void test_CentOS_5() throws Exception {
-        test("CentOS 5");
-    }
-
-    @Test(groups = "Live")
-    public void test_Fedora() throws Exception {
-        test("Fedora ");
-    }
-
-    @Test(groups = "Live")
-    public void test_Red_Hat_Enterprise_Linux_6() throws Exception {
-        test("Red Hat Enterprise Linux 6");
-    }
-
-    public void test(String osRegex) throws Exception {
-        PostgreSqlNode db1 = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
-                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9111)));
-        PostgreSqlNode db2 = tapp.createAndManageChild(EntitySpec.create(PostgreSqlNode.class)
-                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, PostgreSqlIntegrationTest.CREATION_SCRIPT)
-                .configure(PostgreSqlNode.POSTGRESQL_PORT, PortRanges.fromInteger(9111)));
-
-        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageNameRegex", osRegex);
-        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.image-id");
-        brooklynProperties.remove("brooklyn.location.jclouds.rackspace-cloudservers-uk.imageId");
-        brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.inboundPorts", Arrays.asList(22, 9111));
-        Location loc = managementContext.getLocationRegistry().resolve("jclouds:rackspace-cloudservers-uk");
-        
-        startInLocation(tapp, db1, db2, loc);
-
-        //hack to get the port for mysql open; is the inbounds property not respected on rackspace??
-        for (DatastoreCommon node : ImmutableSet.of(db1, db2)) {
-            SshMachineLocation l = (SshMachineLocation) node.getLocations().iterator().next();
-            l.execCommands("add iptables rule", ImmutableList.of(IptablesCommands.insertIptablesRule(Chain.INPUT, Protocol.TCP, 9111, Policy.ACCEPT)));
-        }
-
-        testReplication(db1, db2);
-    }
-    
-    // disable inherited non-live tests
-    @Test(enabled = false, groups = "Integration")
-    public void test_localhost_mysql() throws Exception {
-        super.test_localhost_mysql();
-    }
-
-    // disable inherited non-live tests
-    @Test(enabled = false, groups = "Integration")
-    public void test_localhost_postgres() throws Exception {
-        super.test_localhost_postgres();
-    }
-
-    // disable inherited non-live tests
-    @Test(enabled = false, groups = "Integration")
-    public void test_localhost_postgres_mysql() throws Exception {
-        super.test_localhost_postgres_mysql();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/VogellaExampleAccess.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/VogellaExampleAccess.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/VogellaExampleAccess.java
new file mode 100644
index 0000000..6b5a6cb
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/VogellaExampleAccess.java
@@ -0,0 +1,161 @@
+/*
+ * 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.entity.database;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+import java.sql.*;
+import java.util.List;
+
+/**
+ * Basic JDBC Access test Class, based on the Vogella MySQL tutorial
+ * http://www.vogella.de/articles/MySQLJava/article.html
+ */
+public class VogellaExampleAccess {
+    public static final Logger log = LoggerFactory.getLogger(VogellaExampleAccess.class);
+
+    private Connection connect = null;
+    private Statement statement = null;
+    private final String url;
+    private final String dbName;
+
+    public VogellaExampleAccess(String driverClass, String url) throws ClassNotFoundException {
+        this(driverClass, url, "feedback");
+    }
+    
+    public VogellaExampleAccess(String driverClass, String url, String dbName) throws ClassNotFoundException {
+        // This will load the JDBC driver, each DB has its own driver
+        Class.forName(driverClass);
+        this.url = url;
+        this.dbName = dbName;
+    }
+
+    public void readModifyAndRevertDataBase() throws Exception {
+        connect();
+        readDataBase();
+        modifyDataBase();
+        revertDatabase();
+        close();
+    }
+
+    public void connect() throws Exception {
+        try {
+            // Setup the connection with the DB
+            String jdbcUrl = "jdbc:" + url + dbName + "?" + "user=sqluser&password=sqluserpw";
+            log.info("Connecting to " + jdbcUrl);
+            connect = DriverManager.getConnection(jdbcUrl);
+
+            // Statements allow to issue SQL queries to the database
+            statement = connect.createStatement();
+        } catch (Exception ex) {
+            close();
+            throw ex;
+        }
+    }
+
+    public List<List<String>> readDataBase() throws Exception {
+        List<List<String>> results = Lists.newArrayList();
+        // Result set get the result of the SQL query
+        ResultSet resultSet = statement.executeQuery("SELECT myuser, webpage, datum, summary, COMMENTS from COMMENTS");
+        // ResultSet is initially before the first data set
+        while (resultSet.next()) {
+            List<String> row = Lists.newArrayList();
+            for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
+                row.add(resultSet.getObject(i).toString());
+            }
+            results.add(row);
+        }
+        // Should close resultsets
+        resultSet.close();
+        writeResultSet(results);
+        return results;
+    }
+
+    public void modifyDataBase() throws Exception {
+        // PreparedStatements can use variables and are more efficient
+        PreparedStatement preparedStatement = connect.prepareStatement("insert into  COMMENTS values (?, ?, ?, ?, ? , ?, ?)");
+        // "myuser, webpage, datum, summary, COMMENTS from FEEDBACK.COMMENTS");
+        // Parameters start with 1
+        preparedStatement.setInt(1, 2);
+        preparedStatement.setString(2, "Test");
+        preparedStatement.setString(3, "TestEmail");
+        preparedStatement.setString(4, "TestWebpage");
+        preparedStatement.setDate(5, new Date(new java.util.Date().getTime()));
+        preparedStatement.setString(6, "TestSummary");
+        preparedStatement.setString(7, "TestComment");
+        preparedStatement.executeUpdate();
+
+        writeResultSet(readDataBase());
+        preparedStatement.close();
+    }
+
+    // Remove again the insert comment added by modifyDataBase()
+    public void revertDatabase() throws Exception {
+        PreparedStatement preparedStatement = connect
+                .prepareStatement("delete from COMMENTS where myuser= ? ; ");
+        preparedStatement.setString(1, "Test");
+        preparedStatement.executeUpdate();
+
+        ResultSet resultSet = statement.executeQuery("select * from COMMENTS");
+        writeMetaData(resultSet);
+        // Should close resultsets
+        resultSet.close();
+    }
+
+    private void writeMetaData(ResultSet resultSet) throws SQLException {
+        // Get some metadata from the database
+        log.info("The columns in the table are: ");
+
+        log.info("Table: " + resultSet.getMetaData().getTableName(1));
+        for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) {
+            log.info("Column " + i + " " + resultSet.getMetaData().getColumnName(i));
+        }
+    }
+
+    private void writeResultSet(List<List<String>> resultSet) throws SQLException {
+        for (List<String> row : resultSet) {
+            String user = row.get(0);
+            String website = row.get(1);
+            String date = row.get(2);
+            String summary = row.get(3);
+            String comment = row.get(4);
+            log.info("User: " + user);
+            log.info("Website: " + website);
+            log.info("Summary: " + summary);
+            log.info("Date: " + date);
+            log.info("Comment: " + comment);
+        }
+    }
+
+    // You should always close the statement and connection
+    public void close() throws Exception {
+        if (statement != null) {
+            statement.close();
+            statement = null;
+        }
+
+        if (connect != null) {
+            connect.close();
+            connect = null;
+        }
+    }
+}    
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/crate/CrateNodeIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/crate/CrateNodeIntegrationTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/crate/CrateNodeIntegrationTest.java
new file mode 100644
index 0000000..e91b4ad
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/crate/CrateNodeIntegrationTest.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.entity.database.crate;
+
+import static org.testng.Assert.assertFalse;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.trait.Startable;
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+
+public class CrateNodeIntegrationTest {
+
+    private TestApplication app;
+    private LocalhostMachineProvisioningLocation localhostProvisioningLocation;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() throws Exception {
+        localhostProvisioningLocation = new LocalhostMachineProvisioningLocation();
+        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void tearDown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    @Test(groups = "Integration")
+    public void testCanStartAndStop() throws Exception {
+        CrateNode entity = app.createAndManageChild(EntitySpec.create(CrateNode.class));
+        app.start(ImmutableList.of(localhostProvisioningLocation));
+
+        EntityTestUtils.assertAttributeEqualsEventually(entity, Startable.SERVICE_UP, true);
+        EntityTestUtils.assertAttributeEventuallyNonNull(entity, CrateNode.SERVER_NAME);
+
+        entity.stop();
+        assertFalse(entity.getAttribute(Startable.SERVICE_UP));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbIntegrationTest.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbIntegrationTest.java
new file mode 100644
index 0000000..8e846e1
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbIntegrationTest.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.entity.database.mariadb;
+
+import java.io.File;
+import java.net.InetAddress;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.test.entity.TestApplication;
+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 brooklyn.config.BrooklynProperties;
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.text.Strings;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Runs a slightly modified version of the popular Vogella MySQL tutorial,
+ * from
+ * http://www.vogella.de/articles/MySQLJava/article.html
+ */
+public class MariaDbIntegrationTest {
+
+    public static final Logger log = LoggerFactory.getLogger(MariaDbIntegrationTest.class);
+    
+    protected BrooklynProperties brooklynProperties;
+    protected ManagementContext managementContext;
+    protected TestApplication tapp;
+    protected String hostname;
+    
+    @BeforeMethod(alwaysRun = true)
+    public void setUp() throws Exception {
+        // can start in AWS by running this -- or use brooklyn CLI/REST for most clouds, or programmatic/config for set of fixed IP machines
+        hostname = InetAddress.getLocalHost().getHostName();
+
+        brooklynProperties = BrooklynProperties.Factory.newDefault();
+        managementContext = new LocalManagementContext(brooklynProperties);
+        tapp = ApplicationBuilder.newManagedApp(TestApplication.class, managementContext);
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void ensureShutDown() throws Exception {
+        Entities.destroyAllCatching(managementContext);
+    }
+
+    //from http://www.vogella.de/articles/MySQLJava/article.html
+    public static final String CREATION_SCRIPT =
+            "CREATE DATABASE feedback; " +
+            "CREATE USER 'sqluser'@'localhost' IDENTIFIED BY 'sqluserpw'; " +
+            "GRANT USAGE ON *.* TO 'sqluser'@'localhost'; " +
+            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'localhost'; " +
+            "CREATE USER 'sqluser'@'%' IDENTIFIED BY 'sqluserpw'; " +
+            "GRANT USAGE ON *.* TO 'sqluser'@'%'; " +
+            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'%'; " +
+            "CREATE USER 'sqluser'@'$hostname' IDENTIFIED BY 'sqluserpw'; " +
+            "GRANT USAGE ON *.* TO 'sqluser'@'$hostname'; " +
+            "GRANT ALL PRIVILEGES ON feedback.* TO 'sqluser'@'$hostname'; " +
+            "FLUSH PRIVILEGES; " +
+            "USE feedback; " +
+            "CREATE TABLE COMMENTS ( " +
+                    "id INT NOT NULL AUTO_INCREMENT,  " +
+                    "MYUSER VARCHAR(30) NOT NULL, " +
+                    "EMAIL VARCHAR(30),  " +
+                    "WEBPAGE VARCHAR(100) NOT NULL,  " +
+                    "DATUM DATE NOT NULL,  " +
+                    "SUMMARY VARCHAR(40) NOT NULL, " +
+                    "COMMENTS VARCHAR(400) NOT NULL, " +
+                    "PRIMARY KEY (ID) " +
+                "); " +
+            "INSERT INTO COMMENTS values (default, 'lars', 'myemail@gmail.com','http://www.vogella.de', '2009-09-14 10:33:11', 'Summary','My first comment' );";
+
+    @Test(groups = "Integration")
+    public void test_localhost() throws Exception {
+        String dataDir = "/tmp/mariadb-data-" + Strings.makeRandomId(8);
+        MariaDbNode mariadb = tapp.createAndManageChild(EntitySpec.create(MariaDbNode.class)
+                .configure(MariaDbNode.MARIADB_SERVER_CONF, MutableMap.<String, Object>of("skip-name-resolve",""))
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, CREATION_SCRIPT)
+                .configure(MariaDbNode.DATA_DIR, dataDir));
+        LocalhostMachineProvisioningLocation location = new LocalhostMachineProvisioningLocation();
+
+        tapp.start(ImmutableList.of(location));
+        log.info("MariaDB started");
+
+        new VogellaExampleAccess("com.mysql.jdbc.Driver", mariadb.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
+
+        log.info("Ran vogella MySQL example -- SUCCESS");
+
+        // Ensure the data directory was successfully overridden.
+        File dataDirFile = new File(dataDir);
+        File mariadbSubdirFile = new File(dataDirFile, "mysql");
+        Assert.assertTrue(mariadbSubdirFile.exists());
+
+        // Clean up.
+        dataDirFile.delete();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbLiveEc2Test.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbLiveEc2Test.java b/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbLiveEc2Test.java
new file mode 100644
index 0000000..6fbf43e
--- /dev/null
+++ b/software/database/src/test/java/org/apache/brooklyn/entity/database/mariadb/MariaDbLiveEc2Test.java
@@ -0,0 +1,57 @@
+/*
+ * 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.entity.database.mariadb;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+
+import org.apache.brooklyn.location.jclouds.JcloudsLocation;
+
+import com.google.common.collect.ImmutableList;
+
+@Test(groups = { "Live" })
+public class MariaDbLiveEc2Test extends AbstractEc2LiveTest {
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        // TODO For some CentOS VMs (e.g. in AWS 6.3, us-east-1/ami-a96b01c0), currently need to turn off iptables unfortunately.
+        // Should really just open the ports in iptables.
+        MariaDbNode mariadb = app.createAndManageChild(EntitySpec.create(MariaDbNode.class)
+                .configure(DatastoreCommon.CREATION_SCRIPT_CONTENTS, MariaDbIntegrationTest.CREATION_SCRIPT)
+                .configure(MariaDbNode.PROVISIONING_PROPERTIES.subKey(JcloudsLocation.STOP_IPTABLES.getName()), true));
+
+        app.start(ImmutableList.of(loc));
+
+        new VogellaExampleAccess("com.mysql.jdbc.Driver", mariadb.getAttribute(DatastoreCommon.DATASTORE_URL)).readModifyAndRevertDataBase();
+    }
+
+    @Override
+    @Test(enabled=false, groups = "Live")
+    public void test_Debian_7_2() throws Exception { } // Disabled because MariaDB not available
+
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+
+}
+



[19/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ForwardingTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ForwardingTask.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ForwardingTask.java
new file mode 100644
index 0000000..794dea9
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ForwardingTask.java
@@ -0,0 +1,325 @@
+/*
+ * 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.util.task;
+
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.brooklyn.api.management.Task;
+
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ForwardingObject;
+import com.google.common.util.concurrent.ExecutionList;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public abstract class ForwardingTask<T> extends ForwardingObject implements TaskInternal<T> {
+
+    /** Constructor for use by subclasses. */
+    protected ForwardingTask() {}
+
+    @Override
+    protected abstract TaskInternal<T> delegate();
+
+    @Override
+    public void addListener(Runnable listener, Executor executor) {
+        delegate().addListener(listener, executor);
+    }
+
+    @Override
+    public boolean cancel(boolean arg0) {
+        return delegate().cancel(arg0);
+    }
+
+    @Override
+    public T get() throws InterruptedException, ExecutionException {
+        return delegate().get();
+    }
+
+    @Override
+    public T get(long arg0, TimeUnit arg1) throws InterruptedException, ExecutionException, TimeoutException {
+        return delegate().get(arg0, arg1);
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return delegate().isCancelled();
+    }
+
+    @Override
+    public boolean isDone() {
+        return delegate().isDone();
+    }
+
+    @Override
+    public Task<T> asTask() {
+        return delegate().asTask();
+    }
+
+    @Override
+    public String getId() {
+        return delegate().getId();
+    }
+
+    @Override
+    public Set<Object> getTags() {
+        return delegate().getTags();
+    }
+
+    @Override
+    public long getSubmitTimeUtc() {
+        return delegate().getSubmitTimeUtc();
+    }
+
+    @Override
+    public long getStartTimeUtc() {
+        return delegate().getStartTimeUtc();
+    }
+
+    @Override
+    public long getEndTimeUtc() {
+        return delegate().getEndTimeUtc();
+    }
+
+    @Override
+    public String getDisplayName() {
+        return delegate().getDisplayName();
+    }
+
+    @Override
+    public String getDescription() {
+        return delegate().getDescription();
+    }
+
+    @Override
+    public Task<?> getSubmittedByTask() {
+        return delegate().getSubmittedByTask();
+    }
+
+    @Override
+    public Thread getThread() {
+        return delegate().getThread();
+    }
+
+    @Override
+    public boolean isSubmitted() {
+        return delegate().isSubmitted();
+    }
+
+    @Override
+    public boolean isBegun() {
+        return delegate().isBegun();
+    }
+
+    @Override
+    public boolean isError() {
+        return delegate().isError();
+    }
+
+    @Override
+    public void blockUntilStarted() {
+        delegate().blockUntilStarted();
+    }
+
+    @Override
+    public void blockUntilEnded() {
+        delegate().blockUntilEnded();
+    }
+
+    @Override
+    public boolean blockUntilEnded(Duration timeout) {
+        return delegate().blockUntilEnded(timeout);
+    }
+
+    @Override
+    public String getStatusSummary() {
+        return delegate().getStatusSummary();
+    }
+
+    @Override
+    public String getStatusDetail(boolean multiline) {
+        return delegate().getStatusDetail(multiline);
+    }
+
+    @Override
+    public T get(Duration duration) throws InterruptedException, ExecutionException, TimeoutException {
+        return delegate().get(duration);
+    }
+
+    @Override
+    public T getUnchecked() {
+        return delegate().getUnchecked();
+    }
+
+    @Override
+    public T getUnchecked(Duration duration) {
+        return delegate().getUnchecked(duration);
+    }
+
+    @Override
+    public void initInternalFuture(ListenableFuture<T> result) {
+        delegate().initInternalFuture(result);
+    }
+
+    @Override
+    public long getQueuedTimeUtc() {
+        return delegate().getQueuedTimeUtc();
+    }
+
+    @Override
+    public Future<T> getInternalFuture() {
+        return delegate().getInternalFuture();
+    }
+
+    @Override
+    public boolean isQueued() {
+        return delegate().isQueued();
+    }
+
+    @Override
+    public boolean isQueuedOrSubmitted() {
+        return delegate().isQueuedOrSubmitted();
+    }
+
+    @Override
+    public boolean isQueuedAndNotSubmitted() {
+        return delegate().isQueuedAndNotSubmitted();
+    }
+
+    @Override
+    public void markQueued() {
+        delegate().markQueued();
+    }
+
+    @Override
+    public boolean cancel() {
+        return delegate().cancel();
+    }
+
+    @Override
+    public boolean blockUntilStarted(Duration timeout) {
+        return delegate().blockUntilStarted(timeout);
+    }
+
+    @Override
+    public String setBlockingDetails(String blockingDetails) {
+        return delegate().setBlockingDetails(blockingDetails);
+    }
+
+    @Override
+    public Task<?> setBlockingTask(Task<?> blockingTask) {
+        return delegate().setBlockingTask(blockingTask);
+    }
+
+    @Override
+    public void resetBlockingDetails() {
+        delegate().resetBlockingDetails();
+    }
+
+    @Override
+    public void resetBlockingTask() {
+        delegate().resetBlockingTask();
+    }
+
+    @Override
+    public String getBlockingDetails() {
+        return delegate().getBlockingDetails();
+    }
+
+    @Override
+    public Task<?> getBlockingTask() {
+        return delegate().getBlockingTask();
+    }
+
+    @Override
+    public void setExtraStatusText(Object extraStatus) {
+        delegate().setExtraStatusText(extraStatus);
+    }
+
+    @Override
+    public Object getExtraStatusText() {
+        return delegate().getExtraStatusText();
+    }
+
+    @Override
+    public void runListeners() {
+        delegate().runListeners();
+    }
+
+    @Override
+    public void setEndTimeUtc(long val) {
+        delegate().setEndTimeUtc(val);
+    }
+
+    @Override
+    public void setThread(Thread thread) {
+        delegate().setThread(thread);
+    }
+
+    @Override
+    public Callable<T> getJob() {
+        return delegate().getJob();
+    }
+
+    @Override
+    public void setJob(Callable<T> job) {
+        delegate().setJob(job);
+    }
+
+    @Override
+    public ExecutionList getListeners() {
+        return delegate().getListeners();
+    }
+
+    @Override
+    public void setSubmitTimeUtc(long currentTimeMillis) {
+        delegate().setSubmitTimeUtc(currentTimeMillis);
+    }
+
+    @Override
+    public void setSubmittedByTask(Task<?> task) {
+        delegate().setSubmittedByTask(task);
+    }
+
+    @Override
+    public Set<Object> getMutableTags() {
+        return delegate().getMutableTags();
+    }
+
+    @Override
+    public void setStartTimeUtc(long currentTimeMillis) {
+        delegate().setStartTimeUtc(currentTimeMillis);
+    }
+
+    @Override
+    public void applyTagModifier(Function<Set<Object>, Void> modifier) {
+        delegate().applyTagModifier(modifier);
+    }
+    
+    @Override
+    public Task<?> getProxyTarget() {
+        return delegate().getProxyTarget();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ListenableForwardingFuture.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ListenableForwardingFuture.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ListenableForwardingFuture.java
new file mode 100644
index 0000000..bfe88b0
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ListenableForwardingFuture.java
@@ -0,0 +1,50 @@
+/*
+ * 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.util.task;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+
+import com.google.common.util.concurrent.ExecutionList;
+import com.google.common.util.concurrent.ForwardingFuture.SimpleForwardingFuture;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/** Wraps a Future, making it a ListenableForwardingFuture, but with the caller having the resposibility to:
+ * <li> invoke the listeners on job completion (success or error)
+ * <li> invoke the listeners on cancel */
+public abstract class ListenableForwardingFuture<T> extends SimpleForwardingFuture<T> implements ListenableFuture<T> {
+
+    final ExecutionList listeners;
+    
+    protected ListenableForwardingFuture(Future<T> delegate) {
+        super(delegate);
+        this.listeners = new ExecutionList();
+    }
+
+    protected ListenableForwardingFuture(Future<T> delegate, ExecutionList list) {
+        super(delegate);
+        this.listeners = list;
+    }
+
+    @Override
+    public void addListener(Runnable listener, Executor executor) {
+        listeners.add(listener, executor);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ParallelTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ParallelTask.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ParallelTask.java
new file mode 100644
index 0000000..10da414
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ParallelTask.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.util.task;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.brooklyn.api.management.Task;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.text.Strings;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+
+/**
+ * Runs {@link Task}s in parallel.
+ *
+ * No guarantees of order of starting the tasks, but the return value is a
+ * {@link List} of the return values of supplied tasks in the same
+ * order they were passed as arguments.
+ */
+public class ParallelTask<T> extends CompoundTask<T> {
+    public ParallelTask(Object... tasks) { super(tasks); }
+    
+    public ParallelTask(Map<String,?> flags, Collection<? extends Object> tasks) { super(flags, tasks); }
+    public ParallelTask(Collection<? extends Object> tasks) { super(tasks); }
+    
+    public ParallelTask(Map<String,?> flags, Iterable<? extends Object> tasks) { super(flags, ImmutableList.copyOf(tasks)); }
+    public ParallelTask(Iterable<? extends Object> tasks) { super(ImmutableList.copyOf(tasks)); }
+
+    @Override
+    protected List<T> runJobs() throws InterruptedException, ExecutionException {
+        setBlockingDetails("Executing "+
+                (children.size()==1 ? "1 child task" :
+                children.size()+" children tasks in parallel") );
+        for (Task<? extends T> task : children) {
+            submitIfNecessary(task);
+        }
+
+        List<T> result = Lists.newArrayList();
+        List<Exception> exceptions = Lists.newArrayList();
+        for (Task<? extends T> task : children) {
+            T x;
+            try {
+                x = task.get();
+            } catch (Exception e) {
+                Exceptions.propagateIfFatal(e);
+                if (TaskTags.isInessential(task)) {
+                    // ignore exception as it's inessential
+                } else {
+                    exceptions.add(e);
+                }
+                x = null;
+            }
+            result.add(x);
+        }
+        
+        if (exceptions.isEmpty()) {
+            return result;
+        } else {
+            if (result.size()==1 && exceptions.size()==1)
+                throw Exceptions.propagate( exceptions.get(0) );
+            throw Exceptions.propagate(exceptions.size()+" of "+result.size()+" parallel child task"+Strings.s(result.size())+" failed", exceptions);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ScheduledTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ScheduledTask.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ScheduledTask.java
new file mode 100644
index 0000000..5c4b208
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ScheduledTask.java
@@ -0,0 +1,185 @@
+/*
+ * 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.util.task;
+
+import static brooklyn.util.GroovyJavaMethods.elvis;
+import static brooklyn.util.GroovyJavaMethods.truth;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.management.Task;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.time.Duration;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Throwables;
+
+/**
+ * A task which runs with a fixed period.
+ * <p>
+ * Note that some termination logic, including {@link #addListener(Runnable, java.util.concurrent.Executor)},
+ * is not precisely defined. 
+ */
+// TODO ScheduledTask is a very pragmatic implementation; would be nice to tighten, 
+// reduce external assumptions about internal structure, and clarify "done" semantics
+public class ScheduledTask extends BasicTask {
+    
+    final Callable<Task<?>> taskFactory;
+    /** initial delay before running, set as flag in constructor; defaults to 0 */
+    protected Duration delay;
+    /** time to wait between executions, or null if not to repeat (default), set as flag to constructor;
+     * this may be modified for subsequent submissions by a running task generated by the factory 
+     * using getSubmittedByTask().setPeriod(Duration) */
+    protected Duration period = null;
+    /** optional, set as flag in constructor; defaults to null meaning no limit */
+    protected Integer maxIterations = null;
+    
+    protected int runCount=0;
+    protected Task<?> recentRun, nextRun;
+
+    public int getRunCount() { return runCount; }
+    public ScheduledFuture<?> getNextScheduled() { return (ScheduledFuture<?>)internalFuture; }
+
+    public ScheduledTask(Callable<Task<?>> taskFactory) {
+        this(MutableMap.of(), taskFactory);
+    }
+
+    public ScheduledTask(final Task<?> task) {
+        this(MutableMap.of(), task);
+    }
+
+    public ScheduledTask(Map flags, final Task<?> task){
+        this(flags, new Callable<Task<?>>(){
+            @Override
+            public Task<?> call() throws Exception {
+                return task;
+            }});
+    }
+
+    public ScheduledTask(Map flags, Callable<Task<?>> taskFactory) {
+        super(flags);
+        this.taskFactory = taskFactory;
+        
+        delay = Duration.of(elvis(flags.remove("delay"), 0));
+        period = Duration.of(elvis(flags.remove("period"), null));
+        maxIterations = elvis(flags.remove("maxIterations"), null);
+    }
+    
+    public ScheduledTask delay(Duration d) {
+        this.delay = d;
+        return this;
+    }
+    public ScheduledTask delay(long val) {
+        return delay(Duration.millis(val));
+    }
+
+    public ScheduledTask period(Duration d) {
+        this.period = d;
+        return this;
+    }
+    public ScheduledTask period(long val) {
+        return period(Duration.millis(val));
+    }
+
+    public ScheduledTask maxIterations(int val) {
+        this.maxIterations = val;
+        return this;
+    }
+
+    public Callable<Task<?>> getTaskFactory() {
+        return taskFactory;
+    }
+
+    public Task<?> newTask() {
+        try {
+            return taskFactory.call();
+        } catch (Exception e) {
+            throw Throwables.propagate(e);
+        }
+    }
+    
+    protected String getActiveTaskStatusString(int verbosity) {
+        StringBuilder rv = new StringBuilder("Scheduler");
+        if (runCount>0) rv.append(", iteration "+(runCount+1));
+        if (recentRun!=null) rv.append(", last run "+
+            Duration.sinceUtc(recentRun.getStartTimeUtc())+" ms ago");
+        if (truth(getNextScheduled())) {
+            Duration untilNext = Duration.millis(getNextScheduled().getDelay(TimeUnit.MILLISECONDS));
+            if (untilNext.isPositive())
+                rv.append(", next in "+untilNext);
+            else 
+                rv.append(", next imminent");
+        }
+        return rv.toString();
+    }
+    
+    @Override
+    public boolean isDone() {
+        return isCancelled() || (maxIterations!=null && maxIterations <= runCount) || (period==null && nextRun!=null && nextRun.isDone());
+    }
+    
+    public synchronized void blockUntilFirstScheduleStarted() {
+        // TODO Assumes that maxIterations is not negative!
+        while (true) {
+            if (isCancelled()) throw new CancellationException();
+            if (recentRun==null)
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    Throwables.propagate(e);
+                }
+            if (recentRun!=null) return;
+        }
+    }
+    
+    public void blockUntilEnded() {
+        while (!isDone()) super.blockUntilEnded();
+    }
+
+    /** gets the value of the most recently run task */
+    public Object get() throws InterruptedException, ExecutionException {
+        blockUntilStarted();
+        blockUntilFirstScheduleStarted();
+        return (truth(recentRun)) ? recentRun.get() : internalFuture.get();
+    }
+    
+    @Override
+    public synchronized boolean cancel(boolean mayInterrupt) {
+        boolean result = super.cancel(mayInterrupt);
+        if (nextRun!=null) {
+            nextRun.cancel(mayInterrupt);
+            notifyAll();
+        }
+        return result;
+    }
+    
+    /** internal method used to allow callers to wait for underlying tasks to finished in the case of cancellation 
+     * @param duration */ 
+    @Beta
+    public boolean blockUntilNextRunFinished(Duration timeout) {
+        return Tasks.blockUntilInternalTasksEnded(nextRun, timeout);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/SequentialTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/SequentialTask.java b/core/src/main/java/org/apache/brooklyn/core/util/task/SequentialTask.java
new file mode 100644
index 0000000..93ecdf6
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/SequentialTask.java
@@ -0,0 +1,58 @@
+/*
+ * 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.util.task;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.brooklyn.api.management.Task;
+
+import com.google.common.collect.ImmutableList;
+
+
+/** runs tasks in order, waiting for one to finish before starting the next; return value here is TBD;
+ * (currently is all the return values of individual tasks, but we
+ * might want some pipeline support and eventually only to return final value...) */
+public class SequentialTask<T> extends CompoundTask<T> {
+
+    public SequentialTask(Object... tasks) { super(tasks); }
+    
+    public SequentialTask(Map<String,?> flags, Collection<? extends Object> tasks) { super(flags, tasks); }
+    public SequentialTask(Collection<? extends Object> tasks) { super(tasks); }
+    
+    public SequentialTask(Map<String,?> flags, Iterable<? extends Object> tasks) { super(flags, ImmutableList.copyOf(tasks)); }
+    public SequentialTask(Iterable<? extends Object> tasks) { super(ImmutableList.copyOf(tasks)); }
+    
+    protected List<T> runJobs() throws InterruptedException, ExecutionException {
+        setBlockingDetails("Executing "+
+                (children.size()==1 ? "1 child task" :
+                children.size()+" children tasks sequentially") );
+
+        List<T> result = new ArrayList<T>();
+        for (Task<? extends T> task : children) {
+            submitIfNecessary(task);
+            // throw exception (and cancel subsequent tasks) on error
+            result.add(task.get());
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/SingleThreadedScheduler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/SingleThreadedScheduler.java b/core/src/main/java/org/apache/brooklyn/core/util/task/SingleThreadedScheduler.java
new file mode 100644
index 0000000..2a5b51d
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/SingleThreadedScheduler.java
@@ -0,0 +1,216 @@
+/*
+ * 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.util.task;
+
+import java.util.Queue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.brooklyn.api.management.Task;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Instances of this class ensures that {@link Task}s execute with in-order
+ * single-threaded semantics.
+ *
+ * Tasks can be presented through {@link #submit(Callable)}. The order of execution is the
+ * sumbission order.
+ * <p>
+ * This implementation does so by blocking on a {@link ConcurrentLinkedQueue}, <em>after</em>
+ * the task is started in a thread (and {@link Task#isBegun()} returns true), but (of course)
+ * <em>before</em> the {@link TaskInternal#getJob()} actually gets invoked.
+ */
+public class SingleThreadedScheduler implements TaskScheduler, CanSetName {
+    private static final Logger LOG = LoggerFactory.getLogger(SingleThreadedScheduler.class);
+    
+    private final Queue<QueuedSubmission<?>> order = new ConcurrentLinkedQueue<QueuedSubmission<?>>();
+    private int queueSize = 0;
+    private final AtomicBoolean running = new AtomicBoolean(false);
+    
+    private ExecutorService executor;
+
+    private String name;
+    
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String toString() {
+        return name!=null ? "SingleThreadedScheduler["+name+"]" : super.toString();
+    }
+    
+    @Override
+    public void injectExecutor(ExecutorService executor) {
+        this.executor = executor;
+    }
+
+    @Override
+    public synchronized <T> Future<T> submit(Callable<T> c) {
+        if (running.compareAndSet(false, true)) {
+            return executeNow(c);
+        } else {
+            WrappingFuture<T> f = new WrappingFuture<T>();
+            order.add(new QueuedSubmission<T>(c, f));
+            queueSize++;
+            if (queueSize>0 && (queueSize == 50 || (queueSize<=500 && (queueSize%100)==0) || (queueSize%1000)==0) && queueSize!=lastSizeWarn) {
+                LOG.warn("{} is backing up, {} tasks queued", this, queueSize);
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Task queue backing up detail, queue "+this+"; task context is "+Tasks.current()+"; latest task is "+c+"; first task is "+order.peek());
+                }
+                lastSizeWarn = queueSize;
+            }
+            return f;
+        }
+    }
+    int lastSizeWarn = 0;
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private synchronized void onEnd() {
+        boolean done = false;
+        while (!done) {
+            if (order.isEmpty()) {
+                running.set(false);
+                done = true;
+            } else {
+                QueuedSubmission<?> qs = order.remove();
+                queueSize--;
+                if (!qs.f.isCancelled()) {
+                    Future future = executeNow(qs.c);
+                    qs.f.setDelegate(future);
+                    done = true;
+                }
+            }
+        }
+    }
+
+    private synchronized <T> Future<T> executeNow(final Callable<T> c) {
+        return executor.submit(new Callable<T>() {
+            @Override public T call() throws Exception {
+                try {
+                    return c.call();
+                } finally {
+                    onEnd();
+                }
+            }});
+    }
+    
+    
+    private static class QueuedSubmission<T> {
+        final Callable<T> c;
+        final WrappingFuture<T> f;
+        
+        QueuedSubmission(Callable<T> c, WrappingFuture<T> f) {
+            this.c = c;
+            this.f = f;
+        }
+        
+        @Override
+        public String toString() {
+            return "QueuedSubmission["+c+"]@"+Integer.toHexString(System.identityHashCode(this));
+        }
+    }
+    
+    /**
+     * A future, where the task may not yet have been submitted to the real executor.
+     * It delegates to the real future if present, and otherwise waits for that to appear
+     */
+    private static class WrappingFuture<T> implements Future<T> {
+        private volatile Future<T> delegate;
+        private boolean cancelled;
+        
+        void setDelegate(Future<T> delegate) {
+            synchronized (this) {
+                this.delegate = delegate;
+                notifyAll();
+            }
+        }
+        
+        @Override public boolean cancel(boolean mayInterruptIfRunning) {
+            if (delegate != null) {
+                return delegate.cancel(mayInterruptIfRunning);
+            } else {
+                cancelled = true;
+                synchronized (this) {
+                    notifyAll();
+                }
+                return true;
+            }
+        }
+        
+        @Override public boolean isCancelled() {
+            if (delegate != null) {
+                return delegate.isCancelled();
+            } else {
+                return cancelled;
+            }
+        }
+        
+        @Override public boolean isDone() {
+            return (delegate != null) ? delegate.isDone() : cancelled;
+        }
+        
+        @Override public T get() throws CancellationException, ExecutionException, InterruptedException {
+            if (cancelled) {
+                throw new CancellationException();
+            } else if (delegate != null) {
+                return delegate.get();
+            } else {
+                synchronized (this) {
+                    while (delegate == null && !cancelled) {
+                        wait();
+                    }
+                }
+                return get();
+            }
+        }
+        
+        @Override public T get(long timeout, TimeUnit unit) throws CancellationException, ExecutionException, InterruptedException, TimeoutException {
+            long endtime = System.currentTimeMillis()+unit.toMillis(timeout);
+            
+            if (cancelled) {
+                throw new CancellationException();
+            } else if (delegate != null) {
+                return delegate.get(timeout, unit);
+            } else if (System.currentTimeMillis() >= endtime) {
+                throw new TimeoutException();
+            } else {
+                synchronized (this) {
+                    while (delegate == null && !cancelled && System.currentTimeMillis() < endtime) {
+                        long remaining = endtime - System.currentTimeMillis();
+                        if (remaining > 0) {
+                            wait(remaining);
+                        }
+                    }
+                }
+                long remaining = endtime - System.currentTimeMillis();
+                return get(remaining, TimeUnit.MILLISECONDS);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/TaskBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/TaskBuilder.java b/core/src/main/java/org/apache/brooklyn/core/util/task/TaskBuilder.java
new file mode 100644
index 0000000..b105a00
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/TaskBuilder.java
@@ -0,0 +1,184 @@
+/*
+ * 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.util.task;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.api.management.TaskQueueingContext;
+
+import brooklyn.util.JavaGroovyEquivalents;
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
+
+import com.google.common.collect.Iterables;
+
+/** Convenience for creating tasks; note that DynamicSequentialTask is the default */
+public class TaskBuilder<T> {
+
+    String name = null;
+    String description = null;
+    Callable<T> body = null;
+    Boolean swallowChildrenFailures = null;
+    List<TaskAdaptable<?>> children = MutableList.of();
+    Set<Object> tags = MutableSet.of();
+    Map<String,Object> flags = MutableMap.of();
+    Boolean dynamic = null;
+    boolean parallel = false;
+    
+    public static <T> TaskBuilder<T> builder() {
+        return new TaskBuilder<T>();
+    }
+    
+    public TaskBuilder<T> name(String name) {
+        this.name = name;
+        return this;
+    }
+    
+    public TaskBuilder<T> description(String description) {
+        this.description = description;
+        return this;
+    }
+    
+    /** whether task that is built has been explicitly specified to be a dynamic task 
+     * (ie a Task which is also a {@link TaskQueueingContext}
+     * whereby new tasks can be added after creation */
+    public TaskBuilder<T> dynamic(boolean dynamic) {
+        this.dynamic = dynamic;
+        return this;
+    }
+    
+    /** whether task that is built should be parallel; cannot (currently) also be dynamic */
+    public TaskBuilder<T> parallel(boolean parallel) {
+        this.parallel = parallel;
+        return this;
+    }
+    
+    public TaskBuilder<T> body(Callable<T> body) {
+        this.body = body;
+        return this;
+    }
+    
+    /** sets up a dynamic task not to fail even if children fail */
+    public TaskBuilder<T> swallowChildrenFailures(boolean swallowChildrenFailures) {
+        this.swallowChildrenFailures = swallowChildrenFailures;
+        return this;
+    }
+    
+    public TaskBuilder<T> body(Runnable body) {
+        this.body = JavaGroovyEquivalents.<T>toCallable(body);
+        return this;
+    }
+
+    /** adds a child to the given task; the semantics of how the child is executed is set using
+     * {@link #dynamic(boolean)} and {@link #parallel(boolean)} */
+    public TaskBuilder<T> add(TaskAdaptable<?> child) {
+        children.add(child);
+        return this;
+    }
+
+    public TaskBuilder<T> addAll(Iterable<? extends TaskAdaptable<?>> additionalChildren) {
+        Iterables.addAll(children, additionalChildren);
+        return this;
+    }
+
+    public TaskBuilder<T> add(TaskAdaptable<?>... additionalChildren) {
+        children.addAll(Arrays.asList(additionalChildren));
+        return this;
+    }
+
+    /** adds a tag to the given task */
+    public TaskBuilder<T> tag(Object tag) {
+        tags.add(tag);
+        return this;
+    }
+    
+    /** adds a flag to the given task */
+    public TaskBuilder<T> flag(String flag, Object value) {
+        flags.put(flag, value);
+        return this;
+    }
+
+    /** adds the given flags to the given task */
+    public TaskBuilder<T> flags(Map<String,Object> flags) {
+        this.flags.putAll(flags);
+        return this;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public Task<T> build() {
+        MutableMap<String, Object> taskFlags = MutableMap.copyOf(flags);
+        if (name!=null) taskFlags.put("displayName", name);
+        if (description!=null) taskFlags.put("description", description);
+        if (!tags.isEmpty()) taskFlags.put("tags", tags);
+        
+        if (Boolean.FALSE.equals(dynamic) && children.isEmpty()) {
+            if (swallowChildrenFailures!=null)
+                throw new IllegalArgumentException("Cannot set swallowChildrenFailures for non-dynamic task: "+this);
+            return new BasicTask<T>(taskFlags, body);
+        }
+        
+        // prefer dynamic set unless (a) user has said not dynamic, or (b) it's parallel (since there is no dynamic parallel yet)
+        // dynamic has better cancel (will interrupt the thread) and callers can submit tasks flexibly;
+        // however dynamic uses an extra thread and task and is noisy for contexts which don't need it
+        if (Boolean.TRUE.equals(dynamic) || (dynamic==null && !parallel)) {
+            if (parallel)
+                throw new UnsupportedOperationException("No implementation of parallel dynamic aggregate task available");
+            DynamicSequentialTask<T> result = new DynamicSequentialTask<T>(taskFlags, body);
+            if (swallowChildrenFailures!=null && swallowChildrenFailures.booleanValue()) result.swallowChildrenFailures();
+            for (TaskAdaptable t: children)
+                result.queue(t.asTask());
+            return result;
+        }
+        
+        // T must be of type List<V> for these to be valid
+        if (body != null) {
+            throw new UnsupportedOperationException("No implementation of non-dynamic task with both body and children");
+        }
+        if (swallowChildrenFailures!=null) {
+            throw new IllegalArgumentException("Cannot set swallowChildrenFailures for non-dynamic task: "+this);
+        }
+        
+        if (parallel)
+            return new ParallelTask(taskFlags, children);
+        else
+            return new SequentialTask(taskFlags, children);
+    }
+
+    /** returns a a factory based on this builder */
+    public TaskFactory<Task<T>> buildFactory() {
+        return new TaskFactory<Task<T>>() {
+            public Task<T> newTask() {
+                return build();
+            }
+        };
+    }
+    
+    @Override
+    public String toString() {
+        return super.toString()+"["+name+"]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/TaskInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/TaskInternal.java b/core/src/main/java/org/apache/brooklyn/core/util/task/TaskInternal.java
new file mode 100644
index 0000000..b4a6569
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/TaskInternal.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.core.util.task;
+
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import org.apache.brooklyn.api.management.ExecutionManager;
+import org.apache.brooklyn.api.management.Task;
+
+import brooklyn.util.time.Duration;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.ExecutionList;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * All tasks being passed to the {@link ExecutionManager} should implement this.
+ * Users are strongly encouraged to use (or extend) {@link BasicTask}, rather than
+ * implementing a task from scratch.
+ * 
+ * The methods on this interface will change in subsequent releases. Because this is
+ * marked as beta, the normal deprecation policy for these methods does not apply.
+ * 
+ * @author aled
+ */
+@Beta
+public interface TaskInternal<T> extends Task<T> {
+    
+    /** sets the internal future object used to record the association to a job submitted to an {@link ExecutorService} */
+    void initInternalFuture(ListenableFuture<T> result);
+
+    /** returns the underlying future where this task's results will come in; see {@link #initInternalFuture(ListenableFuture)} */
+    Future<T> getInternalFuture();
+    
+    /** if the job is queued for submission (e.g. by another task) it can indicate that fact (and time) here;
+     * note tasks can (and often are) submitted without any queueing, in which case this value may be -1 */
+    long getQueuedTimeUtc();
+    
+    boolean isQueuedOrSubmitted();
+    boolean isQueuedAndNotSubmitted();
+    boolean isQueued();
+
+    /** marks the task as queued for execution */
+    void markQueued();
+
+    boolean cancel();
+    
+    boolean blockUntilStarted(Duration timeout);
+
+    /** allows a task user to specify why a task is blocked; for use immediately before a blocking/wait,
+     * and typically cleared immediately afterwards; referenced by management api to inspect a task
+     * which is blocking
+     * <p>
+     * returns previous details, in case caller wishes to recall and restore it (e.g. if it is doing a sub-blocking)
+     */
+    String setBlockingDetails(String blockingDetails);
+
+    /** as {@link #setBlockingDetails(String)} but records a task which is blocking,
+     * for use e.g. in a gui to navigate to the current active subtask
+     * <p>
+     * returns previous blocking task, in case caller wishes to recall and restore it
+     */
+    Task<?> setBlockingTask(Task<?> blockingTask);
+    
+    void resetBlockingDetails();
+    
+    void resetBlockingTask();
+
+    /** returns a textual message giving details while the task is blocked */
+    String getBlockingDetails();
+    
+    /** returns a task that this task is blocked on */
+    Task<?> getBlockingTask();
+    
+    void setExtraStatusText(Object extraStatus);
+    
+    Object getExtraStatusText();
+
+    void runListeners();
+
+    void setEndTimeUtc(long val);
+
+    void setThread(Thread thread);
+
+    Callable<T> getJob();
+    
+    void setJob(Callable<T> job);
+
+    ExecutionList getListeners();
+
+    void setSubmitTimeUtc(long currentTimeMillis);
+
+    void setSubmittedByTask(Task<?> task);
+    
+    Set<Object> getMutableTags();
+
+    void setStartTimeUtc(long currentTimeMillis);
+
+    void applyTagModifier(Function<Set<Object>,Void> modifier);
+    
+    /** if a task is a proxy for another one (used mainly for internal tasks),
+     * this returns the "real" task represented by this one */
+    Task<?> getProxyTarget();
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/TaskScheduler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/TaskScheduler.java b/core/src/main/java/org/apache/brooklyn/core/util/task/TaskScheduler.java
new file mode 100644
index 0000000..7c5d8a2
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/TaskScheduler.java
@@ -0,0 +1,41 @@
+/*
+ * 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.util.task;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import org.apache.brooklyn.api.management.Task;
+
+/**
+ * The scheduler is an internal mechanism to decorate {@link Task}s.
+ *
+ * It can control how the tasks are scheduled for execution (e.g. single-threaded execution,
+ * prioritised, etc).
+ */
+public interface TaskScheduler {
+    
+    public void injectExecutor(ExecutorService executor);
+
+    /**
+     * Called by {@link BasicExecutionManager} to schedule tasks.
+     */
+    public <T> Future<T> submit(Callable<T> c);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/TaskTags.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/TaskTags.java b/core/src/main/java/org/apache/brooklyn/core/util/task/TaskTags.java
new file mode 100644
index 0000000..e404e87
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/TaskTags.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.core.util.task;
+
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskAdaptable;
+
+import com.google.common.base.Function;
+
+public class TaskTags {
+
+    /** marks a task which is allowed to fail without failing his parent */
+    public static final String INESSENTIAL_TASK = "inessential";
+
+    /** marks a task which is a subtask of another */
+    public static final String SUB_TASK_TAG = "SUB-TASK";
+
+    public static void addTagDynamically(TaskAdaptable<?> task, final Object tag) {
+        ((BasicTask<?>)task.asTask()).applyTagModifier(new Function<Set<Object>, Void>() {
+            public Void apply(@Nullable Set<Object> input) {
+                input.add(tag);
+                return null;
+            }
+        });
+    }
+    
+    public static void addTagsDynamically(TaskAdaptable<?> task, final Object tag1, final Object ...tags) {
+        ((BasicTask<?>)task.asTask()).applyTagModifier(new Function<Set<Object>, Void>() {
+            public Void apply(@Nullable Set<Object> input) {
+                input.add(tag1);
+                for (Object tag: tags) input.add(tag);
+                return null;
+            }
+        });
+    }
+
+    
+    public static boolean isInessential(Task<?> task) {
+        return hasTag(task, INESSENTIAL_TASK);
+    }
+
+    public static boolean hasTag(Task<?> task, Object tag) {
+        return task.getTags().contains(tag);
+    }
+    
+    public static <U,V extends TaskAdaptable<U>> V markInessential(V task) {
+        addTagDynamically(task, INESSENTIAL_TASK);
+        return task;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/Tasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/Tasks.java b/core/src/main/java/org/apache/brooklyn/core/util/task/Tasks.java
new file mode 100644
index 0000000..d391a90
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/Tasks.java
@@ -0,0 +1,488 @@
+/*
+ * 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.util.task;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.api.management.HasTaskChildren;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.api.management.TaskQueueingContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.ReferenceWithError;
+import brooklyn.util.repeat.Repeater;
+import brooklyn.util.time.CountdownTimer;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+
+public class Tasks {
+    
+    private static final Logger log = LoggerFactory.getLogger(Tasks.class);
+    
+    /** convenience for setting "blocking details" on any task where the current thread is running;
+     * typically invoked prior to a wait, for transparency to a user;
+     * then invoked with 'null' just after the wait */
+    public static String setBlockingDetails(String description) {
+        Task<?> current = current();
+        if (current instanceof TaskInternal)
+            return ((TaskInternal<?>)current).setBlockingDetails(description);
+        return null;
+    }
+    public static void resetBlockingDetails() {
+        Task<?> current = current();
+        if (current instanceof TaskInternal)
+            ((TaskInternal<?>)current).resetBlockingDetails(); 
+    }
+    public static Task<?> setBlockingTask(Task<?> blocker) {
+        Task<?> current = current();
+        if (current instanceof TaskInternal)
+            return ((TaskInternal<?>)current).setBlockingTask(blocker);
+        return null;
+    }
+    public static void resetBlockingTask() {
+        Task<?> current = current();
+        if (current instanceof TaskInternal)
+            ((TaskInternal<?>)current).resetBlockingTask(); 
+    }
+    
+    /** convenience for setting "blocking details" on any task where the current thread is running,
+     * while the passed code is executed; often used from groovy as
+     * <pre>{@code withBlockingDetails("sleeping 5s") { Thread.sleep(5000); } }</pre>
+     * If code block is null, the description is set until further notice (not cleareed). */
+    @SuppressWarnings("rawtypes")
+    public static <T> T withBlockingDetails(String description, Callable<T> code) throws Exception {
+        Task current = current();
+        if (code==null) {
+            log.warn("legacy invocation of withBlockingDetails with null code block, ignoring");
+            return null;
+        }
+        String prevBlockingDetails = null;
+        if (current instanceof TaskInternal) {
+            prevBlockingDetails = ((TaskInternal)current).setBlockingDetails(description);
+        } 
+        try {
+            return code.call();
+        } finally {
+            if (current instanceof TaskInternal)
+                ((TaskInternal)current).setBlockingDetails(prevBlockingDetails); 
+        }
+    }
+
+    /** the {@link Task} where the current thread is executing, if executing in a Task, otherwise null;
+     * if the current task is a proxy, this returns the target of that proxy */
+    @SuppressWarnings("rawtypes")
+    public static Task current() { 
+        return getFinalProxyTarget(BasicExecutionManager.getPerThreadCurrentTask().get());
+    }
+
+    public static Task<?> getFinalProxyTarget(Task<?> task) {
+        if (task==null) return null;
+        Task<?> proxy = ((TaskInternal<?>)task).getProxyTarget();
+        if (proxy==null || proxy.equals(task)) return task;
+        return getFinalProxyTarget(proxy);
+    }
+    
+    /** creates a {@link ValueResolver} instance which allows significantly more customization than
+     * the various {@link #resolveValue(Object, Class, ExecutionContext)} methods here */
+    public static <T> ValueResolver<T> resolving(Object v, Class<T> type) {
+        return new ValueResolver<T>(v, type);
+    }
+
+    public static ValueResolver.ResolverBuilderPretype resolving(Object v) {
+        return new ValueResolver.ResolverBuilderPretype(v);
+    }
+
+    /** @see #resolveValue(Object, Class, ExecutionContext, String) */
+    public static <T> T resolveValue(Object v, Class<T> type, @Nullable ExecutionContext exec) throws ExecutionException, InterruptedException {
+        return new ValueResolver<T>(v, type).context(exec).get();
+    }
+    
+    /** attempt to resolve the given value as the given type, waiting on futures, submitting if necessary,
+     * and coercing as allowed by TypeCoercions;
+     * contextMessage (optional) will be displayed in status reports while it waits (e.g. the name of the config key being looked up).
+     * if no execution context supplied (null) this method will throw an exception if the object is an unsubmitted task */
+    public static <T> T resolveValue(Object v, Class<T> type, @Nullable ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException {
+        return new ValueResolver<T>(v, type).context(exec).description(contextMessage).get();
+    }
+    
+    /**
+     * @see #resolveDeepValue(Object, Class, ExecutionContext, String)
+     */
+    public static Object resolveDeepValue(Object v, Class<?> type, ExecutionContext exec) throws ExecutionException, InterruptedException {
+        return resolveDeepValue(v, type, exec, null);
+    }
+
+    /**
+     * Resolves the given object, blocking on futures and coercing it to the given type. If the object is a 
+     * map or iterable (or a list of map of maps, etc, etc) then walks these maps/iterables to convert all of 
+     * their values to the given type. For example, the following will return a list containing a map with "1"="true":
+     * 
+     *   {@code Object result = resolveDeepValue(ImmutableList.of(ImmutableMap.of(1, true)), String.class, exec)} 
+     *
+     * To perform a deep conversion of futures contained within Iterables or Maps without coercion of each element,
+     * the type should normally be Object, not the type of the collection. This differs from
+     * {@link #resolveValue(Object, Class, ExecutionContext, String)} which will accept Map and Iterable
+     * as the required type.
+     */
+    public static <T> T resolveDeepValue(Object v, Class<T> type, ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException {
+        return new ValueResolver<T>(v, type).context(exec).deep(true).description(contextMessage).get();
+    }
+
+    /** sets extra status details on the current task, if possible (otherwise does nothing).
+     * the extra status is presented in Task.getStatusDetails(true)
+     */
+    public static void setExtraStatusDetails(String notes) {
+        Task<?> current = current();
+        if (current instanceof TaskInternal)
+            ((TaskInternal<?>)current).setExtraStatusText(notes); 
+    }
+
+    public static <T> TaskBuilder<T> builder() {
+        return TaskBuilder.<T>builder();
+    }
+    
+    private static Task<?>[] asTasks(TaskAdaptable<?> ...tasks) {
+        Task<?>[] result = new Task<?>[tasks.length];
+        for (int i=0; i<tasks.length; i++)
+            result[i] = tasks[i].asTask();
+        return result;
+    }
+
+    public static Task<List<?>> parallel(TaskAdaptable<?> ...tasks) {
+        return parallelInternal("parallelised tasks", asTasks(tasks));
+    }
+    public static Task<List<?>> parallel(String name, TaskAdaptable<?> ...tasks) {
+        return parallelInternal(name, asTasks(tasks));
+    }
+    public static Task<List<?>> parallel(Iterable<? extends TaskAdaptable<?>> tasks) {
+        return parallel(asTasks(Iterables.toArray(tasks, TaskAdaptable.class)));
+    }
+    public static Task<List<?>> parallel(String name, Iterable<? extends TaskAdaptable<?>> tasks) {
+        return parallelInternal(name, asTasks(Iterables.toArray(tasks, TaskAdaptable.class)));
+    }
+    private static Task<List<?>> parallelInternal(String name, Task<?>[] tasks) {
+        return Tasks.<List<?>>builder().name(name).parallel(true).add(tasks).build();
+    }
+
+    public static Task<List<?>> sequential(TaskAdaptable<?> ...tasks) {
+        return sequentialInternal("sequential tasks", asTasks(tasks));
+    }
+    public static Task<List<?>> sequential(String name, TaskAdaptable<?> ...tasks) {
+        return sequentialInternal(name, asTasks(tasks));
+    }
+    public static TaskFactory<?> sequential(TaskFactory<?> ...taskFactories) {
+        return sequentialInternal("sequential tasks", taskFactories);
+    }
+    public static TaskFactory<?> sequential(String name, TaskFactory<?> ...taskFactories) {
+        return sequentialInternal(name, taskFactories);
+    }
+    public static Task<List<?>> sequential(List<? extends TaskAdaptable<?>> tasks) {
+        return sequential(asTasks(Iterables.toArray(tasks, TaskAdaptable.class)));
+    }
+    public static Task<List<?>> sequential(String name, List<? extends TaskAdaptable<?>> tasks) {
+        return sequential(name, asTasks(Iterables.toArray(tasks, TaskAdaptable.class)));
+    }
+    private static Task<List<?>> sequentialInternal(String name, Task<?>[] tasks) {
+        return Tasks.<List<?>>builder().name(name).parallel(false).add(tasks).build();
+    }
+    private static TaskFactory<?> sequentialInternal(final String name, final TaskFactory<?> ...taskFactories) {
+        return new TaskFactory<TaskAdaptable<?>>() {
+            @Override
+            public TaskAdaptable<?> newTask() {
+                TaskBuilder<List<?>> tb = Tasks.<List<?>>builder().name(name).parallel(false);
+                for (TaskFactory<?> tf: taskFactories)
+                    tb.add(tf.newTask().asTask());
+                return tb.build();
+            }
+        };
+    }
+
+    /** returns the first tag found on the given task which matches the given type, looking up the submission hierarachy if necessary */
+    @SuppressWarnings("unchecked")
+    public static <T> T tag(@Nullable Task<?> task, Class<T> type, boolean recurseHierarchy) {
+        // support null task to make it easier for callers to walk hierarchies
+        if (task==null) return null;
+        for (Object tag: task.getTags())
+            if (type.isInstance(tag)) return (T)tag;
+        if (!recurseHierarchy) return null;
+        return tag(task.getSubmittedByTask(), type, true);
+    }
+    
+    public static boolean isAncestorCancelled(Task<?> t) {
+        if (t==null) return false;
+        if (t.isCancelled()) return true;
+        return isAncestorCancelled(t.getSubmittedByTask());
+    }
+
+    public static boolean isQueued(TaskAdaptable<?> task) {
+        return ((TaskInternal<?>)task.asTask()).isQueued();
+    }
+
+    public static boolean isSubmitted(TaskAdaptable<?> task) {
+        return ((TaskInternal<?>)task.asTask()).isSubmitted();
+    }
+    
+    public static boolean isQueuedOrSubmitted(TaskAdaptable<?> task) {
+        return ((TaskInternal<?>)task.asTask()).isQueuedOrSubmitted();
+    }
+    
+    /**
+     * Adds the given task to the given context. Does not throw an exception if the addition fails.
+     * @return true if the task was added, false otherwise.
+     */
+    public static boolean tryQueueing(TaskQueueingContext adder, TaskAdaptable<?> task) {
+        if (task==null || isQueued(task))
+            return false;
+        try {
+            adder.queue(task.asTask());
+            return true;
+        } catch (Exception e) {
+            if (log.isDebugEnabled())
+                log.debug("Could not add task "+task+" at "+adder+": "+e);
+            return false;
+        }        
+    }
+    
+    /** see also {@link #resolving(Object)} which gives much more control about submission, timeout, etc */
+    public static <T> Supplier<T> supplier(final TaskAdaptable<T> task) {
+        return new Supplier<T>() {
+            @Override
+            public T get() {
+                return task.asTask().getUnchecked();
+            }
+        };
+    }
+    
+    /** return all children tasks of the given tasks, if it has children, else empty list */
+    public static Iterable<Task<?>> children(Task<?> task) {
+        if (task instanceof HasTaskChildren)
+            return ((HasTaskChildren)task).getChildren();
+        return Collections.emptyList();
+    }
+    
+    /** returns failed tasks */
+    public static Iterable<Task<?>> failed(Iterable<Task<?>> subtasks) {
+        return Iterables.filter(subtasks, new Predicate<Task<?>>() {
+            @Override
+            public boolean apply(Task<?> input) {
+                return input.isError();
+            }
+        });
+    }
+    
+    /** returns the task, its children, and all its children, and so on;
+     * @param root task whose descendants should be iterated
+     * @param parentFirst whether to put parents before children or after
+     */
+    public static Iterable<Task<?>> descendants(Task<?> root, final boolean parentFirst) {
+        Iterable<Task<?>> descs = Iterables.concat(Iterables.transform(Tasks.children(root), new Function<Task<?>,Iterable<Task<?>>>() {
+            @Override
+            public Iterable<Task<?>> apply(Task<?> input) {
+                return descendants(input, parentFirst);
+            }
+        }));
+        if (parentFirst) return Iterables.concat(Collections.singleton(root), descs);
+        else return Iterables.concat(descs, Collections.singleton(root));
+    }
+
+    /** returns the error thrown by the task if {@link Task#isError()}, or null if no error or not done */
+    public static Throwable getError(Task<?> t) {
+        if (t==null) return null;
+        if (!t.isDone()) return null;
+        if (t.isCancelled()) return new CancellationException();
+        try {
+            t.get();
+            return null;
+        } catch (Throwable error) {
+            // do not propagate as we are pretty much guaranteed above that it wasn't this
+            // thread which originally threw the error
+            return error;
+        }
+    }
+    public static Task<Void> fail(final String name, final Throwable optionalError) {
+        return Tasks.<Void>builder().dynamic(false).name(name).body(new Runnable() { public void run() { 
+            if (optionalError!=null) throw Exceptions.propagate(optionalError); else throw new RuntimeException("Failed: "+name);
+        } }).build();
+    }
+    public static Task<Void> warning(final String message, final Throwable optionalError) {
+        log.warn(message);
+        return TaskTags.markInessential(fail(message, optionalError));
+    }
+
+    /** marks the current task inessential; this mainly matters if the task is running in a parent
+     * {@link TaskQueueingContext} and we don't want the parent to fail if this task fails
+     * <p>
+     * no-op (silently ignored) if not in a task */
+    public static void markInessential() {
+        Task<?> task = Tasks.current();
+        if (task==null) {
+            TaskQueueingContext qc = DynamicTasks.getTaskQueuingContext();
+            if (qc!=null) task = qc.asTask();
+        }
+        if (task!=null) {
+            TaskTags.markInessential(task);
+        }
+    }
+    
+    /** causes failures in subtasks of the current task not to fail the parent;
+     * no-op if not in a {@link TaskQueueingContext}.
+     * <p>
+     * essentially like a {@link #markInessential()} on all tasks in the current 
+     * {@link TaskQueueingContext}, including tasks queued subsequently */
+    @Beta
+    public static void swallowChildrenFailures() {
+        Preconditions.checkNotNull(DynamicTasks.getTaskQueuingContext(), "Task queueing context required here");
+        TaskQueueingContext qc = DynamicTasks.getTaskQueuingContext();
+        if (qc!=null) {
+            qc.swallowChildrenFailures();
+        }
+    }
+
+    /** as {@link TaskTags#addTagDynamically(TaskAdaptable, Object)} but for current task, skipping if no current task */
+    public static void addTagDynamically(Object tag) {
+        Task<?> t = Tasks.current();
+        if (t!=null) TaskTags.addTagDynamically(t, tag);
+    }
+    
+    /** 
+     * Workaround for limitation described at {@link Task#cancel(boolean)};
+     * internal method used to allow callers to wait for underlying tasks to finished in the case of cancellation.
+     * <p> 
+     * It is irritating that {@link FutureTask} sync's object clears the runner thread, 
+     * so even if {@link BasicTask#getInternalFuture()} is used, there is no means of determining if the underlying object is done.
+     * The {@link Task#getEndTimeUtc()} seems the only way.
+     *  
+     * @return true if tasks ended; false if timed out
+     **/ 
+    @Beta
+    public static boolean blockUntilInternalTasksEnded(Task<?> t, Duration timeout) {
+        CountdownTimer timer = timeout.countdownTimer();
+        
+        if (t==null)
+            return true;
+        
+        if (t instanceof ScheduledTask) {
+            boolean result = ((ScheduledTask)t).blockUntilNextRunFinished(timer.getDurationRemaining());
+            if (!result) return false;
+        }
+
+        t.blockUntilEnded(timer.getDurationRemaining());
+        
+        while (true) {
+            if (t.getEndTimeUtc()>=0) return true;
+            // above should be sufficient; but just in case, trying the below
+            Thread tt = t.getThread();
+            if (t instanceof ScheduledTask) {
+                ((ScheduledTask)t).blockUntilNextRunFinished(timer.getDurationRemaining());
+                return true;
+            } else {
+                if (tt==null || !tt.isAlive()) {
+                    if (!t.isCancelled()) {
+                        // may happen for a cancelled task, interrupted after submit but before start
+                        log.warn("Internal task thread is dead or null ("+tt+") but task not ended: "+t.getEndTimeUtc()+" ("+t+")");
+                    }
+                    return true;
+                }
+            }
+            if (timer.isExpired())
+                return false;
+            Time.sleep(Repeater.DEFAULT_REAL_QUICK_PERIOD);
+        }
+    }
+    
+    /** returns true if either the current thread or the current task is interrupted/cancelled */
+    public static boolean isInterrupted() {
+        if (Thread.currentThread().isInterrupted()) return true;
+        Task<?> t = current();
+        if (t==null) return false;
+        return t.isCancelled();
+    }
+
+    private static class WaitForRepeaterCallable implements Callable<Boolean> {
+        protected Repeater repeater;
+        protected boolean requireTrue;
+
+        public WaitForRepeaterCallable(Repeater repeater, boolean requireTrue) {
+            this.repeater = repeater;
+            this.requireTrue = requireTrue;
+        }
+
+        @Override
+        public Boolean call() {
+            ReferenceWithError<Boolean> result;
+            Tasks.setBlockingDetails(repeater.getDescription());
+            try {
+               result = repeater.runKeepingError();
+            } finally {
+                Tasks.resetBlockingDetails();
+            }
+
+            if (Boolean.TRUE.equals(result.getWithoutError()))
+                return true;
+            if (result.hasError()) 
+                throw Exceptions.propagate(result.getError());
+            if (requireTrue)
+                throw new IllegalStateException("timeout - "+repeater.getDescription());
+            return false;
+        }
+    }
+
+    /** @return a {@link TaskBuilder} which tests whether the repeater terminates with success in its configured timeframe,
+     * returning true or false depending on whether repeater succeed */
+    public static TaskBuilder<Boolean> testing(Repeater repeater) {
+        return Tasks.<Boolean>builder().body(new WaitForRepeaterCallable(repeater, false))
+            .name("waiting for condition")
+            .description("Testing whether " + getTimeoutString(repeater) + ": "+repeater.getDescription());
+    }
+
+    /** @return a {@link TaskBuilder} which requires that the repeater terminate with success in its configured timeframe,
+     * throwing if it does not */
+    public static TaskBuilder<?> requiring(Repeater repeater) {
+        return Tasks.<Boolean>builder().body(new WaitForRepeaterCallable(repeater, true))
+            .name("waiting for condition")
+            .description("Requiring " + getTimeoutString(repeater) + ": " + repeater.getDescription());
+    }
+    
+    private static String getTimeoutString(Repeater repeater) {
+        Duration timeout = repeater.getTimeLimit();
+        if (timeout==null || Duration.PRACTICALLY_FOREVER.equals(timeout))
+            return "eventually";
+        return "in "+timeout;
+    }
+
+}


[20/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/BasicTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/BasicTask.java b/core/src/main/java/org/apache/brooklyn/core/util/task/BasicTask.java
new file mode 100644
index 0000000..c776e4d
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/BasicTask.java
@@ -0,0 +1,892 @@
+/*
+ * 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.util.task;
+
+import static brooklyn.util.JavaGroovyEquivalents.asString;
+import static brooklyn.util.JavaGroovyEquivalents.elvisString;
+import groovy.lang.Closure;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.management.LockInfo;
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.util.Collections;
+import java.util.ConcurrentModificationException;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.brooklyn.api.management.HasTaskChildren;
+import org.apache.brooklyn.api.management.Task;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.GroovyJavaMethods;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.Callables;
+import com.google.common.util.concurrent.ExecutionList;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The basic concrete implementation of a {@link Task} to be executed.
+ *
+ * A {@link Task} is a wrapper for an executable unit, such as a {@link Closure} or a {@link Runnable} or
+ * {@link Callable} and will run in its own {@link Thread}.
+ * <p>
+ * The task can be given an optional displayName and description in its constructor (as named
+ * arguments in the first {@link Map} parameter). It is guaranteed to have {@link Object#notify()} called
+ * once whenever the task starts running and once again when the task is about to complete. Due to
+ * the way executors work it is ugly to guarantee notification <em>after</em> completion, so instead we
+ * notify just before then expect the user to call {@link #get()} - which will throw errors if the underlying job
+ * did so - or {@link #blockUntilEnded()} which will not throw errors.
+ */
+public class BasicTask<T> implements TaskInternal<T> {
+    private static final Logger log = LoggerFactory.getLogger(BasicTask.class);
+
+    private String id = Identifiers.makeRandomId(8);
+    protected Callable<T> job;
+    public final String displayName;
+    public final String description;
+
+    protected final Set<Object> tags = Sets.newConcurrentHashSet();
+    // for debugging, to record where tasks were created
+//    { tags.add(new Throwable("Creation stack trace")); }
+    
+    protected Task<?> proxyTargetTask = null;
+
+    protected String blockingDetails = null;
+    protected Task<?> blockingTask = null;
+    Object extraStatusText = null;
+
+    /** listeners attached at task level; these are stored here, but run on the underlying ListenableFuture */
+    protected final ExecutionList listeners = new ExecutionList();
+    
+    /**
+     * Constructor needed to prevent confusion in groovy stubs when looking for default constructor,
+     *
+     * The generics on {@link Closure} break it if that is first constructor.
+     */
+    protected BasicTask() { this(Collections.emptyMap()); }
+    protected BasicTask(Map<?,?> flags) { this(flags, (Callable<T>) null); }
+
+    public BasicTask(Callable<T> job) { this(Collections.emptyMap(), job); }
+    
+    public BasicTask(Map<?,?> flags, Callable<T> job) {
+        this.job = job;
+
+        if (flags.containsKey("tag")) tags.add(flags.remove("tag"));
+        Object ftags = flags.remove("tags");
+        if (ftags!=null) {
+            if (ftags instanceof Iterable) Iterables.addAll(tags, (Iterable<?>)ftags);
+            else {
+                log.info("deprecated use of non-collection argument for 'tags' ("+ftags+") in "+this, new Throwable("trace of discouraged use of non-colleciton tags argument"));
+                tags.add(ftags);
+            }
+        }
+
+        description = elvisString(flags.remove("description"), "");
+        String d = asString(flags.remove("displayName"));
+        displayName = (d==null ? "" : d);
+    }
+
+    public BasicTask(Runnable job) { this(GroovyJavaMethods.<T>callableFromRunnable(job)); }
+    public BasicTask(Map<?,?> flags, Runnable job) { this(flags, GroovyJavaMethods.<T>callableFromRunnable(job)); }
+    public BasicTask(Closure<T> job) { this(GroovyJavaMethods.callableFromClosure(job)); }
+    public BasicTask(Map<?,?> flags, Closure<T> job) { this(flags, GroovyJavaMethods.callableFromClosure(job)); }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(id);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof Task)
+            return ((Task<?>)obj).getId().equals(getId());
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        // give display name plus id, or job and tags plus id; some jobs have been extended to include nice tostrings 
+        return "Task["+
+            (Strings.isNonEmpty(displayName) ? 
+                displayName : 
+                (job + (tags!=null && !tags.isEmpty() ? ";"+tags : "")) ) +
+            ":"+getId()+"]";
+    }
+
+    @Override
+    public Task<T> asTask() {
+        return this;
+    }
+    
+    // housekeeping --------------------
+
+    /*
+     * These flags are set by BasicExecutionManager.submit.
+     *
+     * Order is guaranteed to be as shown below, in order of #. Within each # line it is currently in the order specified by commas but this is not guaranteed.
+     * (The spaces between the # section indicate longer delays / logical separation ... it should be clear!)
+     *
+     * # submitter, submit time set, tags and other submit-time fields set
+     *
+     * # thread set, ThreadLocal getCurrentTask set
+     * # start time set, isBegun is true
+     * # task end callback run, if supplied
+     *
+     * # task runs
+     *
+     * # task end callback run, if supplied
+     * # end time set
+     * # thread cleared, ThreadLocal getCurrentTask set
+     * # Task.notifyAll()
+     * # Task.get() (result.get()) available, Task.isDone is true
+     *
+     * Few _consumers_ should care, but internally we rely on this so that, for example, status is displayed correctly.
+     * Tests should catch most things, but be careful if you change any of the above semantics.
+     */
+
+    protected long queuedTimeUtc = -1;
+    protected long submitTimeUtc = -1;
+    protected long startTimeUtc = -1;
+    protected long endTimeUtc = -1;
+    protected Maybe<Task<?>> submittedByTask;
+
+    protected volatile Thread thread = null;
+    private volatile boolean cancelled = false;
+    /** normally a {@link ListenableFuture}, except for scheduled tasks when it may be a {@link ScheduledFuture} */
+    protected volatile Future<T> internalFuture = null;
+    
+    @Override
+    public synchronized void initInternalFuture(ListenableFuture<T> result) {
+        if (this.internalFuture != null) 
+            throw new IllegalStateException("task "+this+" is being given a result twice");
+        this.internalFuture = result;
+        notifyAll();
+    }
+
+    // metadata accessors ------------
+
+    @Override
+    public Set<Object> getTags() { return Collections.unmodifiableSet(new LinkedHashSet<Object>(tags)); }
+    
+    /** if the job is queued for submission (e.g. by another task) it can indicate that fact (and time) here;
+     * note tasks can (and often are) submitted without any queueing, in which case this value may be -1 */
+    @Override
+    public long getQueuedTimeUtc() { return queuedTimeUtc; }
+    
+    @Override
+    public long getSubmitTimeUtc() { return submitTimeUtc; }
+    
+    @Override
+    public long getStartTimeUtc() { return startTimeUtc; }
+    
+    @Override
+    public long getEndTimeUtc() { return endTimeUtc; }
+
+    @Override
+    public Future<T> getInternalFuture() { return internalFuture; }
+    
+    @Override
+    public Task<?> getSubmittedByTask() { 
+        if (submittedByTask==null) return null;
+        return submittedByTask.orNull(); 
+    }
+
+    /** the thread where the task is running, if it is running */
+    @Override
+    public Thread getThread() { return thread; }
+
+    // basic fields --------------------
+
+    @Override
+    public boolean isQueued() {
+        return (queuedTimeUtc >= 0);
+    }
+
+    @Override
+    public boolean isQueuedOrSubmitted() {
+        return isQueued() || isSubmitted();
+    }
+
+    @Override
+    public boolean isQueuedAndNotSubmitted() {
+        return isQueued() && (!isSubmitted());
+    }
+
+    @Override
+    public boolean isSubmitted() {
+        return submitTimeUtc >= 0;
+    }
+
+    @Override
+    public boolean isBegun() {
+        return startTimeUtc >= 0;
+    }
+
+    /** marks the task as queued for execution */
+    @Override
+    public void markQueued() {
+        if (queuedTimeUtc<0)
+            queuedTimeUtc = System.currentTimeMillis();
+    }
+
+    @Override
+    public final synchronized boolean cancel() { return cancel(true); }
+
+    /** doesn't resume it, just means if something was cancelled but not submitted it could now be submitted;
+     * probably going to be removed and perhaps some mechanism for running again made available
+     * @since 0.7.0  */
+    @Beta
+    public synchronized boolean uncancel() {
+        boolean wasCancelled = cancelled;
+        cancelled = false; 
+        return wasCancelled;
+    }
+    
+    @Override
+    public synchronized boolean cancel(boolean mayInterruptIfRunning) {
+        if (isDone()) return false;
+        boolean cancel = true;
+        cancelled = true;
+        if (internalFuture!=null) { 
+            cancel = internalFuture.cancel(mayInterruptIfRunning);
+        }
+        notifyAll();
+        return cancel;
+    }
+
+    @Override
+    public boolean isCancelled() {
+        return cancelled || (internalFuture!=null && internalFuture.isCancelled());
+    }
+
+    @Override
+    public boolean isDone() {
+        // if endTime is set, result might not be completed yet, but it will be set very soon 
+        // (the two values are set close in time, result right after the endTime;
+        // but callback hooks might not see the result yet)
+        return cancelled || (internalFuture!=null && internalFuture.isDone()) || endTimeUtc>0;
+    }
+
+    /**
+     * Returns true if the task has had an error.
+     *
+     * Only true if calling {@link #get()} will throw an exception when it completes (including cancel).
+     * Implementations may set this true before completion if they have that insight, or
+     * (the default) they may compute it lazily after completion (returning false before completion).
+     */
+    @Override
+    public boolean isError() {
+        if (!isDone()) return false;
+        if (isCancelled()) return true;
+        try {
+            get();
+            return false;
+        } catch (Throwable t) {
+            return true;
+        }
+    }
+
+    // future value --------------------
+
+    @Override
+    public T get() throws InterruptedException, ExecutionException {
+        try {
+            if (!isDone())
+                Tasks.setBlockingTask(this);
+            blockUntilStarted();
+            return internalFuture.get();
+        } finally {
+            Tasks.resetBlockingTask();
+        }
+    }
+
+    @Override
+    public T getUnchecked() {
+        try {
+            return get();
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    @Override
+    public synchronized void blockUntilStarted() {
+        blockUntilStarted(null);
+    }
+    
+    @Override
+    public synchronized boolean blockUntilStarted(Duration timeout) {
+        Long endTime = timeout==null ? null : System.currentTimeMillis() + timeout.toMillisecondsRoundingUp();
+        while (true) {
+            if (cancelled) throw new CancellationException();
+            if (internalFuture==null)
+                try {
+                    if (timeout==null) {
+                        wait();
+                    } else {
+                        long remaining = endTime - System.currentTimeMillis();
+                        if (remaining>0)
+                            wait(remaining);
+                        else
+                            return false;
+                    }
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    Throwables.propagate(e);
+                }
+            if (internalFuture!=null) return true;
+        }
+    }
+
+    @Override
+    public void blockUntilEnded() {
+        blockUntilEnded(null);
+    }
+    
+    @Override
+    public boolean blockUntilEnded(Duration timeout) {
+        Long endTime = timeout==null ? null : System.currentTimeMillis() + timeout.toMillisecondsRoundingUp();
+        try { 
+            boolean started = blockUntilStarted(timeout);
+            if (!started) return false;
+            if (timeout==null) {
+                internalFuture.get();
+            } else {
+                long remaining = endTime - System.currentTimeMillis();
+                if (remaining>0)
+                    internalFuture.get(remaining, TimeUnit.MILLISECONDS);
+            }
+            return isDone();
+        } catch (Throwable t) {
+            Exceptions.propagateIfFatal(t);
+            if (!(t instanceof TimeoutException) && log.isDebugEnabled())
+                log.debug("call from "+Thread.currentThread()+", blocking until '"+this+"' finishes, ended with error: "+t);
+            return isDone(); 
+        }
+    }
+
+    @Override
+    public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+        return get(new Duration(timeout, unit));
+    }
+    
+    @Override
+    public T get(Duration duration) throws InterruptedException, ExecutionException, TimeoutException {
+        long start = System.currentTimeMillis();
+        Long end  = duration==null ? null : start + duration.toMillisecondsRoundingUp();
+        while (end==null || end > System.currentTimeMillis()) {
+            if (cancelled) throw new CancellationException();
+            if (internalFuture == null) {
+                synchronized (this) {
+                    long remaining = end - System.currentTimeMillis();
+                    if (internalFuture==null && remaining>0)
+                        wait(remaining);
+                }
+            }
+            if (internalFuture != null) break;
+        }
+        Long remaining = end==null ? null : end -  System.currentTimeMillis();
+        if (isDone()) {
+            return internalFuture.get(1, TimeUnit.MILLISECONDS);
+        } else if (remaining == null) {
+            return internalFuture.get();
+        } else if (remaining > 0) {
+            return internalFuture.get(remaining, TimeUnit.MILLISECONDS);
+        } else {
+            throw new TimeoutException();
+        }
+    }
+
+    @Override
+    public T getUnchecked(Duration duration) {
+        try {
+            return get(duration);
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    // ------------------ status ---------------------------
+    
+    /**
+     * Returns a brief status string
+     *
+     * Plain-text format. Reported status if there is one, otherwise state which will be one of:
+     * <ul>
+     * <li>Not submitted
+     * <li>Submitted for execution
+     * <li>Ended by error
+     * <li>Ended by cancellation
+     * <li>Ended normally
+     * <li>Running
+     * <li>Waiting
+     * </ul>
+     */
+    @Override
+    public String getStatusSummary() {
+        return getStatusString(0);
+    }
+
+    /**
+     * Returns detailed status, suitable for a hover
+     *
+     * Plain-text format, with new-lines (and sometimes extra info) if multiline enabled.
+     */
+    @Override
+    public String getStatusDetail(boolean multiline) {
+        return getStatusString(multiline?2:1);
+    }
+
+    /**
+     * This method is useful for callers to see the status of a task.
+     *
+     * Also for developers to see best practices for examining status fields etc
+     *
+     * @param verbosity 0 = brief, 1 = one-line with some detail, 2 = lots of detail
+     */
+    protected String getStatusString(int verbosity) {
+//        Thread t = getThread();
+        String rv;
+        if (submitTimeUtc <= 0) rv = "Not submitted";
+        else if (!isCancelled() && startTimeUtc <= 0) {
+            rv = "Submitted for execution";
+            if (verbosity>0) {
+                long elapsed = System.currentTimeMillis() - submitTimeUtc;
+                rv += " "+Time.makeTimeStringRoundedSince(elapsed)+" ago";
+            }
+            if (verbosity >= 2 && getExtraStatusText()!=null) {
+                rv += "\n\n"+getExtraStatusText();
+            }
+        } else if (isDone()) {
+            long elapsed = endTimeUtc - submitTimeUtc;
+            String duration = Time.makeTimeStringRounded(elapsed);
+            if (isCancelled()) {
+                rv = "Cancelled";
+                if (verbosity >= 1) rv+=" after "+duration;
+                
+                if (verbosity >= 2 && getExtraStatusText()!=null) {
+                    rv += "\n\n"+getExtraStatusText();
+                }
+            } else if (isError()) {
+                rv = "Failed";
+                if (verbosity >= 1) {
+                    rv += " after "+duration;
+                    Throwable error = Tasks.getError(this);
+
+                    if (verbosity >= 2 && getExtraStatusText()!=null) {
+                        rv += "\n\n"+getExtraStatusText();
+                    }
+                    
+                    //remove outer ExecException which is reported by the get(), we want the exception the task threw
+                    while (error instanceof ExecutionException) error = error.getCause();
+                    String errorMessage = Exceptions.collapseText(error);
+
+                    if (verbosity == 1) rv += ": "+abbreviate(errorMessage);
+                    if (verbosity >= 2) {
+                        rv += ": "+errorMessage;
+                        StringWriter sw = new StringWriter();
+                        ((Throwable)error).printStackTrace(new PrintWriter(sw));
+                        rv += "\n\n"+sw.getBuffer();
+                    }
+                }
+            } else {
+                rv = "Completed";
+                if (verbosity>=1) {
+                    if (verbosity==1) {
+                        try {
+                            Object v = get();
+                            rv += ", " +(v==null ? "no return value (null)" : "result: "+abbreviate(v.toString()));
+                        } catch (Exception e) {
+                            rv += ", but error accessing result ["+e+"]"; //shouldn't happen
+                        }
+                    } else {
+                        rv += " after "+duration;
+                        try {
+                            Object v = get();
+                            rv += "\n\n" + (v==null ? "No return value (null)" : "Result: "+v);
+                        } catch (Exception e) {
+                            rv += " at first\n" +
+                                    "Error accessing result ["+e+"]"; //shouldn't happen
+                        }
+                        if (verbosity >= 2 && getExtraStatusText()!=null) {
+                            rv += "\n\n"+getExtraStatusText();
+                        }
+                    }
+                }
+            }
+        } else {
+            rv = getActiveTaskStatusString(verbosity);
+        }
+        return rv;
+    }
+    
+    private static String abbreviate(String s) {
+        s = Strings.getFirstLine(s);
+        if (s.length()>255) s = s.substring(0, 252)+ "...";
+        return s;
+    }
+
+    protected String getActiveTaskStatusString(int verbosity) {
+        String rv = "";
+        Thread t = getThread();
+    
+        // Normally, it's not possible for thread==null as we were started and not ended
+        
+        // However, there is a race where the task starts sand completes between the calls to getThread()
+        // at the start of the method and this call to getThread(), so both return null even though
+        // the intermediate checks returned started==true isDone()==false.
+        if (t == null) {
+            if (isDone()) {
+                return getStatusString(verbosity);
+            } else {
+                //should only happen for repeating task which is not active
+                return "Sleeping";
+            }
+        }
+
+        ThreadInfo ti = ManagementFactory.getThreadMXBean().getThreadInfo(t.getId(), (verbosity<=0 ? 0 : verbosity==1 ? 1 : Integer.MAX_VALUE));
+        if (getThread()==null)
+            //thread might have moved on to a new task; if so, recompute (it should now say "done")
+            return getStatusString(verbosity);
+        
+        if (verbosity >= 1 && Strings.isNonBlank(blockingDetails)) {
+            if (verbosity==1)
+                // short status string will just show blocking details
+                return blockingDetails;
+            //otherwise show the blocking details, then a new line, then additional information
+            rv = blockingDetails + "\n\n";
+        }
+        
+        if (verbosity >= 1 && blockingTask!=null) {
+            if (verbosity==1)
+                // short status string will just show blocking details
+                return "Waiting on "+blockingTask;
+            //otherwise show the blocking details, then a new line, then additional information
+            rv = "Waiting on "+blockingTask + "\n\n";
+        }
+
+        if (verbosity>=2) {
+            if (getExtraStatusText()!=null) {
+                rv += getExtraStatusText()+"\n\n";
+            }
+            
+            rv += ""+toString()+"\n";
+            if (submittedByTask!=null) {
+                rv += "Submitted by "+submittedByTask+"\n";
+            }
+
+            if (this instanceof HasTaskChildren) {
+                // list children tasks for compound tasks
+                try {
+                    Iterable<Task<?>> childrenTasks = ((HasTaskChildren)this).getChildren();
+                    if (childrenTasks.iterator().hasNext()) {
+                        rv += "Children:\n";
+                        for (Task<?> child: childrenTasks) {
+                            rv += "  "+child+": "+child.getStatusDetail(false)+"\n";
+                        }
+                    }
+                } catch (ConcurrentModificationException exc) {
+                    rv += "  (children not available - currently being modified)\n";
+                }
+            }
+            rv += "\n";
+        }
+        
+        LockInfo lock = ti.getLockInfo();
+        rv += "In progress";
+        if (verbosity>=1) {
+            if (lock==null && ti.getThreadState()==Thread.State.RUNNABLE) {
+                //not blocked
+                if (ti.isSuspended()) {
+                    // when does this happen?
+                    rv += ", thread suspended";
+                } else {
+                    if (verbosity >= 2) rv += " ("+ti.getThreadState()+")";
+                }
+            } else {
+                rv +=", thread waiting ";
+                if (ti.getThreadState() == Thread.State.BLOCKED) {
+                    rv += "(mutex) on "+lookup(lock);
+                    //TODO could say who holds it
+                } else if (ti.getThreadState() == Thread.State.WAITING) {
+                    rv += "(notify) on "+lookup(lock);
+                } else if (ti.getThreadState() == Thread.State.TIMED_WAITING) {
+                    rv += "(timed) on "+lookup(lock);
+                } else {
+                    rv = "("+ti.getThreadState()+") on "+lookup(lock);
+                }
+            }
+        }
+        if (verbosity>=2) {
+            StackTraceElement[] st = ti.getStackTrace();
+            st = brooklyn.util.javalang.StackTraceSimplifier.cleanStackTrace(st);
+            if (st!=null && st.length>0)
+                rv += "\n" +"At: "+st[0];
+            for (int ii=1; ii<st.length; ii++) {
+                rv += "\n" +"    "+st[ii];
+            }
+        }
+        return rv;
+    }
+    
+    protected String lookup(LockInfo info) {
+        return info!=null ? ""+info : "unknown (sleep)";
+    }
+
+    @Override
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    
+    /** allows a task user to specify why a task is blocked; for use immediately before a blocking/wait,
+     * and typically cleared immediately afterwards; referenced by management api to inspect a task
+     * which is blocking
+     */
+    @Override
+    public String setBlockingDetails(String blockingDetails) {
+        String old = this.blockingDetails;
+        this.blockingDetails = blockingDetails;
+        return old;
+    }
+    
+    @Override
+    public Task<?> setBlockingTask(Task<?> blockingTask) {
+        Task<?> old = this.blockingTask;
+        this.blockingTask = blockingTask;
+        return old;
+    }
+    
+    @Override
+    public void resetBlockingDetails() {
+        this.blockingDetails = null;
+    }
+    
+    @Override
+    public void resetBlockingTask() {
+        this.blockingTask = null;
+    }
+
+    /** returns a textual message giving details while the task is blocked */
+    @Override
+    public String getBlockingDetails() {
+        return blockingDetails;
+    }
+    
+    /** returns a task that this task is blocked on */
+    @Override
+    public Task<?> getBlockingTask() {
+        return blockingTask;
+    }
+    
+    @Override
+    public void setExtraStatusText(Object extraStatus) {
+        this.extraStatusText = extraStatus;
+    }
+    
+    @Override
+    public Object getExtraStatusText() {
+        return extraStatusText;
+    }
+
+    // ---- add a way to warn if task is not run
+    
+    public interface TaskFinalizer {
+        public void onTaskFinalization(Task<?> t);
+    }
+
+    public static final TaskFinalizer WARN_IF_NOT_RUN = new TaskFinalizer() {
+        @Override
+        public void onTaskFinalization(Task<?> t) {
+            if (!Tasks.isAncestorCancelled(t) && !t.isSubmitted()) {
+                log.warn(t+" was never submitted; did the code create it and forget to run it? ('cancel' the task to suppress this message)");
+                log.debug("Detail of unsubmitted task "+t+":\n"+t.getStatusDetail(true));
+                return;
+            }
+            if (!t.isDone()) {
+                // shouldn't happen
+                // TODO But does happen if management context was terminated (e.g. running test suite).
+                //      Should check if Execution Manager is running, and only log if it was not terminated?
+                log.warn("Task "+t+" is being finalized before completion");
+                return;
+            }
+        }
+    };
+
+    public static final TaskFinalizer NO_OP = new TaskFinalizer() {
+        @Override
+        public void onTaskFinalization(Task<?> t) {
+        }
+    };
+    
+    public void ignoreIfNotRun() {
+        setFinalizer(NO_OP);
+    }
+    
+    public void setFinalizer(TaskFinalizer f) {
+        TaskFinalizer finalizer = Tasks.tag(this, TaskFinalizer.class, false);
+        if (finalizer!=null && finalizer!=f)
+            throw new IllegalStateException("Cannot apply multiple finalizers");
+        if (isDone())
+            throw new IllegalStateException("Finalizer cannot be set on task "+this+" after it is finished");
+        tags.add(f);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        TaskFinalizer finalizer = Tasks.tag(this, TaskFinalizer.class, false);
+        if (finalizer==null) finalizer = WARN_IF_NOT_RUN;
+        finalizer.onTaskFinalization(this);
+    }
+    
+    public static class SubmissionErrorCatchingExecutor implements Executor {
+        final Executor target;
+        public SubmissionErrorCatchingExecutor(Executor target) {
+            this.target = target;
+        }
+        @Override
+        public void execute(Runnable command) {
+            if (isShutdown()) {
+                log.debug("Skipping execution of task callback hook "+command+" because executor is shutdown.");
+                return;
+            }
+            try {
+                target.execute(command);
+            } catch (Exception e) {
+                if (isShutdown()) {
+                    log.debug("Ignoring failed execution of task callback hook "+command+" because executor is shutdown.");
+                } else {
+                    log.warn("Execution of task callback hook "+command+" failed: "+e, e);
+                }
+            }
+        }
+        protected boolean isShutdown() {
+            return target instanceof ExecutorService && ((ExecutorService)target).isShutdown();
+        }
+    }
+    
+    @Override
+    public void addListener(Runnable listener, Executor executor) {
+        listeners.add(listener, new SubmissionErrorCatchingExecutor(executor));
+    }
+    
+    @Override
+    public void runListeners() {
+        listeners.execute();
+    }
+    
+    @Override
+    public void setEndTimeUtc(long val) {
+        endTimeUtc = val;
+    }
+    
+    @Override
+    public void setThread(Thread thread) {
+        this.thread = thread;
+    }
+    
+    @Override
+    public Callable<T> getJob() {
+        return job;
+    }
+    
+    @Override
+    public void setJob(Callable<T> job) {
+        this.job = job;
+    }
+    
+    @Override
+    public ExecutionList getListeners() {
+        return listeners;
+    }
+    
+    @Override
+    public void setSubmitTimeUtc(long val) {
+        submitTimeUtc = val;
+    }
+    
+    private static <T> Task<T> newGoneTaskFor(Task<?> task) {
+        Task<T> t = Tasks.<T>builder().dynamic(false).name(task.getDisplayName())
+            .description("Details of the original task "+task+" have been forgotten.")
+            .body(Callables.returning((T)null)).build();
+        ((BasicTask<T>)t).ignoreIfNotRun();
+        return t;
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    public void setSubmittedByTask(Task<?> task) {
+        submittedByTask = (Maybe)Maybe.softThen((Task)task, (Maybe)Maybe.of(BasicTask.newGoneTaskFor(task)));
+    }
+    
+    @Override
+    public Set<Object> getMutableTags() {
+        return tags;
+    }
+    
+    @Override
+    public void setStartTimeUtc(long val) {
+        startTimeUtc = val;
+    }
+
+    @Override
+    public void applyTagModifier(Function<Set<Object>,Void> modifier) {
+        modifier.apply(tags);
+    }
+
+    @Override
+    public Task<?> getProxyTarget() {
+        return proxyTargetTask;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/CanSetName.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/CanSetName.java b/core/src/main/java/org/apache/brooklyn/core/util/task/CanSetName.java
new file mode 100644
index 0000000..407a93a
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/CanSetName.java
@@ -0,0 +1,25 @@
+/*
+ * 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.util.task;
+
+public interface CanSetName {
+
+    void setName(String name);
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/CompoundTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/CompoundTask.java b/core/src/main/java/org/apache/brooklyn/core/util/task/CompoundTask.java
new file mode 100644
index 0000000..8fdb146
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/CompoundTask.java
@@ -0,0 +1,131 @@
+/*
+ * 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.util.task;
+
+import groovy.lang.Closure;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.brooklyn.api.management.HasTaskChildren;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.BrooklynTaskTags;
+import brooklyn.util.collections.MutableMap;
+
+
+/**
+ * A {@link Task} that is comprised of other units of work: possibly a heterogeneous mix of {@link Task},
+ * {@link Runnable}, {@link Callable} and {@link Closure} instances.
+ * 
+ * This class holds the collection of child tasks, but subclasses have the responsibility of executing them in a
+ * sensible manner by implementing the abstract {@link #runJobs} method.
+ */
+public abstract class CompoundTask<T> extends BasicTask<List<T>> implements HasTaskChildren {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(CompoundTask.class);
+                
+    protected final List<Task<? extends T>> children;
+    protected final List<Object> result;
+    
+    /**
+     * Constructs a new compound task containing the specified units of work.
+     * 
+     * @param jobs  A potentially heterogeneous mixture of {@link Runnable}, {@link Callable}, {@link Closure} and {@link Task} can be provided. 
+     * @throws IllegalArgumentException if any of the passed child jobs is not one of the above types 
+     */
+    public CompoundTask(Object... jobs) {
+        this( Arrays.asList(jobs) );
+    }
+    
+    /**
+     * Constructs a new compound task containing the specified units of work.
+     * 
+     * @param jobs  A potentially heterogeneous mixture of {@link Runnable}, {@link Callable}, {@link Closure} and {@link Task} can be provided. 
+     * @throws IllegalArgumentException if any of the passed child jobs is not one of the above types 
+     */
+    public CompoundTask(Collection<?> jobs) {
+        this(MutableMap.of("tag", "compound"), jobs);
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public CompoundTask(Map<String,?> flags, Collection<?> jobs) {
+        super(flags);
+        super.job = new Callable<List<T>>() {
+            @Override public List<T> call() throws Exception {
+                return runJobs();
+            }
+        };
+        
+        this.result = new ArrayList<Object>(jobs.size());
+        this.children = new ArrayList<Task<? extends T>>(jobs.size());
+        for (Object job : jobs) {
+            Task subtask;
+            if (job instanceof TaskAdaptable) { subtask = ((TaskAdaptable)job).asTask(); }
+            else if (job instanceof Closure)  { subtask = new BasicTask<T>((Closure) job); }
+            else if (job instanceof Callable) { subtask = new BasicTask<T>((Callable) job); }
+            else if (job instanceof Runnable) { subtask = new BasicTask<T>((Runnable) job); }
+            
+            else throw new IllegalArgumentException("Invalid child "+(job == null ? null : job.getClass() + " ("+job+")")+
+                " passed to compound task; must be Runnable, Callable, Closure or Task");
+            
+            BrooklynTaskTags.addTagDynamically(subtask, ManagementContextInternal.SUB_TASK_TAG);
+            children.add(subtask);
+        }
+        
+        for (Task<?> t: getChildren()) {
+            ((TaskInternal<?>)t).markQueued();
+        }
+    }
+
+    /** return value needs to be specified by subclass; subclass should also setBlockingDetails 
+     * @throws ExecutionException 
+     * @throws InterruptedException */    
+    protected abstract List<T> runJobs() throws InterruptedException, ExecutionException;
+    
+    protected void submitIfNecessary(TaskAdaptable<?> task) {
+        if (!task.asTask().isSubmitted()) {
+            if (BasicExecutionContext.getCurrentExecutionContext() == null) {
+                throw new IllegalStateException("Compound task ("+task+") launched from "+this+" missing required execution context");
+            } else {
+                BasicExecutionContext.getCurrentExecutionContext().submit(task);
+            }
+        }
+    }
+    
+    public List<Task<? extends T>> getChildrenTyped() {
+        return children;
+    }
+    
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public List<Task<?>> getChildren() {
+        return (List) getChildrenTyped();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/DeferredSupplier.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/DeferredSupplier.java b/core/src/main/java/org/apache/brooklyn/core/util/task/DeferredSupplier.java
new file mode 100644
index 0000000..ad9416b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/DeferredSupplier.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.util.task;
+
+import com.google.common.base.Supplier;
+
+/**
+ * A class that supplies objects of a single type. When used as a ConfigKey value,
+ * the evaluation is deferred until getConfig() is called. The returned value will then
+ * be coerced to the correct type. 
+ * 
+ * Subsequent calls to getConfig will result in further calls to deferredProvider.get(), 
+ * rather than reusing the result. If you want to reuse the result, consider instead 
+ * using a Future.
+ * 
+ * Note that this functionality replaces the ues of Closure in brooklyn 0.4.0, which 
+ * served the same purpose.
+ */
+public interface DeferredSupplier<T> extends Supplier<T> {
+    @Override
+    T get();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/DynamicSequentialTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/DynamicSequentialTask.java b/core/src/main/java/org/apache/brooklyn/core/util/task/DynamicSequentialTask.java
new file mode 100644
index 0000000..e197705
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/DynamicSequentialTask.java
@@ -0,0 +1,480 @@
+/*
+ * 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.util.task;
+
+import groovy.lang.Closure;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.apache.brooklyn.api.management.HasTaskChildren;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskQueueingContext;
+import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.BrooklynTaskTags;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.time.CountdownTimer;
+import brooklyn.util.time.Duration;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ImmutableList;
+
+/** Represents a task whose run() method can create other tasks
+ * which are run sequentially, but that sequence runs in parallel to this task
+ * <p>
+ * There is an optional primary job run with this task, along with multiple secondary children.
+ * If any secondary task fails (assuming it isn't {@link Tasks#markInessential()} then by default
+ * subsequent tasks are not submitted and the primary task fails (but no tasks are cancelled or interrupted).
+ * You can change the behavior of this task with fields in {@link FailureHandlingConfig},
+ * or the convenience {@link TaskQueueingContext#swallowChildrenFailures()}
+ * (and {@link DynamicTasks#swallowChildrenFailures()} if you are inside the task).
+ * <p>
+ * This synchronizes on secondary tasks when submitting them, in case they may be manually submitted
+ * and the submitter wishes to ensure it is only submitted once.
+ * <p>
+ * Improvements which would be nice to have:
+ * <li> unqueued tasks not visible in api; would like that
+ * <li> uses an extra thread (submitted as background task) to monitor the secondary jobs; would be nice to remove this,
+ *      and rely on {@link BasicExecutionManager} to run the jobs sequentially (combined with fix to item above)
+ * <li> would be nice to have cancel, resume, and possibly skipQueue available as operations (ideally in the REST API and GUI)   
+ **/
+public class DynamicSequentialTask<T> extends BasicTask<T> implements HasTaskChildren, TaskQueueingContext {
+
+    private static final Logger log = LoggerFactory.getLogger(CompoundTask.class);
+                
+    protected final Queue<Task<?>> secondaryJobsAll = new ConcurrentLinkedQueue<Task<?>>();
+    protected final Queue<Task<?>> secondaryJobsRemaining = new ConcurrentLinkedQueue<Task<?>>();
+    protected final Object jobTransitionLock = new Object();
+    protected volatile boolean primaryStarted = false;
+    protected volatile boolean primaryFinished = false;
+    protected volatile boolean secondaryQueueAborted = false;
+    protected Thread primaryThread;
+    protected DstJob dstJob;
+    protected FailureHandlingConfig failureHandlingConfig = FailureHandlingConfig.DEFAULT;
+
+    // default values for how to handle the various failures
+    @Beta
+    public static class FailureHandlingConfig {
+        /** secondary queue runs independently of primary task (submitting and blocking on each secondary task in order), 
+         * but can set it up not to submit any more tasks if the primary fails */
+        public final boolean abortSecondaryQueueOnPrimaryFailure;
+        /** as {@link #abortSecondaryQueueOnPrimaryFailure} but controls cancelling of secondary queue*/
+        public final boolean cancelSecondariesOnPrimaryFailure;
+        /** secondary queue can continue submitting+blocking tasks even if a secondary task fails (unusual;
+         * typically handled by {@link TaskTags#markInessential(Task)} on the secondary tasks, in which case
+         * the secondary queue is never aborted */
+        public final boolean abortSecondaryQueueOnSecondaryFailure;
+        /** unsubmitted secondary tasks (ie those further in the queue) can be cancelled if a secondary task fails */
+        public final boolean cancelSecondariesOnSecondaryFailure;
+        /** whether to issue cancel against primary task if a secondary task fails */
+        public final boolean cancelPrimaryOnSecondaryFailure;
+        /** whether to fail this task if a secondary task fails */
+        public final boolean failParentOnSecondaryFailure;
+        
+        @Beta
+        public FailureHandlingConfig(
+                boolean abortSecondaryQueueOnPrimaryFailure, boolean cancelSecondariesOnPrimaryFailure,
+                boolean abortSecondaryQueueOnSecondaryFailure, boolean cancelSecondariesOnSecondaryFailure,
+                boolean cancelPrimaryOnSecondaryFailure, boolean failParentOnSecondaryFailure) {
+            this.abortSecondaryQueueOnPrimaryFailure = abortSecondaryQueueOnPrimaryFailure;
+            this.cancelSecondariesOnPrimaryFailure = cancelSecondariesOnPrimaryFailure;
+            this.abortSecondaryQueueOnSecondaryFailure = abortSecondaryQueueOnSecondaryFailure;
+            this.cancelSecondariesOnSecondaryFailure = cancelSecondariesOnSecondaryFailure;
+            this.cancelPrimaryOnSecondaryFailure = cancelPrimaryOnSecondaryFailure;
+            this.failParentOnSecondaryFailure = failParentOnSecondaryFailure;
+        }
+        
+        public static final FailureHandlingConfig DEFAULT = new FailureHandlingConfig(false, false, true, false, false, true);
+        public static final FailureHandlingConfig SWALLOWING_CHILDREN_FAILURES = new FailureHandlingConfig(false, false, false, false, false, false);
+    }
+    
+    public static class QueueAbortedException extends IllegalStateException {
+        private static final long serialVersionUID = -7569362887826818524L;
+        
+        public QueueAbortedException(String msg) {
+            super(msg);
+        }
+        public QueueAbortedException(String msg, Throwable cause) {
+            super(msg, cause);
+        }
+    }
+
+    /**
+     * Constructs a new compound task containing the specified units of work.
+     * 
+     * @param jobs  A potentially heterogeneous mixture of {@link Runnable}, {@link Callable}, {@link Closure} and {@link Task} can be provided. 
+     * @throws IllegalArgumentException if any of the passed child jobs is not one of the above types 
+     */
+    public DynamicSequentialTask() {
+        this(null);
+    }
+    
+    public DynamicSequentialTask(Callable<T> mainJob) {
+        this(MutableMap.of("tag", "compound"), mainJob);
+    }
+    
+    public DynamicSequentialTask(Map<?,?> flags, Callable<T> mainJob) {
+        super(flags);
+        this.job = dstJob = new DstJob(mainJob);
+    }
+    
+    @Override
+    public void queue(Task<?> t) {
+        synchronized (jobTransitionLock) {
+            if (primaryFinished)
+                throw new IllegalStateException("Cannot add a task to "+this+" which is already finished (trying to add "+t+")");
+            if (secondaryQueueAborted)
+                throw new QueueAbortedException("Cannot add a task to "+this+" whose queue has been aborted (trying to add "+t+")");
+            secondaryJobsAll.add(t);
+            secondaryJobsRemaining.add(t);
+            BrooklynTaskTags.addTagsDynamically(t, ManagementContextInternal.SUB_TASK_TAG);
+            ((TaskInternal<?>)t).markQueued();
+            jobTransitionLock.notifyAll();
+        }
+    }
+
+    @Override
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        return cancel(mayInterruptIfRunning, mayInterruptIfRunning, true);
+    }
+    public boolean cancel(boolean mayInterruptTask, boolean interruptPrimaryThread, boolean alsoCancelChildren) {
+        if (isDone()) return false;
+        if (log.isTraceEnabled()) log.trace("cancelling {}", this);
+        boolean cancel = super.cancel(mayInterruptTask);
+        if (alsoCancelChildren) {
+            for (Task<?> t: secondaryJobsAll)
+                cancel |= t.cancel(mayInterruptTask);
+        }
+        synchronized (jobTransitionLock) {
+            if (primaryThread!=null) {
+                if (interruptPrimaryThread) {
+                    if (log.isTraceEnabled()) log.trace("cancelling {} - interrupting", this);
+                    primaryThread.interrupt();
+                }
+                cancel = true;
+            }
+        }
+        return cancel;
+    }
+    
+    @Override
+    public synchronized boolean uncancel() {
+        secondaryQueueAborted = false;
+        return super.uncancel();
+    }
+
+    @Override
+    public Iterable<Task<?>> getChildren() {
+        return Collections.unmodifiableCollection(secondaryJobsAll);
+    }
+    
+    /** submits the indicated task for execution in the current execution context, and returns immediately */
+    protected void submitBackgroundInheritingContext(Task<?> task) {
+        BasicExecutionContext ec = BasicExecutionContext.getCurrentExecutionContext();
+        if (log.isTraceEnabled()) {
+            log.trace("task {} - submitting background task {} ({})", new Object[] { Tasks.current(), task, ec });
+        }
+        if (ec==null) {
+            String message = Tasks.current()!=null ?
+                    // user forgot ExecContext:
+                        "Task "+this+" submitting background task requires an ExecutionContext (an ExecutionManager is not enough): submitting "+task+" in "+Tasks.current()
+                    : // should not happen:
+                        "Cannot submit tasks inside DST when not in a task : submitting "+task+" in "+this;
+            log.warn(message+" (rethrowing)");
+            throw new IllegalStateException(message);
+        }
+        synchronized (task) {
+            if (task.isSubmitted()) {
+                if (log.isTraceEnabled()) {
+                    log.trace("DST "+this+" skipping submission of child "+task+" because it is already submitted");
+                }
+            } else {
+                try {
+                    ec.submit(task);
+                } catch (Exception e) {
+                    Exceptions.propagateIfFatal(e);
+                    // Give some context when the submit fails (happens when the target is already unmanaged)
+                    throw new IllegalStateException("Failure submitting task "+task+" in "+this+": "+e.getMessage(), e);
+                }
+            }
+        }
+    }
+
+    public void setFailureHandlingConfig(FailureHandlingConfig failureHandlingConfig) {
+        this.failureHandlingConfig = failureHandlingConfig;
+    }
+    @Override
+    public void swallowChildrenFailures() {
+        setFailureHandlingConfig(FailureHandlingConfig.SWALLOWING_CHILDREN_FAILURES);
+    }
+    
+    protected class DstJob implements Callable<T> {
+        protected Callable<T> primaryJob;
+        /** currently executing (or just completed) secondary task, or null if none;
+         * with jobTransitionLock notified on change and completion */
+        protected volatile Task<?> currentSecondary = null;
+        protected volatile boolean finishedSecondaries = false;
+        
+        public DstJob(Callable<T> mainJob) {
+            this.primaryJob = mainJob;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public T call() throws Exception {
+
+            synchronized (jobTransitionLock) {
+                primaryStarted = true;
+                primaryThread = Thread.currentThread();
+                for (Task<?> t: secondaryJobsAll)
+                    ((TaskInternal<?>)t).markQueued();
+            }
+            // TODO overkill having a thread/task for this, but it works
+            // optimisation would either use newTaskEndCallback property on task to submit
+            // or use some kind of single threaded executor for the queued tasks
+            Task<List<Object>> secondaryJobMaster = Tasks.<List<Object>>builder().dynamic(false)
+                    .name("DST manager (internal)")
+                    // TODO marking it transient helps it be GC'd sooner, 
+                    // but ideally we wouldn't have this,
+                    // or else it would be a child
+                    .tag(BrooklynTaskTags.TRANSIENT_TASK_TAG)
+                    .body(new Callable<List<Object>>() {
+
+                @Override
+                public List<Object> call() throws Exception {
+                    List<Object> result = new ArrayList<Object>();
+                    try { 
+                        while (!secondaryQueueAborted && (!primaryFinished || !secondaryJobsRemaining.isEmpty())) {
+                            synchronized (jobTransitionLock) {
+                                if (!primaryFinished && secondaryJobsRemaining.isEmpty()) {
+                                    currentSecondary = null;
+                                    jobTransitionLock.wait(1000);
+                                }
+                            }
+                            @SuppressWarnings("rawtypes")
+                            Task secondaryJob = secondaryJobsRemaining.poll();
+                            if (secondaryJob != null) {
+                                synchronized (jobTransitionLock) {
+                                    currentSecondary = secondaryJob;
+                                    submitBackgroundInheritingContext(secondaryJob);
+                                    jobTransitionLock.notifyAll();
+                                }
+                                try {
+                                    result.add(secondaryJob.get());
+                                } catch (Exception e) {
+                                    if (TaskTags.isInessential(secondaryJob)) {
+                                        result.add(Tasks.getError(secondaryJob));
+                                        if (log.isDebugEnabled())
+                                            log.debug("Secondary job queue for "+DynamicSequentialTask.this+" ignoring error in inessential task "+secondaryJob+": "+e);
+                                    } else {
+                                        if (failureHandlingConfig.cancelSecondariesOnSecondaryFailure) {
+                                            if (log.isDebugEnabled())
+                                                log.debug("Secondary job queue for "+DynamicSequentialTask.this+" cancelling "+secondaryJobsRemaining.size()+" remaining, due to error in task "+secondaryJob+": "+e);
+                                            synchronized (jobTransitionLock) {
+                                                for (Task<?> t: secondaryJobsRemaining)
+                                                    t.cancel(true);
+                                                jobTransitionLock.notifyAll();
+                                            }
+                                        }
+                                        
+                                        if (failureHandlingConfig.abortSecondaryQueueOnSecondaryFailure) {
+                                            if (log.isDebugEnabled())
+                                                log.debug("Aborting secondary job queue for "+DynamicSequentialTask.this+" due to error in child task "+secondaryJob+" ("+e+", being rethrown)");
+                                            secondaryQueueAborted = true;
+                                            throw e;
+                                        }
+
+                                        if (!primaryFinished && failureHandlingConfig.cancelPrimaryOnSecondaryFailure) {
+                                            cancel(true, false, false);
+                                        }
+                                        
+                                        result.add(Tasks.getError(secondaryJob));
+                                        if (log.isDebugEnabled())
+                                            log.debug("Secondary job queue for "+DynamicSequentialTask.this+" continuing in presence of error in child task "+secondaryJob+" ("+e+", being remembered)");
+                                    }
+                                }
+                            }
+                        }
+                    } finally {
+                        synchronized (jobTransitionLock) {
+                            currentSecondary = null;
+                            finishedSecondaries = true;
+                            jobTransitionLock.notifyAll();
+                        }
+                    }
+                    return result;
+                }
+            }).build();
+            ((BasicTask<?>)secondaryJobMaster).proxyTargetTask = DynamicSequentialTask.this;
+            
+            submitBackgroundInheritingContext(secondaryJobMaster);
+            
+            T result = null;
+            Throwable error = null;
+            Throwable uninterestingSelfError = null;
+            boolean errorIsFromChild = false;
+            try {
+                if (log.isTraceEnabled()) log.trace("calling primary job for {}", this);
+                if (primaryJob!=null) result = primaryJob.call();
+            } catch (Throwable selfException) {
+                Exceptions.propagateIfFatal(selfException);
+                if (Exceptions.getFirstThrowableOfType(selfException, QueueAbortedException.class) != null) {
+                    // Error was caused by the task already having failed, and this thread calling queue() to try
+                    // to queue more work. The underlying cause will be much more interesting.
+                    // Without this special catch, we record error = "Cannot add a task to ... whose queue has been aborted",
+                    // which gets propagated instead of the more interesting child exception.
+                    uninterestingSelfError = selfException;
+                } else {
+                    error = selfException;
+                    errorIsFromChild = false;
+                }
+                if (failureHandlingConfig.abortSecondaryQueueOnPrimaryFailure) {
+                    if (log.isDebugEnabled())
+                        log.debug("Secondary job queue for "+DynamicSequentialTask.this+" aborting with "+secondaryJobsRemaining.size()+" remaining, due to error in primary task: "+selfException);
+                    secondaryQueueAborted = true;
+                }
+                if (failureHandlingConfig.cancelSecondariesOnPrimaryFailure) {
+                    if (log.isDebugEnabled())
+                        log.debug(DynamicSequentialTask.this+" cancelling "+secondaryJobsRemaining.size()+" remaining, due to error in primary task: "+selfException);
+                    synchronized (jobTransitionLock) {
+                        for (Task<?> t: secondaryJobsRemaining)
+                            t.cancel(true);
+                        // do this early to prevent additions; and note we notify very soon below, so not notify is help off until below
+                        primaryThread = null;
+                        primaryFinished = true;
+                    }
+                }
+            } finally {
+                try {
+                    if (log.isTraceEnabled()) log.trace("cleaning up for {}", this);
+                    synchronized (jobTransitionLock) {
+                        // semaphore might be nicer here (aled notes as it is this is a little hard to read)
+                        primaryThread = null;
+                        primaryFinished = true;
+                        jobTransitionLock.notifyAll();
+                    }
+                    if (!isCancelled() && !Thread.currentThread().isInterrupted()) {
+                        if (log.isTraceEnabled()) log.trace("waiting for secondaries for {}", this);
+                        // wait on tasks sequentially so that blocking information is more interesting
+                        DynamicTasks.waitForLast();
+                        List<Object> result2 = secondaryJobMaster.get();
+                        try {
+                            if (primaryJob==null) result = (T)result2;
+                        } catch (ClassCastException e) { /* ignore class cast exception; leave the result as null */ }
+                    }
+                } catch (Throwable childException) {
+                    Exceptions.propagateIfFatal(childException);
+                    if (error==null) {
+                        error = childException;
+                        errorIsFromChild = true;
+                    } else {
+                        if (log.isDebugEnabled()) log.debug("Parent task "+this+" ignoring child error ("+childException+") in presence of our own error ("+error+")");
+                    }
+                }
+            }
+            if (error!=null) {
+                handleException(error, errorIsFromChild);
+            }
+            if (uninterestingSelfError != null) {
+                handleException(uninterestingSelfError, false);
+            }
+            return result;
+        }
+        
+        @Override
+        public String toString() {
+            return "DstJob:"+DynamicSequentialTask.this.getId();
+        }
+
+        /** waits for this job to complete, or the given time to elapse */
+        public void join(boolean includePrimary, Duration optionalTimeout) throws InterruptedException {
+            CountdownTimer timeLeft = optionalTimeout!=null ? CountdownTimer.newInstanceStarted(optionalTimeout) : null;
+            while (true) {
+                Task<?> cs;
+                Duration remaining;
+                synchronized (jobTransitionLock) {
+                    cs = currentSecondary;
+                    if (finishedSecondaries) return;
+                    remaining = timeLeft==null ? Duration.ONE_SECOND : timeLeft.getDurationRemaining();
+                    if (!remaining.isPositive()) return;
+                    if (cs==null) {
+                        if (!includePrimary && secondaryJobsRemaining.isEmpty()) return;
+                        // parent still running, no children though
+                        Tasks.setBlockingTask(DynamicSequentialTask.this);
+                        jobTransitionLock.wait(remaining.toMilliseconds());
+                        Tasks.resetBlockingDetails();
+                    }
+                }
+                if (cs!=null) {
+                    Tasks.setBlockingTask(cs);
+                    cs.blockUntilEnded(remaining);
+                    Tasks.resetBlockingDetails();
+                }
+            }
+        }
+    }
+
+    @Override
+    public List<Task<?>> getQueue() {
+        return ImmutableList.copyOf(secondaryJobsAll);
+    }
+
+    public void handleException(Throwable throwable, boolean fromChild) throws Exception {
+        Exceptions.propagateIfFatal(throwable);
+        if (fromChild && !failureHandlingConfig.failParentOnSecondaryFailure) {
+            log.debug("Parent task "+this+" swallowing child error: "+throwable);
+            return;
+        }
+        handleException(throwable);
+    }
+    public void handleException(Throwable throwable) throws Exception { 
+        Exceptions.propagateIfFatal(throwable);
+        if (throwable instanceof Exception) {
+            // allow checked exceptions to be passed through
+            throw (Exception)throwable;
+        }
+        throw Exceptions.propagate(throwable);
+    }
+
+    @Override
+    public void drain(Duration optionalTimeout, boolean includePrimary, boolean throwFirstError) {
+        try {
+            dstJob.join(includePrimary, optionalTimeout);
+        } catch (InterruptedException e) {
+            throw Exceptions.propagate(e);
+        }
+        if (throwFirstError) {
+            if (isError()) 
+                getUnchecked();
+            for (Task<?> t: getQueue())
+                if (t.isError() && !TaskTags.isInessential(t))
+                    t.getUnchecked();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/DynamicTasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/DynamicTasks.java b/core/src/main/java/org/apache/brooklyn/core/util/task/DynamicTasks.java
new file mode 100644
index 0000000..ed46558
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/DynamicTasks.java
@@ -0,0 +1,337 @@
+/*
+ * 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.util.task;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.api.management.TaskQueueingContext;
+import org.apache.brooklyn.api.management.TaskWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.time.Duration;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+/** 
+ * Contains static methods which detect and use the current {@link TaskQueueingContext} to execute tasks.
+ * 
+ * @since 0.6.0
+ */
+@Beta
+public class DynamicTasks {
+
+    private static final Logger log = LoggerFactory.getLogger(DynamicTasks.class);
+    private static final ThreadLocal<TaskQueueingContext> taskQueueingContext = new ThreadLocal<TaskQueueingContext>();
+    
+    public static void setTaskQueueingContext(TaskQueueingContext newTaskQC) {
+        taskQueueingContext.set(newTaskQC);
+    }
+    
+    public static TaskQueueingContext getThreadTaskQueuingContext() {
+        return taskQueueingContext.get();
+    }
+    
+    public static TaskQueueingContext getTaskQueuingContext() {
+        TaskQueueingContext adder = getThreadTaskQueuingContext();
+        if (adder!=null) return adder;
+        Task<?> t = Tasks.current();
+        if (t instanceof TaskQueueingContext) return (TaskQueueingContext) t;
+        return null;
+    }
+
+    
+    public static void removeTaskQueueingContext() {
+        taskQueueingContext.remove();
+    }
+
+    public static class TaskQueueingResult<T> implements TaskWrapper<T> {
+        private final Task<T> task;
+        private final boolean wasQueued;
+        private ExecutionContext execContext = null;
+        
+        private TaskQueueingResult(TaskAdaptable<T> task, boolean wasQueued) {
+            this.task = task.asTask();
+            this.wasQueued = wasQueued;
+        }
+        @Override
+        public Task<T> asTask() {
+            return task;
+        }
+        @Override
+        public Task<T> getTask() {
+            return task;
+        }
+        /** returns true if the task was queued */
+        public boolean wasQueued() {
+            return wasQueued;
+        }
+        /** returns true if the task either is currently queued or has been submitted */
+        public boolean isQueuedOrSubmitted() {
+            return wasQueued || Tasks.isQueuedOrSubmitted(task);
+        }
+        /** specifies an execContext to use if the task has to be explicitly submitted;
+         * if omitted it will attempt to find one based on the current thread's context */
+        public TaskQueueingResult<T> executionContext(ExecutionContext execContext) {
+            this.execContext = execContext;
+            return this;
+        }
+        /** as {@link #executionContext(ExecutionContext)} but inferring from the entity */
+        public TaskQueueingResult<T> executionContext(Entity entity) {
+            this.execContext = ((EntityInternal)entity).getManagementSupport().getExecutionContext();
+            return this;
+        }
+        private boolean orSubmitInternal() {
+            if (!wasQueued()) {
+                if (isQueuedOrSubmitted()) {
+                    log.warn("Redundant call to execute "+getTask()+"; skipping");
+                    return false;
+                } else {
+                    ExecutionContext ec = execContext;
+                    if (ec==null)
+                        ec = BasicExecutionContext.getCurrentExecutionContext();
+                    if (ec==null)
+                        throw new IllegalStateException("Cannot execute "+getTask()+" without an execution context; ensure caller is in an ExecutionContext");
+                    ec.submit(getTask());
+                    return true;
+                }
+            } else {
+                return false;
+            }
+        }
+        /** causes the task to be submitted (asynchronously) if it hasn't already been,
+         * requiring an entity execution context (will try to find a default if not set) */
+        public TaskQueueingResult<T> orSubmitAsync() {
+            orSubmitInternal();
+            return this;
+        }
+        /** convenience for setting {@link #executionContext(ExecutionContext)} then submitting async */
+        public TaskQueueingResult<T> orSubmitAsync(Entity entity) {
+            executionContext(entity);
+            return orSubmitAsync();
+        }
+        /** causes the task to be submitted *synchronously* if it hasn't already been submitted;
+         * useful in contexts such as libraries where callers may be either on a legacy call path 
+         * (which assumes all commands complete immediately);
+         * requiring an entity execution context (will try to find a default if not set) */
+        public TaskQueueingResult<T> orSubmitAndBlock() {
+            if (orSubmitInternal()) task.getUnchecked();
+            return this;
+        }
+        /** convenience for setting {@link #executionContext(ExecutionContext)} then submitting blocking */
+        public TaskQueueingResult<T> orSubmitAndBlock(Entity entity) {
+            executionContext(entity);
+            return orSubmitAndBlock();
+        }
+        /** blocks for the task to be completed
+         * <p>
+         * needed in any context where subsequent commands assume the task has completed.
+         * not needed in a context where the task is simply being built up and queued.
+         * <p>
+         * throws if there are any errors
+         */
+        public T andWaitForSuccess() {
+            return task.getUnchecked();
+        }
+        public void orCancel() {
+            if (!wasQueued()) {
+                task.cancel(false);
+            }
+        }
+    }
+    
+    /**
+     * Tries to add the task to the current addition context if there is one, otherwise does nothing.
+     * <p/>
+     * Call {@link TaskQueueingResult#orSubmitAsync() orSubmitAsync()} on the returned
+     * {@link TaskQueueingResult TaskQueueingResult} to handle execution of tasks in a
+     * {@link BasicExecutionContext}.
+     */
+    public static <T> TaskQueueingResult<T> queueIfPossible(TaskAdaptable<T> task) {
+        TaskQueueingContext adder = getTaskQueuingContext();
+        boolean result = false;
+        if (adder!=null)
+            result = Tasks.tryQueueing(adder, task);
+        return new TaskQueueingResult<T>(task, result);
+    }
+
+    /** @see #queueIfPossible(TaskAdaptable) */
+    public static <T> TaskQueueingResult<T> queueIfPossible(TaskFactory<? extends TaskAdaptable<T>> task) {
+        return queueIfPossible(task.newTask());
+    }
+
+    /** adds the given task to the nearest task addition context,
+     * either set as a thread-local, or in the current task, or the submitter of the task, etc
+     * <p>
+     * throws if it cannot add */
+    public static <T> Task<T> queueInTaskHierarchy(Task<T> task) {
+        Preconditions.checkNotNull(task, "Task to queue cannot be null");
+        Preconditions.checkState(!Tasks.isQueuedOrSubmitted(task), "Task to queue must not yet be submitted: {}", task);
+        
+        TaskQueueingContext adder = getTaskQueuingContext();
+        if (adder!=null) { 
+            if (Tasks.tryQueueing(adder, task)) {
+                log.debug("Queued task {} at context {} (no hierarchy)", task, adder);
+                return task;
+            }
+        }
+        
+        Task<?> t = Tasks.current();
+        Preconditions.checkState(t!=null || adder!=null, "No task addition context available for queueing task "+task);
+        
+        while (t!=null) {
+            if (t instanceof TaskQueueingContext) {
+                if (Tasks.tryQueueing((TaskQueueingContext)t, task)) {
+                    log.debug("Queued task {} at hierarchical context {}", task, t);
+                    return task;
+                }
+            }
+            t = t.getSubmittedByTask();
+        }
+        
+        throw new IllegalStateException("No task addition context available in current task hierarchy for adding task "+task);
+    }
+
+    /**
+     * Queues the given task.
+     * <p/>
+     * This method is only valid within a dynamic task. Use {@link #queueIfPossible(TaskAdaptable)}
+     * and {@link TaskQueueingResult#orSubmitAsync()} if the calling context is a basic task.
+     *
+     * @param task The task to queue
+     * @throws IllegalStateException if no task queueing context is available
+     * @return The queued task
+     */
+    public static <V extends TaskAdaptable<?>> V queue(V task) {
+        try {
+            Preconditions.checkNotNull(task, "Task to queue cannot be null");
+            Preconditions.checkState(!Tasks.isQueued(task), "Task to queue must not yet be queued: %s", task);
+            TaskQueueingContext adder = getTaskQueuingContext();
+            if (adder==null) {
+                throw new IllegalStateException("Task "+task+" cannot be queued here; no queueing context available");
+            }
+            adder.queue(task.asTask());
+            return task;
+        } catch (Throwable e) {
+            log.warn("Error queueing "+task+" (rethrowing): "+e);
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    /** @see #queue(org.apache.brooklyn.api.management.TaskAdaptable)  */
+    public static void queue(TaskAdaptable<?> task1, TaskAdaptable<?> task2, TaskAdaptable<?> ...tasks) {
+        queue(task1);
+        queue(task2);
+        for (TaskAdaptable<?> task: tasks) queue(task);
+    }
+
+    /** @see #queue(org.apache.brooklyn.api.management.TaskAdaptable)  */
+    public static <T extends TaskAdaptable<?>> T queue(TaskFactory<T> taskFactory) {
+        return queue(taskFactory.newTask());
+    }
+
+    /** @see #queue(org.apache.brooklyn.api.management.TaskAdaptable)  */
+    public static void queue(TaskFactory<?> task1, TaskFactory<?> task2, TaskFactory<?> ...tasks) {
+        queue(task1.newTask());
+        queue(task2.newTask());
+        for (TaskFactory<?> task: tasks) queue(task.newTask());
+    }
+
+    /** @see #queue(org.apache.brooklyn.api.management.TaskAdaptable)  */
+    public static <T> Task<T> queue(String name, Callable<T> job) {
+        return DynamicTasks.queue(Tasks.<T>builder().name(name).body(job).build());
+    }
+
+    /** @see #queue(org.apache.brooklyn.api.management.TaskAdaptable)  */
+    public static <T> Task<T> queue(String name, Runnable job) {
+        return DynamicTasks.queue(Tasks.<T>builder().name(name).body(job).build());
+    }
+
+    /** queues the task if needed, i.e. if it is not yet submitted (so it will run), 
+     * or if it is submitted but not queued and we are in a queueing context (so it is available for informational purposes) */
+    public static <T extends TaskAdaptable<?>> T queueIfNeeded(T task) {
+        if (!Tasks.isQueued(task)) {
+            if (Tasks.isSubmitted(task) && getTaskQueuingContext()==null) {
+                // already submitted and not in a queueing context, don't try to queue
+            } else {
+                // needs submitting, put it in the queue
+                // (will throw an error if we are not a queueing context)
+                queue(task);
+            }
+        }
+        return task;
+    }
+    
+    /** submits/queues the given task if needed, and gets the result (unchecked) 
+     * only permitted in a queueing context (ie a DST main job) if the task is not yet submitted */
+    // things get really confusing if you try to queueInTaskHierarchy -- easy to cause deadlocks!
+    public static <T> T get(TaskAdaptable<T> t) {
+        return queueIfNeeded(t).asTask().getUnchecked();
+    }
+
+    /** As {@link #drain(Duration, boolean)} waiting forever and throwing the first error 
+     * (excluding errors in inessential tasks),
+     * then returning the last task in the queue (which is guaranteed to have finished without error,
+     * if this method returns without throwing) */
+    public static Task<?> waitForLast() {
+        drain(null, true);
+        // this call to last is safe, as the above guarantees everything will have run
+        // (on errors the above will throw so we won't come here)
+        List<Task<?>> q = DynamicTasks.getTaskQueuingContext().getQueue();
+        return q.isEmpty() ? null : Iterables.getLast(q);
+    }
+    
+    /** Calls {@link TaskQueueingContext#drain(Duration, boolean, boolean)} on the current task context */
+    public static TaskQueueingContext drain(Duration optionalTimeout, boolean throwFirstError) {
+        TaskQueueingContext qc = DynamicTasks.getTaskQueuingContext();
+        Preconditions.checkNotNull(qc, "Cannot drain when there is no queueing context");
+        qc.drain(optionalTimeout, false, throwFirstError);
+        return qc;
+    }
+
+    /** as {@link Tasks#swallowChildrenFailures()} but requiring a {@link TaskQueueingContext}. */
+    @Beta
+    public static void swallowChildrenFailures() {
+        Preconditions.checkNotNull(DynamicTasks.getTaskQueuingContext(), "Task queueing context required here");
+        Tasks.swallowChildrenFailures();
+    }
+
+    /** same as {@link Tasks#markInessential()}
+     * (but included here for convenience as it is often used in conjunction with {@link DynamicTasks}) */
+    public static void markInessential() {
+        Tasks.markInessential();
+    }
+
+    /** queues the task if possible, otherwise submits it asynchronously; returns the task for callers to 
+     * {@link Task#getUnchecked()} or {@link Task#blockUntilEnded()} */
+    public static <T> Task<T> submit(TaskAdaptable<T> task, Entity entity) {
+        return queueIfPossible(task).orSubmitAsync(entity).asTask();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ExecutionListener.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ExecutionListener.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ExecutionListener.java
new file mode 100644
index 0000000..5341b21
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ExecutionListener.java
@@ -0,0 +1,31 @@
+/*
+ * 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.util.task;
+
+import org.apache.brooklyn.api.management.Task;
+
+public interface ExecutionListener {
+
+    /** invoked when a task completes: 
+     * {@link Task#getEndTimeUtc()} and {@link Task#isDone()} are guaranteed to be set,
+     * and {@link Task#get()} should return immediately for most Task implementations
+     * (care has been taken to avoid potential deadlocks here, waiting for a result!)  */
+    public void onTaskDone(Task<?> task);
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/ExecutionUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/ExecutionUtils.java b/core/src/main/java/org/apache/brooklyn/core/util/task/ExecutionUtils.java
new file mode 100644
index 0000000..be677e3
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/ExecutionUtils.java
@@ -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.core.util.task;
+
+import groovy.lang.Closure;
+
+import java.util.concurrent.Callable;
+
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+
+public class ExecutionUtils {
+    /**
+     * Attempts to run/call the given object, with the given arguments if possible, preserving the return value if there is one (null otherwise);
+     * throws exception if the callable is a non-null object which cannot be invoked (not a callable or runnable)
+     * @deprecated since 0.7.0 ; this super-loose typing should be avoided; if it is needed, let's move it to one of the Groovy compatibility classes
+     */
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static Object invoke(Object callable, Object ...args) {
+        if (callable instanceof Closure) return ((Closure<?>)callable).call(args);
+        if (callable instanceof Callable) {
+            try {
+                return ((Callable<?>)callable).call();
+            } catch (Throwable t) {
+                throw Throwables.propagate(t);
+            }
+        }
+        if (callable instanceof Runnable) { ((Runnable)callable).run(); return null; }
+        if (callable instanceof Function && args.length == 1) { return ((Function)callable).apply(args[0]); }
+        if (callable==null) return null;
+        throw new IllegalArgumentException("Cannot invoke unexpected object "+callable+" of type "+callable.getClass()+", with "+args.length+" args");
+    }
+}



[43/64] incubator-brooklyn git commit: brooklyn-software-messaging: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/zookeeper/ZooKeeperEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/zookeeper/ZooKeeperEc2LiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/zookeeper/ZooKeeperEc2LiveTest.java
new file mode 100644
index 0000000..c905f38
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/zookeeper/ZooKeeperEc2LiveTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.entity.messaging.zookeeper;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.trait.Startable;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
+
+import com.google.common.collect.ImmutableList;
+
+public class ZooKeeperEc2LiveTest extends AbstractEc2LiveTest {
+
+    /**
+     * Test that can install, start and use a Zookeeper instance.
+     */
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        ZooKeeperNode zookeeper = app.createAndManageChild(EntitySpec.create(ZooKeeperNode.class).configure("jmxPort", "31001+"));
+        app.start(ImmutableList.of(loc));
+        Entities.dumpInfo(zookeeper);
+        EntityTestUtils.assertAttributeEqualsEventually(zookeeper, Startable.SERVICE_UP, true);
+    }
+    
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/zookeeper/ZooKeeperEnsembleLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/zookeeper/ZooKeeperEnsembleLiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/zookeeper/ZooKeeperEnsembleLiveTest.java
new file mode 100644
index 0000000..c4ca441
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/zookeeper/ZooKeeperEnsembleLiveTest.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.entity.messaging.zookeeper;
+
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.trait.Startable;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.Uninterruptibles;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.net.Socket;
+import java.util.concurrent.TimeUnit;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * A live test of the {@link org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble} entity.
+ *
+ * Tests that a 3 node cluster can be started on Amazon EC2 and data written on one {@link org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble}
+ * can be read from another, using the Astyanax API.
+ */
+public class ZooKeeperEnsembleLiveTest {
+
+    private static final Logger log = LoggerFactory.getLogger(ZooKeeperEnsembleLiveTest.class);
+    
+    private String provider = 
+            "gce-europe-west1";
+//            "aws-ec2:eu-west-1";
+//            "named:hpcloud-compute-at";
+//            "localhost";
+
+    protected TestApplication app;
+    protected Location testLocation;
+    protected ZooKeeperEnsemble cluster;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setup() {
+        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        testLocation = app.getManagementContext().getLocationRegistry().resolve(provider);
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void shutdown() {
+        Entities.destroyAll(app.getManagementContext());
+    }
+
+    /**
+     * Test that a two node cluster starts up and allows access through both nodes.
+     */
+    @Test(groups = "Live")
+    public void testStartUpConnectAndResize() throws Exception {
+        try {
+            cluster = app.createAndManageChild(EntitySpec.create(ZooKeeperEnsemble.class)
+                    .configure("initialSize", 3)
+                    .configure("clusterName", "ZooKeeperEnsembleLiveTest"));
+            assertEquals(cluster.getCurrentSize().intValue(), 0);
+
+            app.start(ImmutableList.of(testLocation));
+
+            EntityTestUtils.assertAttributeEqualsEventually(cluster, ZooKeeperEnsemble.GROUP_SIZE, 3);
+            Entities.dumpInfo(app);
+
+            EntityTestUtils.assertAttributeEqualsEventually(cluster, Startable.SERVICE_UP, true);
+            for(Entity zkNode : cluster.getMembers()) {
+                assertTrue(isSocketOpen((ZooKeeperNode) zkNode));
+            }
+            cluster.resize(1);
+            EntityTestUtils.assertAttributeEqualsEventually(cluster, ZooKeeperEnsemble.GROUP_SIZE, 1);
+            Entities.dumpInfo(app);
+            EntityTestUtils.assertAttributeEqualsEventually(cluster, Startable.SERVICE_UP, true);
+            for (Entity zkNode : cluster.getMembers()) {
+                assertTrue(isSocketOpen((ZooKeeperNode) zkNode));
+            }
+        } catch (Throwable e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
+    protected static boolean isSocketOpen(ZooKeeperNode node) {
+        int attempt = 0, maxAttempts = 20;
+        while(attempt < maxAttempts) {
+            try {
+                Socket s = new Socket(node.getAttribute(Attributes.HOSTNAME), node.getZookeeperPort());
+                s.close();
+                return true;
+            } catch (Exception e) {
+                attempt++;
+            }
+            Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
+        }
+        return false;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/usage/launcher/src/test/resources/opengamma-cluster.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/opengamma-cluster.yaml b/usage/launcher/src/test/resources/opengamma-cluster.yaml
index ebb5c35..a532f41 100644
--- a/usage/launcher/src/test/resources/opengamma-cluster.yaml
+++ b/usage/launcher/src/test/resources/opengamma-cluster.yaml
@@ -28,7 +28,7 @@ services:
       attributes:
         postgresql:
           sql: io/cloudsoft/opengamma/config/create-brooklyn-db.sql
-  - type: brooklyn.entity.messaging.activemq.ActiveMQBroker
+  - type: org.apache.brooklyn.entity.messaging.activemq.ActiveMQBroker
     id: og-amq
 - type: Fabric
   id: web-fabric

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/usage/launcher/src/test/resources/storm-blueprint.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/storm-blueprint.yaml b/usage/launcher/src/test/resources/storm-blueprint.yaml
index 47e7af5..8271c1a 100644
--- a/usage/launcher/src/test/resources/storm-blueprint.yaml
+++ b/usage/launcher/src/test/resources/storm-blueprint.yaml
@@ -19,7 +19,7 @@
 name: Storm Sample App
 location: aws-ec2:us-east-1
 services:
-- type: brooklyn.entity.messaging.storm.StormDeployment
+- type: org.apache.brooklyn.entity.messaging.storm.StormDeployment
   name: Storm Deployment
   brooklyn.config:
     storm.supervisors.count: 5


[60/64] incubator-brooklyn git commit: brooklyn-software-database: add org.apache package prefix

Posted by he...@apache.org.
brooklyn-software-database: add org.apache package prefix


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

Branch: refs/heads/master
Commit: ac1a7c0947b33a71124ef4d56ed356a248db357d
Parents: 5dfe944
Author: Ciprian Ciubotariu <ch...@gmx.net>
Authored: Fri Aug 14 16:24:40 2015 +0300
Committer: Ciprian Ciubotariu <ch...@gmx.net>
Committed: Tue Aug 18 12:33:38 2015 +0300

----------------------------------------------------------------------
 docs/guide/start/_my-web-cluster.yaml           |   2 +-
 .../appserver-clustered-w-db-concise.yaml       |   2 +-
 .../example_yaml/appserver-clustered-w-db.yaml  |   2 +-
 .../appserver-w-db-other-flavor.yaml            |   2 +-
 .../guide/yaml/example_yaml/appserver-w-db.yaml |   2 +-
 .../yaml/example_yaml/appserver-w-policy.yaml   |   2 +-
 .../demo/WebClusterDatabaseExample.java         |   2 +-
 .../demo/WebClusterDatabaseExampleApp.java      |   2 +-
 ...lusterDatabaseExampleAppIntegrationTest.java |   2 +-
 .../postgresql/PostgreSqlNodeSaltImpl.java      |   2 +-
 .../postgresql/PostgreSqlSaltLiveTest.java      |   6 +-
 software/database/pom.xml                       |  18 +-
 .../brooklyn/entity/database/DatabaseNode.java  |  29 --
 .../entity/database/DatastoreMixins.java        | 104 ----
 .../entity/database/crate/CrateNode.java        |  92 ----
 .../entity/database/crate/CrateNodeDriver.java  |  24 -
 .../entity/database/crate/CrateNodeImpl.java    |  99 ----
 .../database/crate/CrateNodeSshDriver.java      | 118 -----
 .../entity/database/mariadb/MariaDbDriver.java  |  31 --
 .../entity/database/mariadb/MariaDbNode.java    | 100 ----
 .../database/mariadb/MariaDbNodeImpl.java       | 139 -----
 .../database/mariadb/MariaDbSshDriver.java      | 259 ----------
 .../entity/database/mysql/MySqlCluster.java     |  68 ---
 .../entity/database/mysql/MySqlClusterImpl.java | 445 ----------------
 .../entity/database/mysql/MySqlDriver.java      |  31 --
 .../entity/database/mysql/MySqlNode.java        |  97 ----
 .../entity/database/mysql/MySqlNodeImpl.java    | 167 ------
 .../entity/database/mysql/MySqlRowParser.java   |  39 --
 .../entity/database/mysql/MySqlSshDriver.java   | 279 ----------
 .../database/postgresql/PostgreSqlDriver.java   |  33 --
 .../database/postgresql/PostgreSqlNode.java     |  95 ----
 .../PostgreSqlNodeChefImplFromScratch.java      | 171 -------
 .../database/postgresql/PostgreSqlNodeImpl.java |  85 ---
 .../database/postgresql/PostgreSqlSpecs.java    |  43 --
 .../postgresql/PostgreSqlSshDriver.java         | 425 ---------------
 .../entity/database/rubyrep/RubyRepDriver.java  |  28 -
 .../entity/database/rubyrep/RubyRepNode.java    | 109 ----
 .../database/rubyrep/RubyRepNodeImpl.java       | 111 ----
 .../database/rubyrep/RubyRepSshDriver.java      | 126 -----
 .../brooklyn/entity/database/DatabaseNode.java  |  29 ++
 .../entity/database/DatastoreMixins.java        | 104 ++++
 .../entity/database/crate/CrateNode.java        |  92 ++++
 .../entity/database/crate/CrateNodeDriver.java  |  24 +
 .../entity/database/crate/CrateNodeImpl.java    |  99 ++++
 .../database/crate/CrateNodeSshDriver.java      | 118 +++++
 .../entity/database/mariadb/MariaDbDriver.java  |  31 ++
 .../entity/database/mariadb/MariaDbNode.java    | 100 ++++
 .../database/mariadb/MariaDbNodeImpl.java       | 139 +++++
 .../database/mariadb/MariaDbSshDriver.java      | 259 ++++++++++
 .../entity/database/mysql/MySqlCluster.java     |  68 +++
 .../entity/database/mysql/MySqlClusterImpl.java | 445 ++++++++++++++++
 .../entity/database/mysql/MySqlDriver.java      |  31 ++
 .../entity/database/mysql/MySqlNode.java        |  97 ++++
 .../entity/database/mysql/MySqlNodeImpl.java    | 167 ++++++
 .../entity/database/mysql/MySqlRowParser.java   |  39 ++
 .../entity/database/mysql/MySqlSshDriver.java   | 279 ++++++++++
 .../database/postgresql/PostgreSqlDriver.java   |  33 ++
 .../database/postgresql/PostgreSqlNode.java     |  95 ++++
 .../PostgreSqlNodeChefImplFromScratch.java      | 171 +++++++
 .../database/postgresql/PostgreSqlNodeImpl.java |  85 +++
 .../database/postgresql/PostgreSqlSpecs.java    |  43 ++
 .../postgresql/PostgreSqlSshDriver.java         | 425 +++++++++++++++
 .../entity/database/rubyrep/RubyRepDriver.java  |  28 +
 .../entity/database/rubyrep/RubyRepNode.java    | 109 ++++
 .../database/rubyrep/RubyRepNodeImpl.java       | 111 ++++
 .../database/rubyrep/RubyRepSshDriver.java      | 126 +++++
 .../brooklyn/entity/database/crate/crate.yaml   |  28 -
 .../brooklyn/entity/database/mariadb/my.cnf     |  19 -
 .../entity/database/mssql/ConfigurationFile.ini | 390 --------------
 .../entity/database/mssql/checkrunningmssql.bat |  23 -
 .../entity/database/mssql/configuremssql.ps1    |  22 -
 .../entity/database/mssql/installmssql.ps1      |  49 --
 .../entity/database/mssql/launchmssql.bat       |  25 -
 .../brooklyn/entity/database/mssql/mssql.yaml   |  40 --
 .../entity/database/mssql/stopmssql.bat         |  24 -
 .../brooklyn/entity/database/mysql/mysql.conf   |  19 -
 .../entity/database/mysql/mysql_master.conf     |  26 -
 .../entity/database/mysql/mysql_slave.conf      |  33 --
 .../entity/database/postgresql/postgresql.conf  | 513 -------------------
 .../entity/database/rubyrep/rubyrep.conf        |  28 -
 .../brooklyn/entity/database/crate/crate.yaml   |  28 +
 .../brooklyn/entity/database/mariadb/my.cnf     |  19 +
 .../entity/database/mssql/ConfigurationFile.ini | 390 ++++++++++++++
 .../entity/database/mssql/checkrunningmssql.bat |  23 +
 .../entity/database/mssql/configuremssql.ps1    |  22 +
 .../entity/database/mssql/installmssql.ps1      |  49 ++
 .../entity/database/mssql/launchmssql.bat       |  25 +
 .../brooklyn/entity/database/mssql/mssql.yaml   |  40 ++
 .../entity/database/mssql/stopmssql.bat         |  24 +
 .../brooklyn/entity/database/mysql/mysql.conf   |  19 +
 .../entity/database/mysql/mysql_master.conf     |  26 +
 .../entity/database/mysql/mysql_slave.conf      |  33 ++
 .../entity/database/postgresql/postgresql.conf  | 513 +++++++++++++++++++
 .../entity/database/rubyrep/rubyrep.conf        |  28 +
 .../entity/database/VogellaExampleAccess.java   | 161 ------
 .../crate/CrateNodeIntegrationTest.java         |  64 ---
 .../mariadb/MariaDbIntegrationTest.java         | 127 -----
 .../database/mariadb/MariaDbLiveEc2Test.java    |  57 ---
 .../mariadb/MariaDbLiveRackspaceTest.java       | 104 ----
 .../mysql/MySqlClusterIntegrationTest.java      |  44 --
 .../database/mysql/MySqlClusterLiveEc2Test.java |  43 --
 .../mysql/MySqlClusterLiveSoftlayerTest.java    |  39 --
 .../database/mysql/MySqlClusterTestHelper.java  | 115 -----
 .../database/mysql/MySqlIntegrationTest.java    | 106 ----
 .../entity/database/mysql/MySqlLiveEc2Test.java |  53 --
 .../entity/database/mysql/MySqlLiveGceTest.java |  49 --
 .../database/mysql/MySqlLiveRackspaceTest.java  | 107 ----
 .../mysql/MySqlRestartIntegrationTest.java      |  42 --
 .../database/mysql/MysqlDockerLiveTest.java     |  48 --
 .../postgresql/PostgreSqDockerLiveTest.java     |  46 --
 .../database/postgresql/PostgreSqlChefTest.java | 105 ----
 .../postgresql/PostgreSqlEc2LiveTest.java       |  54 --
 .../postgresql/PostgreSqlGceLiveTest.java       |  46 --
 .../postgresql/PostgreSqlIntegrationTest.java   |  97 ----
 .../postgresql/PostgreSqlRackspaceLiveTest.java | 108 ----
 .../PostgreSqlRebindIntegrationTest.java        |  58 ---
 .../PostgreSqlRestartIntegrationTest.java       |  50 --
 .../database/rubyrep/RubyRepEc2LiveTest.java    |  75 ---
 .../rubyrep/RubyRepIntegrationTest.java         | 191 -------
 .../rubyrep/RubyRepRackspaceLiveTest.java       | 130 -----
 .../entity/database/VogellaExampleAccess.java   | 161 ++++++
 .../crate/CrateNodeIntegrationTest.java         |  64 +++
 .../mariadb/MariaDbIntegrationTest.java         | 125 +++++
 .../database/mariadb/MariaDbLiveEc2Test.java    |  57 +++
 .../mariadb/MariaDbLiveRackspaceTest.java       | 104 ++++
 .../mysql/MySqlClusterIntegrationTest.java      |  44 ++
 .../database/mysql/MySqlClusterLiveEc2Test.java |  43 ++
 .../mysql/MySqlClusterLiveSoftlayerTest.java    |  39 ++
 .../database/mysql/MySqlClusterTestHelper.java  | 115 +++++
 .../database/mysql/MySqlIntegrationTest.java    | 106 ++++
 .../entity/database/mysql/MySqlLiveEc2Test.java |  53 ++
 .../entity/database/mysql/MySqlLiveGceTest.java |  49 ++
 .../database/mysql/MySqlLiveRackspaceTest.java  | 107 ++++
 .../mysql/MySqlRestartIntegrationTest.java      |  42 ++
 .../database/mysql/MysqlDockerLiveTest.java     |  48 ++
 .../postgresql/PostgreSqDockerLiveTest.java     |  46 ++
 .../database/postgresql/PostgreSqlChefTest.java | 105 ++++
 .../postgresql/PostgreSqlEc2LiveTest.java       |  54 ++
 .../postgresql/PostgreSqlGceLiveTest.java       |  46 ++
 .../postgresql/PostgreSqlIntegrationTest.java   |  96 ++++
 .../postgresql/PostgreSqlRackspaceLiveTest.java | 108 ++++
 .../PostgreSqlRebindIntegrationTest.java        |  58 +++
 .../PostgreSqlRestartIntegrationTest.java       |  50 ++
 .../database/rubyrep/RubyRepEc2LiveTest.java    |  75 +++
 .../rubyrep/RubyRepIntegrationTest.java         | 191 +++++++
 .../rubyrep/RubyRepRackspaceLiveTest.java       | 130 +++++
 .../monitoring/monit/MonitIntegrationTest.java  |   2 +-
 .../nosql/cassandra/CassandraDatacenter.java    |   2 +-
 .../entity/nosql/cassandra/CassandraNode.java   |   2 +-
 .../nosql/cassandra/CassandraNodeSshDriver.java |   2 +-
 .../nosql/elasticsearch/ElasticSearchNode.java  |   2 +-
 .../app/ClusterWebServerDatabaseSample.java     |   4 +-
 .../brooklyn/sample/app/SampleUnitTest.java     |   4 +-
 .../java-web-app-and-db-with-function-2.yaml    |   2 +-
 .../java-web-app-and-db-with-function.yaml      |   2 +-
 .../java-web-app-and-db-with-policy.yaml        |   2 +-
 ...-java-web-app-spec-and-db-with-function.yaml |   2 +-
 .../java-web-app-and-db-with-function.yaml      |   2 +-
 .../launcher/src/test/resources/mssql-test.yaml |  12 +-
 .../test/resources/postgres-gce-blueprint.yaml  |   2 +-
 .../qa/load/SimulatedMySqlNodeImpl.java         |   6 +-
 .../brooklyn/qa/load/SimulatedTheeTierApp.java  |   2 +-
 162 files changed, 6749 insertions(+), 6752 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/docs/guide/start/_my-web-cluster.yaml
----------------------------------------------------------------------
diff --git a/docs/guide/start/_my-web-cluster.yaml b/docs/guide/start/_my-web-cluster.yaml
index ded2a69..d4c5ce6 100644
--- a/docs/guide/start/_my-web-cluster.yaml
+++ b/docs/guide/start/_my-web-cluster.yaml
@@ -14,7 +14,7 @@ services:
         component("db").attributeWhenReady("datastore.url"),
         "visitors", "brooklyn", "br00k11n")
 
-- type: brooklyn.entity.database.mysql.MySqlNode
+- type: org.apache.brooklyn.entity.database.mysql.MySqlNode
   id: db
   name: My DB
   brooklyn.config:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/docs/guide/yaml/example_yaml/appserver-clustered-w-db-concise.yaml
----------------------------------------------------------------------
diff --git a/docs/guide/yaml/example_yaml/appserver-clustered-w-db-concise.yaml b/docs/guide/yaml/example_yaml/appserver-clustered-w-db-concise.yaml
index 9e51c0a..0fd8759 100644
--- a/docs/guide/yaml/example_yaml/appserver-clustered-w-db-concise.yaml
+++ b/docs/guide/yaml/example_yaml/appserver-clustered-w-db-concise.yaml
@@ -8,7 +8,7 @@ services:
     java.sysprops: 
       brooklyn.example.db.url: $brooklyn:formatString("jdbc:%s%s?user=%s\\&password=%s",
            component("db").attributeWhenReady("datastore.url"), "visitors", "brooklyn", "br00k11n")
-- type: brooklyn.entity.database.mysql.MySqlNode
+- type: org.apache.brooklyn.entity.database.mysql.MySqlNode
   id: db
   name: DB HelloWorld Visitors
   brooklyn.config:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/docs/guide/yaml/example_yaml/appserver-clustered-w-db.yaml
----------------------------------------------------------------------
diff --git a/docs/guide/yaml/example_yaml/appserver-clustered-w-db.yaml b/docs/guide/yaml/example_yaml/appserver-clustered-w-db.yaml
index 10592d8..79bc187 100644
--- a/docs/guide/yaml/example_yaml/appserver-clustered-w-db.yaml
+++ b/docs/guide/yaml/example_yaml/appserver-clustered-w-db.yaml
@@ -11,7 +11,7 @@ services:
         java.sysprops: 
           brooklyn.example.db.url: $brooklyn:formatString("jdbc:%s%s?user=%s\\&password=%s",
               component("db").attributeWhenReady("datastore.url"), "visitors", "brooklyn", "br00k11n")
-- type: brooklyn.entity.database.mysql.MySqlNode
+- type: org.apache.brooklyn.entity.database.mysql.MySqlNode
   id: db
   name: DB HelloWorld Visitors
   brooklyn.config:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/docs/guide/yaml/example_yaml/appserver-w-db-other-flavor.yaml
----------------------------------------------------------------------
diff --git a/docs/guide/yaml/example_yaml/appserver-w-db-other-flavor.yaml b/docs/guide/yaml/example_yaml/appserver-w-db-other-flavor.yaml
index 6a4a81d..8c0fa2a 100644
--- a/docs/guide/yaml/example_yaml/appserver-w-db-other-flavor.yaml
+++ b/docs/guide/yaml/example_yaml/appserver-w-db-other-flavor.yaml
@@ -8,7 +8,7 @@ services:
     java.sysprops: 
       brooklyn.example.db.url: $brooklyn:formatString("jdbc:%s%s?user=%s\\&password=%s",
          component("db").attributeWhenReady("datastore.url"), "visitors", "brooklyn", "br00k11n")
-- type: brooklyn.entity.database.mariadb.MariaDbNode
+- type: org.apache.brooklyn.entity.database.mariadb.MariaDbNode
   id: db
   name: DB HelloWorld Visitors
   brooklyn.config:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/docs/guide/yaml/example_yaml/appserver-w-db.yaml
----------------------------------------------------------------------
diff --git a/docs/guide/yaml/example_yaml/appserver-w-db.yaml b/docs/guide/yaml/example_yaml/appserver-w-db.yaml
index a043f1a..adc90f0 100644
--- a/docs/guide/yaml/example_yaml/appserver-w-db.yaml
+++ b/docs/guide/yaml/example_yaml/appserver-w-db.yaml
@@ -8,7 +8,7 @@ services:
     java.sysprops: 
       brooklyn.example.db.url: $brooklyn:formatString("jdbc:%s%s?user=%s\\&password=%s",
          component("db").attributeWhenReady("datastore.url"), "visitors", "brooklyn", "br00k11n")
-- type: brooklyn.entity.database.mysql.MySqlNode
+- type: org.apache.brooklyn.entity.database.mysql.MySqlNode
   id: db
   name: DB HelloWorld Visitors
   brooklyn.config:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/docs/guide/yaml/example_yaml/appserver-w-policy.yaml
----------------------------------------------------------------------
diff --git a/docs/guide/yaml/example_yaml/appserver-w-policy.yaml b/docs/guide/yaml/example_yaml/appserver-w-policy.yaml
index cada61f..34480b1 100644
--- a/docs/guide/yaml/example_yaml/appserver-w-policy.yaml
+++ b/docs/guide/yaml/example_yaml/appserver-w-policy.yaml
@@ -19,7 +19,7 @@ services:
       metricUpperBound: 100
       minPoolSize: 1
       maxPoolSize: 5
-- type: brooklyn.entity.database.mysql.MySqlNode
+- type: org.apache.brooklyn.entity.database.mysql.MySqlNode
   id: db
   name: DB HelloWorld Visitors
   brooklyn.config:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 7084b74..4f08517 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
@@ -33,7 +33,7 @@ import brooklyn.enricher.HttpLatencyDetector;
 import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.database.mysql.MySqlNode;
+import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import brooklyn.event.basic.Sensors;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 441999f..96301be 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
@@ -45,7 +45,7 @@ import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.database.mysql.MySqlNode;
+import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.java.JavaEntityMethods;
 import brooklyn.event.basic.Sensors;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 38f7059..4835af3 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
@@ -51,7 +51,7 @@ import brooklyn.enricher.HttpLatencyDetector;
 import brooklyn.enricher.basic.Propagator;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.database.mysql.MySqlNode;
+import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.java.JavaEntityMethods;
 import brooklyn.entity.rebind.RebindOptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 2fa16fc..4cd74eb 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
@@ -36,7 +36,7 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EffectorStartableImpl;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.database.postgresql.PostgreSqlNode;
+import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
 import brooklyn.entity.effector.EffectorBody;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.software.SshEffectorTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 fde60cc..6f195bb 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
@@ -36,9 +36,9 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.Entities;
-import brooklyn.entity.database.VogellaExampleAccess;
-import brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
-import brooklyn.entity.database.postgresql.PostgreSqlNode;
+import org.apache.brooklyn.entity.database.VogellaExampleAccess;
+import org.apache.brooklyn.entity.database.postgresql.PostgreSqlIntegrationTest;
+import org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode;
 import brooklyn.entity.effector.EffectorTasks;
 import brooklyn.entity.software.SshEffectorTasks;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/pom.xml
----------------------------------------------------------------------
diff --git a/software/database/pom.xml b/software/database/pom.xml
index f98a8e3..97d571c 100644
--- a/software/database/pom.xml
+++ b/software/database/pom.xml
@@ -46,15 +46,15 @@
                                 the given components. These are files "without any degree of creativity" from the
                                 perspective of the Brooklyn/Apache contribution.
                             -->
-                            <exclude>src/main/resources/brooklyn/entity/database/crate/crate.yaml</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/database/mariadb/my.cnf</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/database/mysql/mysql.conf</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/database/mysql/mysql_master.conf</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/database/mysql/mysql_slave.conf</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/database/postgresql/postgresql.conf</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/database/rubyrep/rubyrep.conf</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/database/mssql/ConfigurationFile.ini</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/database/mssql/mssql.yaml</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/database/crate/crate.yaml</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/database/mariadb/my.cnf</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql.conf</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql_master.conf</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/database/mysql/mysql_slave.conf</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/database/postgresql/postgresql.conf</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/database/rubyrep/rubyrep.conf</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/database/mssql/ConfigurationFile.ini</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/database/mssql/mssql.yaml</exclude>
                         </excludes>
                     </configuration>
                 </plugin>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/DatabaseNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/DatabaseNode.java b/software/database/src/main/java/brooklyn/entity/database/DatabaseNode.java
deleted file mode 100644
index 33bf2e8..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/DatabaseNode.java
+++ /dev/null
@@ -1,29 +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 brooklyn.entity.database;
-
-import org.apache.brooklyn.api.event.AttributeSensor;
-
-/** @deprecated since 0.7.0 use DatastoreMixins.DatastoreCommon */ @Deprecated 
-public interface DatabaseNode extends DatastoreMixins.DatastoreCommon {
-
-    /** @deprecated since 0.7.0 use DATASTORE_URL */ @Deprecated 
-    public static final AttributeSensor<String> DB_URL = DATASTORE_URL;
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/DatastoreMixins.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/DatastoreMixins.java b/software/database/src/main/java/brooklyn/entity/database/DatastoreMixins.java
deleted file mode 100644
index 4727473..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/DatastoreMixins.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 brooklyn.entity.database;
-
-import java.io.InputStream;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.entity.Effector;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.ResourceUtils;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.effector.Effectors;
-import brooklyn.event.basic.Sensors;
-import brooklyn.util.stream.KnownSizeInputStream;
-import brooklyn.util.text.Strings;
-
-public class DatastoreMixins {
-
-    private DatastoreMixins() {}
-    
-    
-    public static final AttributeSensor<String> DATASTORE_URL = HasDatastoreUrl.DATASTORE_URL;
-    
-    public static interface HasDatastoreUrl {
-        public static final AttributeSensor<String> DATASTORE_URL = Sensors.newStringSensor("datastore.url",
-            "Primary contact URL for a datastore (e.g. mysql://localhost:3306/)");
-    }
-
-    
-    public static final Effector<String> EXECUTE_SCRIPT = CanExecuteScript.EXECUTE_SCRIPT;
-    
-    public static interface CanExecuteScript {
-        public static final Effector<String> EXECUTE_SCRIPT = Effectors.effector(String.class, "executeScript")
-            .description("executes the given script contents")
-            .parameter(String.class, "commands")
-            .buildAbstract();
-    }
-
-    
-    public static final ConfigKey<String> CREATION_SCRIPT_CONTENTS = CanGiveCreationScript.CREATION_SCRIPT_CONTENTS; 
-    public static final ConfigKey<String> CREATION_SCRIPT_URL = CanGiveCreationScript.CREATION_SCRIPT_URL; 
-
-    public static interface CanGiveCreationScript {
-        @SetFromFlag("creationScriptContents")
-        public static final ConfigKey<String> CREATION_SCRIPT_CONTENTS = ConfigKeys.newStringConfigKey(
-                "datastore.creation.script.contents",
-                "Contents of creation script to initialize the datastore",
-                "");
-        
-        @SetFromFlag("creationScriptUrl")
-        public static final ConfigKey<String> CREATION_SCRIPT_URL = ConfigKeys.newStringConfigKey(
-                "datastore.creation.script.url",
-                "URL of creation script to use to initialize the datastore (ignored if creationScriptContents is specified)",
-                "");
-    }
-
-    /** returns the creation script contents, if it exists, or null if none is defined (error if it cannot be loaded) */
-    @Nullable public static InputStream getDatabaseCreationScript(Entity entity) {
-        String url = entity.getConfig(DatastoreMixins.CREATION_SCRIPT_URL);
-        if (!Strings.isBlank(url))
-            return new ResourceUtils(entity).getResourceFromUrl(url);
-        String contents = entity.getConfig(DatastoreMixins.CREATION_SCRIPT_CONTENTS);
-        if (!Strings.isBlank(contents))
-            return KnownSizeInputStream.of(contents);
-        return null;
-    }
-
-    /** returns the creation script contents, if it exists, or null if none is defined (error if it cannot be loaded) */
-    @Nullable public static String getDatabaseCreationScriptAsString(Entity entity) {
-        String url = entity.getConfig(DatastoreMixins.CREATION_SCRIPT_URL);
-        if (!Strings.isBlank(url))
-            return new ResourceUtils(entity).getResourceAsString(url);
-        String contents = entity.getConfig(DatastoreMixins.CREATION_SCRIPT_CONTENTS);
-        if (!Strings.isBlank(contents))
-            return contents;
-        return null;
-    }
-    
-    /** An entity with the most common datastore config, sensors, and effectors */ 
-    public interface DatastoreCommon extends Entity, DatastoreMixins.HasDatastoreUrl, DatastoreMixins.CanExecuteScript, DatastoreMixins.CanGiveCreationScript {
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/crate/CrateNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/crate/CrateNode.java b/software/database/src/main/java/brooklyn/entity/database/crate/CrateNode.java
deleted file mode 100644
index 8373648..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/crate/CrateNode.java
+++ /dev/null
@@ -1,92 +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 brooklyn.entity.database.crate;
-
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.java.UsesJava;
-import brooklyn.entity.java.UsesJavaMXBeans;
-import brooklyn.entity.java.UsesJmx;
-import brooklyn.event.basic.AttributeSensorAndConfigKey;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-
-import org.apache.brooklyn.location.basic.PortRanges;
-
-@ImplementedBy(CrateNodeImpl.class)
-public interface CrateNode extends SoftwareProcess, UsesJava,UsesJmx, UsesJavaMXBeans, DatastoreCommon {
-
-    @SetFromFlag("version")
-    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION,
-            "0.45.7");
-
-    @SetFromFlag("downloadUrl")
-    AttributeSensorAndConfigKey<String, String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey(
-            Attributes.DOWNLOAD_URL,
-            "https://cdn.crate.io/downloads/releases/crate-${version}.tar.gz");
-
-    @SetFromFlag("serverConfig")
-    BasicAttributeSensorAndConfigKey<String> SERVER_CONFIG_URL = new BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey(
-            "crate.serverConfig", "A URL of a YAML file to use to configure the server",
-            "classpath://brooklyn/entity/database/crate/crate.yaml");
-
-    @SetFromFlag("port")
-    public static final PortAttributeSensorAndConfigKey CRATE_PORT = new PortAttributeSensorAndConfigKey(
-            "crate.port", "The port for node-to-node communication", PortRanges.fromString("4300+"));
-
-    @SetFromFlag("httpPort")
-    public static final PortAttributeSensorAndConfigKey CRATE_HTTP_PORT = new PortAttributeSensorAndConfigKey(
-            "crate.httpPort", "The port for HTTP traffic", PortRanges.fromString("4200+"));
-
-    AttributeSensor<String> MANAGEMENT_URL = Sensors.newStringSensor(
-            "crate.managementUri", "The address at which the Crate server listens");
-
-    AttributeSensor<String> SERVER_NAME = Sensors.newStringSensor(
-            "crate.server.name", "The name of the server");
-
-    AttributeSensor<Boolean> SERVER_OK = Sensors.newBooleanSensor(
-            "crate.server.ok", "True if the server reports thus");
-
-    AttributeSensor<Integer> SERVER_STATUS = Sensors.newIntegerSensor(
-            "crate.server.status", "The status of the server");
-
-    AttributeSensor<String> SERVER_BUILD_TIMESTAMP = Sensors.newStringSensor(
-            "crate.server.buildTimestamp", "The timestamp of the server build");
-
-    AttributeSensor<String> SERVER_BUILD_HASH = Sensors.newStringSensor(
-            "crate.server.buildHash", "The build hash of the server");
-
-    AttributeSensor<Boolean> SERVER_IS_BUILD_SNAPSHOT = Sensors.newBooleanSensor(
-            "crate.server.isBuildSnapshot", "True if the server reports it is a snapshot build");
-
-    AttributeSensor<String> SERVER_LUCENE_VERSION = Sensors.newStringSensor(
-            "crate.server.luceneVersion", "The Lucene version of the server");
-
-    AttributeSensor<String> SERVER_ES_VERSION = Sensors.newStringSensor(
-            "crate.server.esVersion", "The ES version of the server");
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeDriver.java b/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeDriver.java
deleted file mode 100644
index 225db07..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeDriver.java
+++ /dev/null
@@ -1,24 +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 brooklyn.entity.database.crate;
-
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-
-public interface CrateNodeDriver extends JavaSoftwareProcessDriver {
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeImpl.java b/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeImpl.java
deleted file mode 100644
index 5dcfc30..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeImpl.java
+++ /dev/null
@@ -1,99 +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 brooklyn.entity.database.crate;
-
-import brooklyn.config.render.RendererHints;
-import brooklyn.enricher.Enrichers;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.java.JavaAppUtils;
-import brooklyn.event.feed.http.HttpFeed;
-import brooklyn.event.feed.http.HttpPollConfig;
-import brooklyn.event.feed.http.HttpValueFunctions;
-import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.util.guava.Functionals;
-
-public class CrateNodeImpl extends SoftwareProcessImpl implements CrateNode{
-
-    private JmxFeed jmxFeed;
-    private HttpFeed httpFeed;
-
-    static {
-        JavaAppUtils.init();
-        RendererHints.register(MANAGEMENT_URL, RendererHints.namedActionWithUrl());
-    }
-
-    @Override
-    public Class getDriverInterface() {
-        return CrateNodeDriver.class;
-    }
-
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-        connectServiceUpIsRunning();
-        jmxFeed = JavaAppUtils.connectMXBeanSensors(this);
-        setAttribute(DATASTORE_URL, "crate://" + getAttribute(HOSTNAME) + ":" + getPort());
-        String url = "http://" + getAttribute(HOSTNAME) + ":" + getHttpPort();
-        setAttribute(MANAGEMENT_URL, url);
-
-        httpFeed = HttpFeed.builder()
-                .entity(this)
-                .baseUri(url)
-                .poll(new HttpPollConfig<String>(SERVER_NAME)
-                        .onSuccess(HttpValueFunctions.jsonContents("name", String.class)))
-                .poll(new HttpPollConfig<Integer>(SERVER_STATUS)
-                        .onSuccess(HttpValueFunctions.jsonContents("status", Integer.class)))
-                .poll(new HttpPollConfig<Boolean>(SERVER_OK)
-                        .onSuccess(HttpValueFunctions.jsonContents("ok", Boolean.class)))
-                .poll(new HttpPollConfig<String>(SERVER_BUILD_TIMESTAMP)
-                        .onSuccess(HttpValueFunctions.jsonContents(new String[]{"version", "build_timestamp"}, String.class)))
-                .poll(new HttpPollConfig<String>(SERVER_BUILD_HASH)
-                        .onSuccess(HttpValueFunctions.jsonContents(new String[]{"version", "build_hash"}, String.class)))
-                .poll(new HttpPollConfig<Boolean>(SERVER_IS_BUILD_SNAPSHOT)
-                        .onSuccess(HttpValueFunctions.jsonContents(new String[] {"version", "build_snapshot"}, Boolean.class)))
-                .poll(new HttpPollConfig<String>(SERVER_LUCENE_VERSION)
-                        .onSuccess(HttpValueFunctions.jsonContents(new String[] {"version", "lucene_version"}, String.class)))
-                .poll(new HttpPollConfig<String>(SERVER_ES_VERSION)
-                        .onSuccess(HttpValueFunctions.jsonContents(new String[] {"version", "es_version"}, String.class)))
-                .build();
-
-        addEnricher(Enrichers.builder().updatingMap(Attributes.SERVICE_NOT_UP_INDICATORS)
-                .from(SERVER_OK)
-                .computing(Functionals.ifNotEquals(true).value("Crate server reports it is not ok."))
-                .build());
-    }
-
-    @Override
-    protected void disconnectSensors() {
-        disconnectServiceUpIsRunning();
-        if (jmxFeed != null) jmxFeed.stop();
-        if (httpFeed != null) httpFeed.stop();
-        super.disconnectSensors();
-    }
-
-    public Integer getPort() {
-        return getAttribute(CRATE_PORT);
-    }
-
-    public Integer getHttpPort() {
-        return getAttribute(CRATE_HTTP_PORT);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeSshDriver.java b/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeSshDriver.java
deleted file mode 100644
index 55610da..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/crate/CrateNodeSshDriver.java
+++ /dev/null
@@ -1,118 +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 brooklyn.entity.database.crate;
-
-import static java.lang.String.format;
-
-import java.util.List;
-
-import org.apache.brooklyn.api.entity.basic.EntityLocal;
-
-import com.google.common.collect.ImmutableList;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.net.Urls;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-
-public class CrateNodeSshDriver extends JavaSoftwareProcessSshDriver {
-
-    public CrateNodeSshDriver(EntityLocal entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(),
-                resolver.getUnpackedDirectoryName(format("crate-%s", getVersion()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-
-        List<String> commands = ImmutableList.<String>builder()
-                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
-                .add("tar xvfz "+saveAs)
-                .build();
-
-        newScript(INSTALLING)
-                .failOnNonZeroResultCode()
-                .body.append(commands).execute();
-    }
-
-    @Override
-    public void customize() {
-        newScript(CUSTOMIZING)
-                .body.append("mkdir -p " + getDataLocation())
-                .execute();
-        copyTemplate(entity.getConfig(CrateNode.SERVER_CONFIG_URL), getConfigFileLocation());
-    }
-
-    @Override
-    public void launch() {
-        StringBuilder command = new StringBuilder(getExpandedInstallDir())
-                .append("/bin/crate ")
-                .append(" -d")
-                .append(" -p ").append(getPidFileLocation())
-                .append(" -Des.config=").append(getConfigFileLocation());
-        newScript(LAUNCHING)
-                .failOnNonZeroResultCode()
-                .body.append(command).execute();
-
-    }
-
-    @Override
-    public boolean isRunning() {
-        return newScript (MutableMap.of("usePidFile", getPidFileLocation()), CHECK_RUNNING)
-                .execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        // See https://crate.io/docs/stable/cli.html#signal-handling.
-        newScript(STOPPING)
-                .body.append("kill -USR2 `cat " + getPidFileLocation() + "`")
-                .execute();
-    }
-
-    protected String getConfigFileLocation() {
-        return Urls.mergePaths(getRunDir(), "config.yaml");
-    }
-
-    @Override
-    public String getLogFileLocation() {
-        return Urls.mergePaths(getRunDir(), "crate.log");
-    }
-
-    protected String getPidFileLocation () {
-        return Urls.mergePaths(getRunDir(), "pid.txt");
-    }
-
-    // public for use in template too.
-    public String getDataLocation() {
-        return Urls.mergePaths(getRunDir(), "data");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbDriver.java b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbDriver.java
deleted file mode 100644
index 2db7f2ef4..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbDriver.java
+++ /dev/null
@@ -1,31 +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 brooklyn.entity.database.mariadb;
-
-import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
-
-import brooklyn.entity.basic.SoftwareProcessDriver;
-
-/**
- * The {@link SoftwareProcessDriver} for MariaDB.
- */
-public interface MariaDbDriver extends SoftwareProcessDriver {
-    public String getStatusCmd();
-    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNode.java b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNode.java
deleted file mode 100644
index ab77af5..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNode.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 brooklyn.entity.database.mariadb;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.entity.trait.HasShortName;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.database.DatabaseNode;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
-import brooklyn.event.basic.MapConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-
-import org.apache.brooklyn.location.basic.PortRanges;
-
-@Catalog(name="MariaDB Node", description="MariaDB is an open source relational database management system (RDBMS)", iconUrl="classpath:///mariadb-logo-180x119.png")
-@ImplementedBy(MariaDbNodeImpl.class)
-public interface MariaDbNode extends SoftwareProcess, DatastoreCommon, HasShortName, DatabaseNode {
-
-    @SetFromFlag("version")
-    public static final ConfigKey<String> SUGGESTED_VERSION =
-        ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "5.5.40");
-
-    // https://downloads.mariadb.org/interstitial/mariadb-5.5.33a/kvm-bintar-hardy-amd64/mariadb-5.5.33a-linux-x86_64.tar.gz/from/http://mirrors.coreix.net/mariadb
-    // above redirects to download the artifactd from the URLs below.
-    // Use `curl -sL -w "%{http_code} %{url_effective}\n" "http://..." -o target.tar.gz` to find out redirect URL.
-    //     64-bit: http://mirrors.coreix.net/mariadb/mariadb-5.5.40/bintar-linux-x86_64/mariadb-5.5.40-linux-x86_64.tar.gz
-    //     32-bit: http://mirrors.coreix.net/mariadb/mariadb-5.5.40/bintar-linux-x86/mariadb-5.5.40-linux-i686.tar.gz
-
-    @SetFromFlag("downloadUrl")
-    public static final BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new StringAttributeSensorAndConfigKey(
-          Attributes.DOWNLOAD_URL, "${driver.mirrorUrl}/mariadb-${version}/${driver.downloadParentDir}/mariadb-${version}-${driver.osTag}.tar.gz");
-
-    /** download mirror, if desired */
-    @SetFromFlag("mirrorUrl")
-    public static final ConfigKey<String> MIRROR_URL = ConfigKeys.newStringConfigKey("mariadb.install.mirror.url", "URL of mirror",
-        "http://mirrors.coreix.net/mariadb/"
-     );
-
-    @SetFromFlag("port")
-    public static final PortAttributeSensorAndConfigKey MARIADB_PORT =
-        new PortAttributeSensorAndConfigKey("mariadb.port", "MariaDB port", PortRanges.fromString("3306, 13306+"));
-
-    @SetFromFlag("dataDir")
-    public static final ConfigKey<String> DATA_DIR = ConfigKeys.newStringConfigKey(
-        "mariadb.datadir", "Directory for writing data files", null);
-
-    @SetFromFlag("serverConf")
-    public static final MapConfigKey<Object> MARIADB_SERVER_CONF = new MapConfigKey<Object>(
-        Object.class, "mariadb.server.conf", "Configuration options for MariaDB server");
-
-    public static final ConfigKey<Object> MARIADB_SERVER_CONF_LOWER_CASE_TABLE_NAMES =
-        MARIADB_SERVER_CONF.subKey("lower_case_table_names", "See MariaDB (or MySQL!) guide. Set 1 to ignore case in table names (useful for OS portability)");
-
-    @SetFromFlag("password")
-    public static final StringAttributeSensorAndConfigKey PASSWORD = new StringAttributeSensorAndConfigKey(
-        "mariadb.password", "Database admin password (or randomly generated if not set)", null);
-
-    @SetFromFlag("socketUid")
-    public static final StringAttributeSensorAndConfigKey SOCKET_UID = new StringAttributeSensorAndConfigKey(
-        "mariadb.socketUid", "Socket uid, for use in file /tmp/mysql.sock.<uid>.3306 (or randomly generated if not set)", null);
-
-    /** @deprecated since 0.7.0 use DATASTORE_URL */ @Deprecated
-    public static final AttributeSensor<String> MARIADB_URL = DATASTORE_URL;
-
-    @SetFromFlag("configurationTemplateUrl")
-    static final BasicAttributeSensorAndConfigKey<String> TEMPLATE_CONFIGURATION_URL = new StringAttributeSensorAndConfigKey(
-        "mariadb.template.configuration.url", "Template file (in freemarker format) for the my.cnf file",
-        "classpath://brooklyn/entity/database/mariadb/my.cnf");
-
-    public static final AttributeSensor<Double> QUERIES_PER_SECOND_FROM_MARIADB =
-        Sensors.newDoubleSensor("mariadb.queries.perSec.fromMariadb");
-
-    public String executeScript(String commands);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
deleted file mode 100644
index a22af08..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
+++ /dev/null
@@ -1,139 +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 brooklyn.entity.database.mariadb;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.effector.EffectorBody;
-import brooklyn.event.feed.ssh.SshFeed;
-import brooklyn.event.feed.ssh.SshPollConfig;
-import brooklyn.event.feed.ssh.SshPollValue;
-
-import org.apache.brooklyn.core.util.config.ConfigBag;
-import org.apache.brooklyn.location.basic.Locations;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Function;
-
-public class MariaDbNodeImpl extends SoftwareProcessImpl implements MariaDbNode {
-
-    private static final Logger LOG = LoggerFactory.getLogger(MariaDbNodeImpl.class);
-
-    private SshFeed feed;
-
-    @Override
-    public Class<?> getDriverInterface() {
-        return MariaDbDriver.class;
-    }
-
-    @Override
-    public MariaDbDriver getDriver() {
-        return (MariaDbDriver) super.getDriver();
-    }
-
-    @Override
-    public void init() {
-        super.init();
-        getMutableEntityType().addEffector(EXECUTE_SCRIPT, new EffectorBody<String>() {
-            @Override
-            public String call(ConfigBag parameters) {
-                return executeScript((String)parameters.getStringKey("commands"));
-            }
-        });
-    }
-    
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-        setAttribute(DATASTORE_URL, String.format("mysql://%s:%s/", getAttribute(HOSTNAME), getAttribute(MARIADB_PORT)));
-
-        /*        
-         * TODO status gives us things like:
-         *   Uptime: 2427  Threads: 1  Questions: 581  Slow queries: 0  Opens: 53  Flush tables: 1  Open tables: 35  Queries per second avg: 0.239
-         * So can extract lots of sensors from that.
-         */
-        Maybe<SshMachineLocation> machine = Locations.findUniqueSshMachineLocation(getLocations());
-
-        if (machine.isPresent()) {
-            String cmd = getDriver().getStatusCmd();
-            feed = SshFeed.builder()
-                    .entity(this)
-                    .period(Duration.FIVE_SECONDS)
-                    .machine(machine.get())
-                    .poll(new SshPollConfig<Boolean>(SERVICE_UP)
-                            .command(cmd)
-                            .setOnSuccess(true)
-                            .setOnFailureOrException(false))
-                    .poll(new SshPollConfig<Double>(QUERIES_PER_SECOND_FROM_MARIADB)
-                            .command(cmd)
-                            .onSuccess(new Function<SshPollValue, Double>() {
-                                public Double apply(SshPollValue input) {
-                                    String q = Strings.getFirstWordAfter(input.getStdout(), "Queries per second avg:");
-                                    return (q == null) ? null : Double.parseDouble(q);
-                                }})
-                            .setOnFailureOrException(null) )
-                    .build();
-        } else {
-            LOG.warn("Location(s) {} not an ssh-machine location, so not polling for status; setting serviceUp immediately", getLocations());
-            setAttribute(SERVICE_UP, true);
-        }
-    }
-
-    @Override
-    protected void disconnectSensors() {
-        if (feed != null) feed.stop();
-        super.disconnectSensors();
-    }
-
-    public int getPort() {
-        return getAttribute(MARIADB_PORT);
-    }
-
-    public String getSocketUid() {
-        String result = getAttribute(MariaDbNode.SOCKET_UID);
-        if (Strings.isBlank(result))
-            setAttribute(MariaDbNode.SOCKET_UID, (result = Identifiers.makeRandomId(6)));
-        return result;
-    }
-
-    public String getPassword() {
-        String result = getAttribute(MariaDbNode.PASSWORD);
-        if (Strings.isBlank(result))
-            setAttribute(MariaDbNode.PASSWORD, (result = Identifiers.makeRandomId(6)));
-        return result;
-    }
-
-    @Override
-    public String getShortName() {
-        return "MariaDB";
-    }
-
-    @Override
-    public String executeScript(String commands) {
-        return getDriver().executeScriptAsync(commands).block().getStdout();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbSshDriver.java b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
deleted file mode 100644
index 4d916b9..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
+++ /dev/null
@@ -1,259 +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 brooklyn.entity.database.mariadb;
-
-import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
-import static brooklyn.util.ssh.BashCommands.commandsToDownloadUrlsAs;
-import static brooklyn.util.ssh.BashCommands.installPackage;
-import static brooklyn.util.ssh.BashCommands.ok;
-import static java.lang.String.format;
-
-import java.io.InputStream;
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.database.DatastoreMixins;
-import brooklyn.entity.software.SshEffectorTasks;
-
-import org.apache.brooklyn.api.location.OsDetails;
-import org.apache.brooklyn.core.util.task.DynamicTasks;
-import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.net.Urls;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.CountdownTimer;
-import brooklyn.util.time.Duration;
-
-import com.google.common.collect.ImmutableMap;
-
-/**
- * The SSH implementation of the {@link MariaDbDriver}.
- */
-public class MariaDbSshDriver extends AbstractSoftwareProcessSshDriver implements MariaDbDriver {
-
-    public static final Logger log = LoggerFactory.getLogger(MariaDbSshDriver.class);
-
-    public MariaDbSshDriver(MariaDbNodeImpl entity, SshMachineLocation machine) {
-        super(entity, machine);
-
-        entity.setAttribute(Attributes.LOG_FILE_LOCATION, getLogFile());
-    }
-
-    public String getOsTag() {
-        OsDetails os = getLocation().getOsDetails();
-        // NOTE: cannot rely on OsDetails.isLinux() to return true for all linux flavours, so
-        // explicitly test for unsupported OSes, otherwise assume generic linux.
-        if (os == null) return "linux-i686";
-        if (os.isWindows() || os.isMac())
-            throw new UnsupportedOperationException("only support linux versions just now; OS details: " + os);
-        return (os.is64bit() ? "linux-x86_64" : "linux-i686");
-    }
-
-    public String getDownloadParentDir() {
-        // NOTE: cannot rely on OsDetails.isLinux() to return true for all linux flavours, so
-        // explicitly test for unsupported OSes, otherwise assume generic linux.
-        OsDetails os = getLocation().getOsDetails();
-        if (os == null) return "bintar-linux-x86";
-        if (os.isWindows() || os.isMac())
-            throw new UnsupportedOperationException("only support linux versions just now; OS details: " + os);
-        return (os.is64bit() ? "bintar-linux-x86_64" : "bintar-linux-x86");
-    }
-
-    public String getMirrorUrl() {
-        return entity.getConfig(MariaDbNode.MIRROR_URL);
-    }
-
-    public String getBaseDir() { return getExpandedInstallDir(); }
-
-    public String getDataDir() {
-        String result = entity.getConfig(MariaDbNode.DATA_DIR);
-        return (result == null) ? "." : result;
-    }
-
-    public String getLogFile() {
-        return Urls.mergePaths(getRunDir(), "console.log");
-    }
-
-    public String getConfigFile() {
-        return "my.cnf";
-    }
-
-    public String getInstallFilename() {
-        return String.format("mariadb-%s-%s.tar.gz", getVersion(), getOsTag());
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this, ImmutableMap.of("filename", getInstallFilename()));
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("mariadb-%s-%s", getVersion(), getOsTag()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-
-        List<String> commands = new LinkedList<String>();
-        commands.add(BashCommands.INSTALL_TAR);
-        commands.add(BashCommands.INSTALL_CURL);
-
-        commands.add("echo installing extra packages");
-        commands.add(installPackage(ImmutableMap.of("yum", "libgcc_s.so.1"), null));
-        commands.add(installPackage(ImmutableMap.of("yum", "libaio.so.1 libncurses.so.5", "apt", "libaio1 libaio-dev"), null));
-
-        // these deps are needed on some OS versions but others don't need them so ignore failures (ok(...))
-        commands.add(ok(installPackage(ImmutableMap.of("yum", "libaio", "apt", "ia32-libs"), null)));
-        commands.add("echo finished installing extra packages");
-
-        commands.addAll(commandsToDownloadUrlsAs(urls, saveAs));
-        commands.add(format("tar xfvz %s", saveAs));
-
-        newScript(INSTALLING).body.append(commands).execute();
-    }
-
-    public MariaDbNodeImpl getEntity() { return (MariaDbNodeImpl) super.getEntity(); }
-    public int getPort() { return getEntity().getPort(); }
-    public String getSocketUid() { return getEntity().getSocketUid(); }
-    public String getPassword() { return getEntity().getPassword(); }
-
-    @Override
-    public void customize() {
-        copyDatabaseConfigScript();
-
-        newScript(CUSTOMIZING)
-            .updateTaskAndFailOnNonZeroResultCode()
-            .body.append(
-                "chmod 600 "+getConfigFile(),
-                getBaseDir()+"/scripts/mysql_install_db "+
-                    "--basedir="+getBaseDir()+" --datadir="+getDataDir()+" "+
-                    "--defaults-file="+getConfigFile())
-            .execute();
-
-        // launch, then we will configure it
-        launch();
-
-        CountdownTimer timer = Duration.seconds(20).countdownTimer();
-        boolean hasCreationScript = copyDatabaseCreationScript();
-        timer.waitForExpiryUnchecked();
-
-        DynamicTasks.queue(
-            SshEffectorTasks.ssh(
-                "cd "+getRunDir(),
-                getBaseDir()+"/bin/mysqladmin --defaults-file="+getConfigFile()+" --password= password "+getPassword()
-            ).summary("setting password"));
-
-        if (hasCreationScript)
-            executeScriptFromInstalledFileAsync("creation-script.sql");
-
-        // not sure necessary to stop then subsequently launch, but seems safest
-        // (if skipping, use a flag in launch to indicate we've just launched it)
-        stop();
-    }
-
-    private void copyDatabaseConfigScript() {
-        newScript(CUSTOMIZING).execute();  //create the directory
-
-        String configScriptContents = processTemplate(entity.getAttribute(MariaDbNode.TEMPLATE_CONFIGURATION_URL));
-        Reader configContents = new StringReader(configScriptContents);
-
-        getMachine().copyTo(configContents, Urls.mergePaths(getRunDir(), getConfigFile()));
-    }
-
-    private boolean copyDatabaseCreationScript() {
-        InputStream creationScript = DatastoreMixins.getDatabaseCreationScript(entity);
-        if (creationScript==null) return false;
-        getMachine().copyTo(creationScript, getRunDir() + "/creation-script.sql");
-        return true;
-    }
-
-    public String getMariaDbServerOptionsString() {
-        Map<String, Object> options = entity.getConfig(MariaDbNode.MARIADB_SERVER_CONF);
-        StringBuilder result = new StringBuilder();
-        if (groovyTruth(options)) {
-            for (Map.Entry<String, Object> entry : options.entrySet()) {
-                result.append(entry.getKey());
-                String value = entry.getValue().toString();
-                if (!Strings.isEmpty(value)) {
-                    result.append(" = ").append(value);
-                }
-                result.append('\n');
-            }
-        }
-        return result.toString();
-    }
-
-    @Override
-    public void launch() {
-        newScript(MutableMap.of("usePidFile", true), LAUNCHING)
-            .updateTaskAndFailOnNonZeroResultCode()
-            .body.append(format("nohup %s/bin/mysqld --defaults-file=%s --user=`whoami` > %s 2>&1 < /dev/null &", getBaseDir(), getConfigFile(), getLogFile()))
-            .execute();
-    }
-
-    @Override
-    public boolean isRunning() {
-        return newScript(MutableMap.of("usePidFile", false), CHECK_RUNNING)
-            .body.append(getStatusCmd())
-            .execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        newScript(MutableMap.of("usePidFile", true), STOPPING).execute();
-    }
-
-    @Override
-    public void kill() {
-        newScript(MutableMap.of("usePidFile", true), KILLING).execute();
-    }
-
-    @Override
-    public String getStatusCmd() {
-        return format("%s/bin/mysqladmin --defaults-file=%s status", getExpandedInstallDir(), Urls.mergePaths(getRunDir(), getConfigFile()));
-    }
-
-    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands) {
-        String filename = "mariadb-commands-"+Identifiers.makeRandomId(8);
-        DynamicTasks.queue(SshEffectorTasks.put(Urls.mergePaths(getRunDir(), filename)).contents(commands).summary("copying datastore script to execute "+filename));
-        return executeScriptFromInstalledFileAsync(filename);
-    }
-
-    public ProcessTaskWrapper<Integer> executeScriptFromInstalledFileAsync(String filenameAlreadyInstalledAtServer) {
-        return DynamicTasks.queue(
-                SshEffectorTasks.ssh(
-                                "cd "+getRunDir(),
-                                getBaseDir()+"/bin/mysql --defaults-file="+getConfigFile()+" < "+filenameAlreadyInstalledAtServer)
-                        .summary("executing datastore script "+filenameAlreadyInstalledAtServer));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlCluster.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlCluster.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlCluster.java
deleted file mode 100644
index 3badd77..0000000
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlCluster.java
+++ /dev/null
@@ -1,68 +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 brooklyn.entity.database.mysql;
-
-import java.util.Collection;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.event.AttributeSensor;
-
-import com.google.common.reflect.TypeToken;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.database.DatastoreMixins.HasDatastoreUrl;
-import brooklyn.entity.group.DynamicCluster;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-
-@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")
-public interface MySqlCluster extends DynamicCluster, HasDatastoreUrl {
-    interface MySqlMaster {
-        AttributeSensor<String> MASTER_LOG_FILE = Sensors.newStringSensor("mysql.master.log_file", "The binary log file master is writing to");
-        AttributeSensor<Integer> MASTER_LOG_POSITION = Sensors.newIntegerSensor("mysql.master.log_position", "The position in the log file to start replication");
-    }
-    interface MySqlSlave {
-        AttributeSensor<Boolean> SLAVE_HEALTHY = Sensors.newBooleanSensor("mysql.slave.healthy", "Indicates that the replication state of the slave is healthy");
-        AttributeSensor<Integer> SLAVE_SECONDS_BEHIND_MASTER = Sensors.newIntegerSensor("mysql.slave.seconds_behind_master", "How many seconds behind master is the replication state on the slave");
-    }
-
-    ConfigKey<String> SLAVE_USERNAME = ConfigKeys.newStringConfigKey(
-            "mysql.slave.username", "The user name slaves will use to connect to the master", "slave");
-    ConfigKey<String> SLAVE_REPLICATE_DO_DB = ConfigKeys.newStringConfigKey(
-            "mysql.slave.replicate_do_db", "Replicate only listed DBs");
-    ConfigKey<String> SLAVE_REPLICATE_IGNORE_DB = ConfigKeys.newStringConfigKey(
-            "mysql.slave.replicate_ignore_db", "Don't replicate listed DBs");
-    ConfigKey<String> SLAVE_REPLICATE_DO_TABLE = ConfigKeys.newStringConfigKey(
-            "mysql.slave.replicate_do_table", "Replicate only listed tables");
-    ConfigKey<String> SLAVE_REPLICATE_IGNORE_TABLE = ConfigKeys.newStringConfigKey(
-            "mysql.slave.replicate_ignore_table", "Don't replicate listed tables");
-    ConfigKey<String> SLAVE_REPLICATE_WILD_DO_TABLE = ConfigKeys.newStringConfigKey(
-            "mysql.slave.replicate_wild_do_table", "Replicate only listed tables, wildcards acepted");
-    ConfigKey<String> SLAVE_REPLICATE_WILD_IGNORE_TABLE = ConfigKeys.newStringConfigKey(
-            "mysql.slave.replicate_wild_ignore_table", "Don't replicate listed tables, wildcards acepted");
-    StringAttributeSensorAndConfigKey SLAVE_PASSWORD = new StringAttributeSensorAndConfigKey(
-            "mysql.slave.password", "The password slaves will use to connect to the master. Will be auto-generated by default.");
-    @SuppressWarnings("serial")
-    AttributeSensor<Collection<String>> SLAVE_DATASTORE_URL_LIST = Sensors.newSensor(new TypeToken<Collection<String>>() {},
-            "mysql.slave.datastore.url", "List of all slave's DATASTORE_URL sensors");
-    AttributeSensor<Double> QUERIES_PER_SECOND_FROM_MYSQL_PER_NODE = Sensors.newDoubleSensor("mysql.queries.perSec.fromMysql.perNode");
-}


[27/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/XmlUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/XmlUtil.java b/core/src/main/java/brooklyn/util/xstream/XmlUtil.java
deleted file mode 100644
index 1ab1293..0000000
--- a/core/src/main/java/brooklyn/util/xstream/XmlUtil.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 brooklyn.util.xstream;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPathExpression;
-import javax.xml.xpath.XPathExpressionException;
-import javax.xml.xpath.XPathFactory;
-
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
-
-import brooklyn.util.exceptions.Exceptions;
-
-public class XmlUtil {
-
-    public static Object xpath(String xml, String xpath) {
-        // TODO Could share factory/doc in thread-local storage; see http://stackoverflow.com/questions/9828254/is-documentbuilderfactory-thread-safe-in-java-5
-        try {
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            DocumentBuilder builder = factory.newDocumentBuilder();
-            Document doc = builder.parse(new ByteArrayInputStream(xml.getBytes()));
-            XPathFactory xPathfactory = XPathFactory.newInstance();
-            XPathExpression expr = xPathfactory.newXPath().compile(xpath);
-            
-            return expr.evaluate(doc);
-            
-        } catch (ParserConfigurationException e) {
-            throw Exceptions.propagate(e);
-        } catch (SAXException e) {
-            throw Exceptions.propagate(e);
-        } catch (IOException e) {
-            throw Exceptions.propagate(e);
-        } catch (XPathExpressionException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
index 0e8ec80..ae3f39f 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
@@ -55,6 +55,7 @@ import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.core.catalog.CatalogPredicates;
 import org.apache.brooklyn.core.catalog.internal.CatalogClasspathDo.CatalogScanningModes;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import brooklyn.config.BrooklynServerConfig;
 
@@ -64,7 +65,6 @@ import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.AggregateClassLoader;
 import brooklyn.util.javalang.LoadedClassLoader;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogClasspathDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogClasspathDo.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogClasspathDo.java
index 2bf9cca..822a8d2 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogClasspathDo.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogClasspathDo.java
@@ -39,13 +39,13 @@ import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.javalang.ReflectionScanner;
+import org.apache.brooklyn.core.util.javalang.UrlClassLoader;
 
 import brooklyn.entity.basic.ApplicationBuilder;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.javalang.AggregateClassLoader;
-import brooklyn.util.javalang.ReflectionScanner;
-import brooklyn.util.javalang.UrlClassLoader;
 import brooklyn.util.os.Os;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogDto.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogDto.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogDto.java
index 847f114..aefb635 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogDto.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogDto.java
@@ -27,8 +27,8 @@ import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.core.util.ResourceUtils;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogDtoUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogDtoUtils.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogDtoUtils.java
index e2df123..6a27393 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogDtoUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogDtoUtils.java
@@ -22,10 +22,10 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 
 import org.apache.brooklyn.core.catalog.internal.CatalogClasspathDo.CatalogScanningModes;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 
 public class CatalogDtoUtils {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
index 047a168..e00211c 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
@@ -29,14 +29,14 @@ import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.ha.ManagementNodeState;
 import org.apache.brooklyn.core.management.ManagementContextInjectable;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import brooklyn.config.BrooklynServerConfig;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.FatalRuntimeException;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
index 5aa073b..a7e52ee 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemDtoAbstract.java
@@ -34,12 +34,12 @@ import brooklyn.basic.AbstractBrooklynObject;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.entity.rebind.RebindSupport;
 import org.apache.brooklyn.api.mementos.CatalogItemMemento;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.rebind.BasicCatalogItemRebindSupport;
 import brooklyn.util.collections.MutableList;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogXmlSerializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogXmlSerializer.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogXmlSerializer.java
index 462e00e..836cac3 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogXmlSerializer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogXmlSerializer.java
@@ -24,10 +24,10 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.brooklyn.core.catalog.internal.CatalogClasspathDo.CatalogScanningModes;
+import org.apache.brooklyn.core.util.xstream.EnumCaseForgivingSingleValueConverter;
+import org.apache.brooklyn.core.util.xstream.XmlSerializer;
 
 import brooklyn.basic.AbstractBrooklynObject;
-import brooklyn.util.xstream.EnumCaseForgivingSingleValueConverter;
-import brooklyn.util.xstream.XmlSerializer;
 
 public class CatalogXmlSerializer extends XmlSerializer<Object> {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynFeatureEnablement.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynFeatureEnablement.java b/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynFeatureEnablement.java
index 24d138b..686fd35 100644
--- a/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynFeatureEnablement.java
+++ b/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynFeatureEnablement.java
@@ -21,12 +21,12 @@ package org.apache.brooklyn.core.internal;
 import java.util.Map;
 
 import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.BrooklynProperties;
 import brooklyn.internal.storage.BrooklynStorage;
-import brooklyn.util.internal.ssh.ShellTool;
 
 import com.google.common.annotations.Beta;
 import com.google.common.collect.Maps;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynInitialization.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynInitialization.java b/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynInitialization.java
index 1858306..d1104af 100644
--- a/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynInitialization.java
+++ b/core/src/main/java/org/apache/brooklyn/core/internal/BrooklynInitialization.java
@@ -20,9 +20,10 @@ package org.apache.brooklyn.core.internal;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.crypto.SecureKeys;
-import brooklyn.util.flags.TypeCoercions;
+
 import brooklyn.util.net.Networking;
 
 import com.google.common.annotations.Beta;
@@ -52,7 +53,7 @@ public class BrooklynInitialization {
 
     @SuppressWarnings("deprecation")
     public static void initLegacyLanguageExtensions() {
-        brooklyn.util.BrooklynLanguageExtensions.init();
+        org.apache.brooklyn.core.util.BrooklynLanguageExtensions.init();
     }
 
     /* other things:
@@ -74,7 +75,7 @@ public class BrooklynInitialization {
     @SuppressWarnings("deprecation")
     public synchronized static void reinitAll() {
         done.set(false);
-        brooklyn.util.BrooklynLanguageExtensions.reinit();
+        org.apache.brooklyn.core.util.BrooklynLanguageExtensions.reinit();
         initAll();
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/entitlement/Entitlements.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/entitlement/Entitlements.java b/core/src/main/java/org/apache/brooklyn/core/management/entitlement/Entitlements.java
index 6bf9329..dc49053 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/entitlement/Entitlements.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/entitlement/Entitlements.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.management.entitlement.EntitlementClass;
 import org.apache.brooklyn.api.management.entitlement.EntitlementContext;
 import org.apache.brooklyn.api.management.entitlement.EntitlementManager;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,7 +50,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.javalang.Reflections;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 
 /** @since 0.7.0 */

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/ha/HighAvailabilityManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/ha/HighAvailabilityManagerImpl.java b/core/src/main/java/org/apache/brooklyn/core/management/ha/HighAvailabilityManagerImpl.java
index bda7f6f..f369124 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/ha/HighAvailabilityManagerImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/ha/HighAvailabilityManagerImpl.java
@@ -51,6 +51,8 @@ import org.apache.brooklyn.core.management.internal.LocalEntityManager;
 import org.apache.brooklyn.core.management.internal.LocationManagerInternal;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.management.internal.ManagementTransitionMode;
+import org.apache.brooklyn.core.util.task.ScheduledTask;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,8 +73,6 @@ import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.ReferenceWithError;
-import brooklyn.util.task.ScheduledTask;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/ha/OsgiManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/ha/OsgiManager.java b/core/src/main/java/org/apache/brooklyn/core/management/ha/OsgiManager.java
index 6a133fc..8241479 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/ha/OsgiManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/ha/OsgiManager.java
@@ -39,6 +39,8 @@ import brooklyn.BrooklynVersion;
 
 import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.osgi.Osgis;
+import org.apache.brooklyn.core.util.osgi.Osgis.BundleFinder;
 
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.config.BrooklynServerPaths;
@@ -49,8 +51,6 @@ import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.os.Os;
 import brooklyn.util.os.Os.DeletionResult;
-import brooklyn.util.osgi.Osgis;
-import brooklyn.util.osgi.Osgis.BundleFinder;
 import brooklyn.util.repeat.Repeater;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/AbstractManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/AbstractManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/AbstractManagementContext.java
index 58e2f60..7c1e473 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/AbstractManagementContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/AbstractManagementContext.java
@@ -56,6 +56,10 @@ import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.classloading.JavaBrooklynClassLoadingContext;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
 import org.apache.brooklyn.core.management.ha.HighAvailabilityManagerImpl;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.Tasks;
 
 import brooklyn.config.BrooklynProperties;
 import brooklyn.config.StringConfigMap;
@@ -74,13 +78,9 @@ import brooklyn.internal.storage.impl.inmemory.InMemoryDataGridFactory;
 import org.apache.brooklyn.location.basic.BasicLocationRegistry;
 
 import brooklyn.util.GroovyJavaMethods;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.BasicExecutionContext;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.base.Function;
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/AsyncCollectionChangeAdapter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/AsyncCollectionChangeAdapter.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/AsyncCollectionChangeAdapter.java
index 038ec90..1fc1060 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/AsyncCollectionChangeAdapter.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/AsyncCollectionChangeAdapter.java
@@ -21,13 +21,13 @@ package org.apache.brooklyn.core.management.internal;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import org.apache.brooklyn.api.management.ExecutionManager;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.SingleThreadedScheduler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.BasicExecutionManager;
-import brooklyn.util.task.SingleThreadedScheduler;
 
 public class AsyncCollectionChangeAdapter<Item> implements CollectionChangeListener<Item> {
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/BrooklynGarbageCollector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/BrooklynGarbageCollector.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/BrooklynGarbageCollector.java
index c02ff81..45876c5 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/BrooklynGarbageCollector.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/BrooklynGarbageCollector.java
@@ -39,6 +39,9 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.management.HasTaskChildren;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.ExecutionListener;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -55,9 +58,6 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.javalang.MemoryUsageTracker;
-import brooklyn.util.task.BasicExecutionManager;
-import brooklyn.util.task.ExecutionListener;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/EffectorUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/EffectorUtils.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/EffectorUtils.java
index 028f2d2..0f3ab99 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/EffectorUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/EffectorUtils.java
@@ -33,6 +33,8 @@ import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ParameterType;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,10 +43,8 @@ import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.PropagatedRuntimeException;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 
 import com.google.common.collect.Lists;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/EntityManagementUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/EntityManagementUtils.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/EntityManagementUtils.java
index 3f59774..b243cda 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/EntityManagementUtils.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/EntityManagementUtils.java
@@ -38,6 +38,8 @@ import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.core.management.classloading.JavaBrooklynClassLoadingContext;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -54,8 +56,6 @@ import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalEntityManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalEntityManager.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalEntityManager.java
index 53d31eb..23039ba 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalEntityManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalEntityManager.java
@@ -43,6 +43,7 @@ import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,7 +63,6 @@ import brooklyn.internal.storage.BrooklynStorage;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.collections.SetFromLiveMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.CountdownTimer;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalLocationManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalLocationManager.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalLocationManager.java
index 54708f5..f3e6aef 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalLocationManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalLocationManager.java
@@ -30,6 +30,8 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.ProvisioningLocation;
 import org.apache.brooklyn.api.management.AccessController;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,11 +46,9 @@ import brooklyn.internal.storage.BrooklynStorage;
 import org.apache.brooklyn.location.basic.AbstractLocation;
 import org.apache.brooklyn.location.basic.LocationInternal;
 
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalManagementContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalManagementContext.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalManagementContext.java
index 3c353e2..b29c178 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalManagementContext.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalManagementContext.java
@@ -45,6 +45,11 @@ import org.apache.brooklyn.api.management.TaskAdaptable;
 import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
 import org.apache.brooklyn.core.management.ha.OsgiManager;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskTags;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,11 +63,6 @@ import brooklyn.entity.proxying.InternalPolicyFactory;
 import brooklyn.internal.storage.DataGridFactory;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.BasicExecutionContext;
-import brooklyn.util.task.BasicExecutionManager;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskTags;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalSubscriptionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalSubscriptionManager.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalSubscriptionManager.java
index 99b79ec..9a75621 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalSubscriptionManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalSubscriptionManager.java
@@ -40,12 +40,12 @@ import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.management.ExecutionManager;
 import org.apache.brooklyn.api.management.SubscriptionHandle;
 import org.apache.brooklyn.api.management.SubscriptionManager;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.SingleThreadedScheduler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.task.BasicExecutionManager;
-import brooklyn.util.task.SingleThreadedScheduler;
 import brooklyn.util.text.Identifiers;
 
 import com.google.common.base.Predicate;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalUsageManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalUsageManager.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalUsageManager.java
index dc95d11..991f930 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalUsageManager.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/LocalUsageManager.java
@@ -39,6 +39,7 @@ import org.apache.brooklyn.core.management.ManagementContextInjectable;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
 import org.apache.brooklyn.core.management.usage.ApplicationUsage;
 import org.apache.brooklyn.core.management.usage.LocationUsage;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -52,7 +53,6 @@ import org.apache.brooklyn.location.basic.LocationConfigKeys;
 import org.apache.brooklyn.location.basic.LocationInternal;
 
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.javalang.Reflections;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/management/internal/ManagementContextInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/management/internal/ManagementContextInternal.java b/core/src/main/java/org/apache/brooklyn/core/management/internal/ManagementContextInternal.java
index 6c993d8..3fc0677 100644
--- a/core/src/main/java/org/apache/brooklyn/core/management/internal/ManagementContextInternal.java
+++ b/core/src/main/java/org/apache/brooklyn/core/management/internal/ManagementContextInternal.java
@@ -31,6 +31,7 @@ import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
 import org.apache.brooklyn.core.management.ha.OsgiManager;
+import org.apache.brooklyn.core.util.task.TaskTags;
 
 import brooklyn.config.BrooklynProperties;
 import brooklyn.entity.basic.BrooklynTaskTags;
@@ -39,7 +40,6 @@ import brooklyn.entity.proxying.InternalLocationFactory;
 import brooklyn.entity.proxying.InternalPolicyFactory;
 import brooklyn.internal.storage.BrooklynStorage;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.TaskTags;
 
 import com.google.common.annotations.Beta;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/BrooklynLanguageExtensions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/BrooklynLanguageExtensions.java b/core/src/main/java/org/apache/brooklyn/core/util/BrooklynLanguageExtensions.java
new file mode 100644
index 0000000..9e1b80e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/BrooklynLanguageExtensions.java
@@ -0,0 +1,48 @@
+/*
+ * 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.util;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.brooklyn.core.internal.BrooklynInitialization;
+
+import brooklyn.util.internal.TimeExtras;
+
+/** @deprecated since 0.7.0 use {@link BrooklynInitialization} */
+public class BrooklynLanguageExtensions {
+
+    private BrooklynLanguageExtensions() {}
+    
+    private static AtomicBoolean done = new AtomicBoolean(false);
+    
+    public synchronized static void reinit() {
+        done.set(false);
+        init();
+    }
+    
+    /** performs the language extensions required for this project */
+    public synchronized static void init() {
+        if (done.getAndSet(true)) return;
+        TimeExtras.init();
+        BrooklynInitialization.initPortRanges();
+    }
+    
+    static { BrooklynInitialization.initLegacyLanguageExtensions(); }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/BrooklynMavenArtifacts.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/BrooklynMavenArtifacts.java b/core/src/main/java/org/apache/brooklyn/core/util/BrooklynMavenArtifacts.java
new file mode 100644
index 0000000..c00fec0
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/BrooklynMavenArtifacts.java
@@ -0,0 +1,58 @@
+/*
+ * 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.util;
+
+import brooklyn.BrooklynVersion;
+import brooklyn.util.maven.MavenArtifact;
+import brooklyn.util.maven.MavenRetriever;
+import brooklyn.util.text.Strings;
+
+public class BrooklynMavenArtifacts {
+
+    public static MavenArtifact jar(String artifactId) {
+        return artifact(null, artifactId, "jar");
+    }
+    
+    public static MavenArtifact artifact(String subgroupUnderIoBrooklyn, String artifactId, String packaging) {
+        return artifact(subgroupUnderIoBrooklyn, artifactId, packaging, null);
+    }
+
+    public static MavenArtifact artifact(String subgroupUnderIoBrooklyn, String artifactId, String packaging, String classifier) {
+        return new MavenArtifact(
+                Strings.isEmpty(subgroupUnderIoBrooklyn) ? "org.apache.brooklyn" : "org.apache.brooklyn."+subgroupUnderIoBrooklyn,
+                artifactId, packaging, classifier, BrooklynVersion.get());
+    }
+
+    public static String localUrlForJar(String artifactId) {
+        return MavenRetriever.localUrl(jar(artifactId));
+    }
+    
+    public static String localUrl(String subgroupUnderIoBrooklyn, String artifactId, String packaging) {
+        return MavenRetriever.localUrl(artifact(subgroupUnderIoBrooklyn, artifactId, packaging));
+    }
+
+    public static String hostedUrlForJar(String artifactId) {
+        return MavenRetriever.hostedUrl(jar(artifactId));
+    }
+    
+    public static String hostedUrl(String subgroupUnderIoBrooklyn, String artifactId, String packaging) {
+        return MavenRetriever.hostedUrl(artifact(subgroupUnderIoBrooklyn, artifactId, packaging));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/BrooklynNetworkUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/BrooklynNetworkUtils.java b/core/src/main/java/org/apache/brooklyn/core/util/BrooklynNetworkUtils.java
new file mode 100644
index 0000000..7240425
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/BrooklynNetworkUtils.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util;
+
+import java.net.InetAddress;
+
+import brooklyn.config.BrooklynServiceAttributes;
+
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.location.geo.LocalhostExternalIpLoader;
+
+import brooklyn.util.JavaGroovyEquivalents;
+import brooklyn.util.net.Networking;
+
+public class BrooklynNetworkUtils {
+
+    /** returns the externally-facing IP address from which this host comes, or 127.0.0.1 if not resolvable */
+    public static String getLocalhostExternalIp() {
+        return LocalhostExternalIpLoader.getLocalhostIpQuicklyOrDefault();
+    }
+
+    /** returns a IP address for localhost paying attention to a system property to prevent lookup in some cases */ 
+    public static InetAddress getLocalhostInetAddress() {
+        return TypeCoercions.coerce(JavaGroovyEquivalents.elvis(BrooklynServiceAttributes.LOCALHOST_IP_ADDRESS.getValue(), 
+                Networking.getLocalHost()), InetAddress.class);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/ResourceUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/ResourceUtils.java b/core/src/main/java/org/apache/brooklyn/core/util/ResourceUtils.java
new file mode 100644
index 0000000..bbd88d5
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/ResourceUtils.java
@@ -0,0 +1,639 @@
+/*
+ * 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.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.api.management.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
+import org.apache.brooklyn.core.internal.BrooklynInitialization;
+import org.apache.brooklyn.core.management.classloading.JavaBrooklynClassLoadingContext;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpTool.HttpClientBuilder;
+import org.apache.brooklyn.core.util.text.DataUriSchemeParser;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.javalang.Threads;
+import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+
+public class ResourceUtils {
+    
+    private static final Logger log = LoggerFactory.getLogger(ResourceUtils.class);
+    private static final List<Function<Object,BrooklynClassLoadingContext>> classLoaderProviders = Lists.newCopyOnWriteArrayList();
+
+    private BrooklynClassLoadingContext loader = null;
+    private String context = null;
+    private Object contextObject = null;
+    
+    static { BrooklynInitialization.initNetworking(); }
+    
+    /**
+     * Creates a {@link ResourceUtils} object with a specific class loader and context.
+     * <p>
+     * Use the provided {@link ClassLoader} object for class loading with the
+     * {@code contextObject} for context and the {@code contextMessage} string for
+     * error messages.
+     *
+     * @see ResourceUtils#create(Object, String)
+     * @see ResourceUtils#create(Object)
+     */
+    public static final ResourceUtils create(ClassLoader loader, Object contextObject, String contextMessage) {
+        return new ResourceUtils(loader, contextObject, contextMessage);
+    }
+
+    /**
+     * Creates a {@link ResourceUtils} object with a specific class loader and context.
+     * <p>
+     * Use the provided {@link BrooklynClassLoadingContext} object for class loading with the
+     * {@code contextObject} for context and the {@code contextMessage} string for
+     * error messages.
+     *
+     * @see ResourceUtils#create(Object, String)
+     * @see ResourceUtils#create(Object)
+     */
+    public static final ResourceUtils create(BrooklynClassLoadingContext loader, Object contextObject, String contextMessage) {
+        return new ResourceUtils(loader, contextObject, contextMessage);
+    }
+
+    /**
+     * Creates a {@link ResourceUtils} object with the given context.
+     * <p>
+     * Uses the {@link ClassLoader} of the given {@code contextObject} for class
+     * loading and the {@code contextMessage} string for error messages.
+     *
+     * @see ResourceUtils#create(ClassLoader, Object, String)
+     * @see ResourceUtils#create(Object)
+     */
+    public static final ResourceUtils create(Object contextObject, String contextMessage) {
+        return new ResourceUtils(contextObject, contextMessage);
+    }
+
+    /**
+     * Creates a {@link ResourceUtils} object with the given context.
+     * <p>
+     * Uses the {@link ClassLoader} of the given {@code contextObject} for class
+     * loading and its {@link Object#toString()} (preceded by the word 'for') as
+     * the string used in error messages.
+     *
+     * @see ResourceUtils#create(ClassLoader, Object, String)
+     * @see ResourceUtils#create(Object)
+     */
+    public static final ResourceUtils create(Object contextObject) {
+        return new ResourceUtils(contextObject);
+    }
+
+    /**
+     * Creates a {@link ResourceUtils} object with itself as the context.
+     *
+     * @see ResourceUtils#create(Object)
+     */
+    public static final ResourceUtils create() {
+        return new ResourceUtils(null);
+    }
+
+    public ResourceUtils(ClassLoader loader, Object contextObject, String contextMessage) {
+        this(getClassLoadingContextInternal(loader, contextObject), contextObject, contextMessage);
+    }
+    
+    public ResourceUtils(BrooklynClassLoadingContext loader, Object contextObject, String contextMessage) {
+        this.loader = loader;
+        this.contextObject = contextObject;
+        this.context = contextMessage;
+    }
+
+    public ResourceUtils(Object contextObject, String contextMessage) {
+        this(contextObject==null ? null : getClassLoadingContextInternal(null, contextObject), contextObject, contextMessage);
+    }
+
+    public ResourceUtils(Object contextObject) {
+        this(contextObject, Strings.toString(contextObject));
+    }
+    
+    /** used to register custom mechanisms for getting classloaders given an object */
+    public static void addClassLoaderProvider(Function<Object,BrooklynClassLoadingContext> provider) {
+        classLoaderProviders.add(provider);
+    }
+    
+    // TODO rework this class so it accepts but does not require a BCLC ?
+    @SuppressWarnings("deprecation")
+    protected static BrooklynClassLoadingContext getClassLoadingContextInternal(ClassLoader loader, Object contextObject) {
+        if (contextObject instanceof BrooklynClassLoadingContext)
+            return (BrooklynClassLoadingContext) contextObject;
+        
+        for (Function<Object,BrooklynClassLoadingContext> provider: classLoaderProviders) {
+            BrooklynClassLoadingContext result = provider.apply(contextObject);
+            if (result!=null) return result;
+        }
+
+        BrooklynClassLoadingContext bl = BrooklynLoaderTracker.getLoader();
+        ManagementContext mgmt = (bl!=null ? bl.getManagementContext() : null);
+
+        ClassLoader cl = loader;
+        if (cl==null) cl = contextObject instanceof Class ? ((Class<?>)contextObject).getClassLoader() : 
+            contextObject instanceof ClassLoader ? ((ClassLoader)contextObject) : 
+                contextObject.getClass().getClassLoader();
+            
+        return JavaBrooklynClassLoadingContext.create(mgmt, cl);
+    }
+    
+    /** This should not be exposed as it risks it leaking into places where it would be serialized.
+     * Better for callers use {@link CatalogUtils#getClassLoadingContext(org.apache.brooklyn.api.entity.Entity)} or similar. }.
+     */
+    private BrooklynClassLoadingContext getLoader() {
+        return (loader!=null ? loader : getClassLoadingContextInternal(null, contextObject!=null ? contextObject : this));
+    }
+
+    /**
+     * @return all resources in Brooklyn's {@link BrooklynClassLoadingContext} with the given name.
+     */
+    public Iterable<URL> getResources(String name) {
+        return getLoader().getResources(name);
+    }
+    
+    /**
+     * Takes a string which is treated as a URL (with some extended "schemes" also expected),
+     * or as a path to something either on the classpath (absolute only) or the local filesystem (relative or absolute, depending on leading slash)
+     * <p>
+     * URLs can be of the form <b>classpath://com/acme/Foo.properties</b>
+     * as well as <b>file:///home/...</b> and <b>http://acme.com/...</b>.
+     * <p>
+     * Throws exception if not found, using the context parameter passed into the constructor.
+     * <p>
+     * TODO may want OSGi, or typed object; should consider pax url
+     * 
+     * @return a stream, or throws exception (never returns null)
+     */
+    public InputStream getResourceFromUrl(String url) {
+        try {
+            if (url==null) throw new NullPointerException("Cannot read from null");
+            if (url=="") throw new NullPointerException("Cannot read from empty string");
+            String orig = url;
+            String protocol = Urls.getProtocol(url);
+            if (protocol!=null) {
+                if ("classpath".equals(protocol)) {
+                    try {
+                        return getResourceViaClasspath(url);
+                    } catch (IOException e) {
+                        //catch the above because both orig and modified url may be interesting
+                        throw new IOException("Error accessing "+orig+": "+e, e);
+                    }
+                }
+                if ("sftp".equals(protocol)) {
+                    try {
+                        return getResourceViaSftp(url);
+                    } catch (IOException e) {
+                        throw new IOException("Error accessing "+orig+": "+e, e);
+                    }
+                }
+
+                if ("file".equals(protocol))
+                    url = tidyFileUrl(url);
+                
+                if ("data".equals(protocol)) {
+                    return new DataUriSchemeParser(url).lax().parse().getDataAsInputStream();
+                }
+
+                if ("http".equals(protocol) || "https".equals(protocol)) {
+                    return getResourceViaHttp(url);
+                }
+
+                return new URL(url).openStream();
+            }
+
+            try {
+                //try as classpath reference, then as file
+                try {
+                    URL u = getLoader().getResource(url);
+                    if (u!=null) return u.openStream();
+                } catch (IllegalArgumentException e) {
+                    //Felix installs an additional URL to the system classloader
+                    //which throws an IllegalArgumentException when passed a
+                    //windows path. See ExtensionManager.java static initializer.
+
+                    //ignore, not a classpath resource
+                }
+                if (url.startsWith("/")) {
+                    //some getResource calls fail if argument starts with /
+                    String urlNoSlash = url;
+                    while (urlNoSlash.startsWith("/")) urlNoSlash = urlNoSlash.substring(1);
+                    URL u = getLoader().getResource(urlNoSlash);
+                    if (u!=null) return u.openStream();
+//                    //Class.getResource can require a /  (else it attempts to be relative) but Class.getClassLoader doesn't
+//                    u = getLoader().getResource("/"+urlNoSlash);
+//                    if (u!=null) return u.openStream();
+                }
+                File f;
+                // but first, if it starts with tilde, treat specially
+                if (url.startsWith("~/")) {
+                    f = new File(Os.home(), url.substring(2));
+                } else if (url.startsWith("~\\")) {
+                    f = new File(Os.home(), url.substring(2));
+                } else {
+                    f = new File(url);
+                }
+                if (f.exists()) return new FileInputStream(f);
+            } catch (IOException e) {
+                //catch the above because both u and modified url will be interesting
+                throw new IOException("Error accessing "+orig+": "+e, e);
+            }
+            throw new IOException("'"+orig+"' not found on classpath or filesystem");
+        } catch (Exception e) {
+            if (context!=null) {
+                throw new RuntimeException("Error getting resource '"+url+"' for "+context+": "+e, e);
+            } else {
+                throw Exceptions.propagate(e);
+            }
+        }
+    }
+    
+    private final static Pattern pattern = Pattern.compile("^file:/*~/+(.*)$");
+
+    public static URL tidy(URL url) {
+        // File class has helpful methods for URIs but not URLs. So we convert.
+        URI in;
+        try {
+            in = url.toURI();
+        } catch (URISyntaxException e) {
+            throw Exceptions.propagate(e);
+        }
+        URI out;
+
+        Matcher matcher = pattern.matcher(in.toString());
+        if (matcher.matches()) {
+            // home-relative
+            File home = new File(Os.home());
+            File file = new File(home, matcher.group(1));
+            out = file.toURI();
+        } else if (in.getScheme().equals("file:")) {
+            // some other file, so canonicalize
+            File file = new File(in);
+            out = file.toURI();
+        } else {
+            // some other scheme, so no-op
+            out = in;
+        }
+
+        URL urlOut;
+        try {
+            urlOut = out.toURL();
+        } catch (MalformedURLException e) {
+            throw Exceptions.propagate(e);
+        }
+        if (!urlOut.equals(url) && log.isDebugEnabled()) {
+            log.debug("quietly changing " + url + " to " + urlOut);
+        }
+        return urlOut;
+    }
+    
+    public static String tidyFileUrl(String url) {
+        try {
+            return tidy(new URL(url)).toString();
+        } catch (MalformedURLException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    /** @deprecated since 0.7.0; use method {@link Os#mergePaths(String...)} */ @Deprecated
+    public static String mergeFilePaths(String... items) {
+        return Os.mergePaths(items);
+    }
+    
+    /** @deprecated since 0.7.0; use method {@link Os#tidyPath(String)} */ @Deprecated
+    public static String tidyFilePath(String path) {
+        return Os.tidyPath(path);
+    }
+    
+    /** @deprecated since 0.7.0; use method {@link Urls#getProtocol(String)} */ @Deprecated
+    public static String getProtocol(String url) {
+        return Urls.getProtocol(url);
+    }
+    
+    private InputStream getResourceViaClasspath(String url) throws IOException {
+        assert url.startsWith("classpath:");
+        String subUrl = url.substring("classpath:".length());
+        while (subUrl.startsWith("/")) subUrl = subUrl.substring(1);
+        URL u = getLoader().getResource(subUrl);
+        if (u!=null) return u.openStream();
+        else throw new IOException(subUrl+" not found on classpath");
+    }
+    
+    private InputStream getResourceViaSftp(String url) throws IOException {
+        assert url.startsWith("sftp://");
+        String subUrl = url.substring("sftp://".length());
+        String user;
+        String address;
+        String path;
+        int atIndex = subUrl.indexOf("@");
+        int colonIndex = subUrl.indexOf(":", (atIndex > 0 ? atIndex : 0));
+        if (colonIndex <= 0 || colonIndex <= atIndex) {
+            throw new IllegalArgumentException("Invalid sftp url ("+url+"); IP or hostname must be specified, such as sftp://localhost:/path/to/file");
+        }
+        if (subUrl.length() <= (colonIndex+1)) {
+            throw new IllegalArgumentException("Invalid sftp url ("+url+"); must specify path of remote file, such as sftp://localhost:/path/to/file");
+        }
+        if (atIndex >= 0) {
+            user = subUrl.substring(0, atIndex);
+        } else {
+            user = null;
+        }
+        address = subUrl.substring(atIndex + 1, colonIndex);
+        path = subUrl.substring(colonIndex+1);
+        
+        // TODO messy way to get an SCP session 
+        SshMachineLocation machine = new SshMachineLocation(MutableMap.builder()
+                .putIfNotNull("user", user)
+                .put("address", InetAddress.getByName(address))
+                .build());
+        try {
+            final File tempFile = Os.newTempFile("brooklyn-sftp", "tmp");
+            tempFile.setReadable(true, true);
+            machine.copyFrom(path, tempFile.getAbsolutePath());
+            return new FileInputStream(tempFile) {
+                @Override
+                public void close() throws IOException {
+                    super.close();
+                    tempFile.delete();
+                }
+            };
+        } finally {
+            Streams.closeQuietly(machine);
+        }
+    }
+    
+    //For HTTP(S) targets use HttpClient so
+    //we can do authentication
+    private InputStream getResourceViaHttp(String resource) throws IOException {
+        URI uri = URI.create(resource);
+        HttpClientBuilder builder = HttpTool.httpClientBuilder()
+                .laxRedirect(true)
+                .uri(uri);
+        Credentials credentials = getUrlCredentials(uri.getRawUserInfo());
+        if (credentials != null) {
+            builder.credentials(credentials);
+        }
+        HttpClient client = builder.build();
+        HttpResponse result = client.execute(new HttpGet(resource));
+        int statusCode = result.getStatusLine().getStatusCode();
+        if (HttpTool.isStatusCodeHealthy(statusCode)) {
+            HttpEntity entity = result.getEntity();
+            if (entity != null) {
+                return entity.getContent();
+            } else {
+                return new ByteArrayInputStream(new byte[0]);
+            }
+        } else {
+            EntityUtils.consume(result.getEntity());
+            throw new IllegalStateException("Invalid response invoking " + resource + ": response code " + statusCode);
+        }
+    }
+
+    private Credentials getUrlCredentials(String userInfo) {
+        if (userInfo != null) {
+            String[] arr = userInfo.split(":");
+            String username;
+            String password = null;
+            if (arr.length == 1) {
+                username = urlDecode(arr[0]);
+            } else if (arr.length == 2) {
+                username = urlDecode(arr[0]);
+                password = urlDecode(arr[1]);
+            } else {
+                return null;
+            }
+            return new UsernamePasswordCredentials(username, password);
+        } else {
+            return null;
+        }
+    }
+
+    private String urlDecode(String str) {
+        try {
+            return URLDecoder.decode(str, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    /** takes {@link #getResourceFromUrl(String)} and reads fully, into a string */
+    public String getResourceAsString(String url) {
+        try {
+            return readFullyString(getResourceFromUrl(url));
+        } catch (Exception e) {
+            log.debug("ResourceUtils got error reading "+url+(context==null?"":" "+context)+" (rethrowing): "+e);
+            throw Throwables.propagate(e);
+        }
+    }
+
+    /** allows failing-fast if URL cannot be read */
+    public String checkUrlExists(String url) {
+        return checkUrlExists(url, null);
+    }
+    
+    public String checkUrlExists(String url, String message) {
+        if (url==null) throw new NullPointerException("URL "+(message!=null ? message+" " : "")+"must not be null");
+        InputStream s;
+        try {
+            s = getResourceFromUrl(url);
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            throw new IllegalArgumentException("Unable to access URL "+(message!=null ? message : "")+": "+url, e);
+        }
+        Streams.closeQuietly(s); 
+        return url;
+    }
+
+    /** tests whether the url exists, returning true or false */
+    public boolean doesUrlExist(String url) {
+        InputStream s = null;
+        try {
+            s = getResourceFromUrl(url);
+            return true;
+        } catch (Exception e) {
+            return false;
+        } finally {
+            Streams.closeQuietly(s);
+        }
+    }
+    
+    /** returns the first available URL */
+    public Optional<String> firstAvailableUrl(String ...urls) {
+        for (String url: urls) {
+            if (doesUrlExist(url)) return Optional.of(url);
+        }
+        return Optional.absent();
+    }
+    
+    /** returns the base directory or JAR from which the context is class-loaded, if possible;
+     * throws exception if not found */
+    public String getClassLoaderDir() {
+        if (contextObject==null) throw new IllegalArgumentException("No suitable context ("+context+") to auto-detect classloader dir");
+        Class<?> cc = contextObject instanceof Class ? (Class<?>)contextObject : contextObject.getClass();
+        return getClassLoaderDir(cc.getCanonicalName().replace('.', '/')+".class");
+    }
+    
+    public String getClassLoaderDir(String resourceInThatDir) {
+        resourceInThatDir = Strings.removeFromStart(resourceInThatDir, "/");
+        URL resourceUrl = getLoader().getResource(resourceInThatDir);
+        if (resourceUrl==null) throw new NoSuchElementException("Resource ("+resourceInThatDir+") not found");
+
+        URL containerUrl = getContainerUrl(resourceUrl, resourceInThatDir);
+
+        if (!"file".equals(containerUrl.getProtocol())) throw new IllegalStateException("Resource ("+resourceInThatDir+") not on file system (at "+containerUrl+")");
+
+        //convert from file: URL to File
+        File file;
+        try {
+            file = new File(containerUrl.toURI());
+        } catch (URISyntaxException e) {
+            throw new IllegalStateException("Resource ("+resourceInThatDir+") found at invalid URI (" + containerUrl + ")", e);
+        }
+        
+        if (!file.exists()) throw new IllegalStateException("Context class url substring ("+containerUrl+") not found on filesystem");
+        return file.getPath();
+        
+    }
+
+    public static URL getContainerUrl(URL url, String resourceInThatDir) {
+        //Switching from manual parsing of jar: and file: URLs to java provided functionality.
+        //The old code was breaking on any Windows path and instead of fixing it, using
+        //the provided Java APIs seemed like the better option since they are already tested
+        //on multiple platforms.
+        boolean isJar = "jar".equals(url.getProtocol());
+        if(isJar) {
+            try {
+                //let java handle the parsing of jar URL, no network connection is established.
+                //Strips the jar protocol:
+                //  jar:file:/<path to jar>!<resourceInThatDir>
+                //  becomes
+                //  file:/<path to jar>
+                JarURLConnection connection = (JarURLConnection) url.openConnection();
+                url = connection.getJarFileURL();
+            } catch (IOException e) {
+                throw new IllegalStateException(e);
+            }
+        } else {
+            //Remove the trailing resouceInThatDir path from the URL, thus getting the parent folder.
+            String path = url.toString();
+            int i = path.indexOf(resourceInThatDir);
+            if (i==-1) throw new IllegalStateException("Resource path ("+resourceInThatDir+") not in url substring ("+url+")");
+            String parent = path.substring(0, i);
+            try {
+                url = new URL(parent);
+            } catch (MalformedURLException e) {
+                throw new IllegalStateException("Resource ("+resourceInThatDir+") found at invalid URL parent (" + parent + ")", e);
+            }
+        }
+        return url;
+    }
+    
+    /** @deprecated since 0.7.0 use {@link Streams#readFullyString(InputStream) */ @Deprecated
+    public static String readFullyString(InputStream is) throws IOException {
+        return Streams.readFullyString(is);
+    }
+
+    /** @deprecated since 0.7.0 use {@link Streams#readFully(InputStream) */ @Deprecated
+    public static byte[] readFullyBytes(InputStream is) throws IOException {
+        return Streams.readFully(is);
+    }
+    
+    /** @deprecated since 0.7.0 use {@link Streams#copy(InputStream, OutputStream)} */ @Deprecated
+    public static void copy(InputStream input, OutputStream output) throws IOException {
+        Streams.copy(input, output);
+    }
+
+    /** @deprecated since 0.7.0; use same method in {@link Os} */ @Deprecated
+    public static File mkdirs(File dir) {
+        return Os.mkdirs(dir);
+    }
+
+    /** @deprecated since 0.7.0; use same method in {@link Os} */ @Deprecated
+    public static File writeToTempFile(InputStream is, String prefix, String suffix) {
+        return Os.writeToTempFile(is, prefix, suffix);
+    }
+    
+    /** @deprecated since 0.7.0; use same method in {@link Os} */ @Deprecated
+    public static File writeToTempFile(InputStream is, File tempDir, String prefix, String suffix) {
+        return Os.writeToTempFile(is, tempDir, prefix, suffix);
+    }
+
+    /** @deprecated since 0.7.0; use method {@link Os#writePropertiesToTempFile(Properties, String, String)} */ @Deprecated
+    public static File writeToTempFile(Properties props, String prefix, String suffix) {
+        return Os.writePropertiesToTempFile(props, prefix, suffix);
+    }
+    
+    /** @deprecated since 0.7.0; use method {@link Os#writePropertiesToTempFile(Properties, File, String, String)} */ @Deprecated
+    public static File writeToTempFile(Properties props, File tempDir, String prefix, String suffix) {
+        return Os.writePropertiesToTempFile(props, tempDir, prefix, suffix);
+    }
+
+    /** @deprecated since 0.7.0; use method {@link Threads#addShutdownHook(Runnable)} */ @Deprecated
+    public static Thread addShutdownHook(final Runnable task) {
+        return Threads.addShutdownHook(task);
+    }
+    /** @deprecated since 0.7.0; use method {@link Threads#removeShutdownHook(Thread)} */ @Deprecated
+    public static boolean removeShutdownHook(Thread hook) {
+        return Threads.removeShutdownHook(hook);
+    }
+
+    /** returns the items with exactly one "/" between items (whether or not the individual items start or end with /),
+     * except where character before the / is a : (url syntax) in which case it will permit multiple (will not remove any) 
+     * @deprecated since 0.7.0 use either {@link Os#mergePathsUnix(String...)} {@link Urls#mergePaths(String...) */ @Deprecated
+    public static String mergePaths(String ...items) {
+        return Urls.mergePaths(items);
+    }
+}


[15/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/qa/performance/TaskPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/qa/performance/TaskPerformanceTest.java b/core/src/test/java/brooklyn/qa/performance/TaskPerformanceTest.java
index 6e4a0d0..c940a36 100644
--- a/core/src/test/java/brooklyn/qa/performance/TaskPerformanceTest.java
+++ b/core/src/test/java/brooklyn/qa/performance/TaskPerformanceTest.java
@@ -26,6 +26,8 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.SingleThreadedScheduler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.BeforeMethod;
@@ -33,8 +35,6 @@ import org.testng.annotations.Test;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.BasicExecutionManager;
-import brooklyn.util.task.SingleThreadedScheduler;
 import brooklyn.util.time.Time;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/test/HttpService.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/test/HttpService.java b/core/src/test/java/brooklyn/test/HttpService.java
index 2710211..80f63f0 100644
--- a/core/src/test/java/brooklyn/test/HttpService.java
+++ b/core/src/test/java/brooklyn/test/HttpService.java
@@ -40,10 +40,10 @@ import org.eclipse.jetty.webapp.WebAppContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.crypto.SecureKeys;
 import brooklyn.util.javalang.Threads;
 import brooklyn.util.os.Os;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/test/policy/TestEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/test/policy/TestEnricher.java b/core/src/test/java/brooklyn/test/policy/TestEnricher.java
index c204c8b..88cc362 100644
--- a/core/src/test/java/brooklyn/test/policy/TestEnricher.java
+++ b/core/src/test/java/brooklyn/test/policy/TestEnricher.java
@@ -23,6 +23,7 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;
 
@@ -30,7 +31,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 public class TestEnricher extends AbstractEnricher {
     @SetFromFlag("confName")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/test/policy/TestPolicy.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/test/policy/TestPolicy.java b/core/src/test/java/brooklyn/test/policy/TestPolicy.java
index b93450c..184eb4e 100644
--- a/core/src/test/java/brooklyn/test/policy/TestPolicy.java
+++ b/core/src/test/java/brooklyn/test/policy/TestPolicy.java
@@ -22,12 +22,12 @@ import java.util.Collections;
 import java.util.Map;
 
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.policy.basic.AbstractPolicy;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/BrooklynMavenArtifactsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/BrooklynMavenArtifactsTest.java b/core/src/test/java/brooklyn/util/BrooklynMavenArtifactsTest.java
deleted file mode 100644
index 0fcfdf7..0000000
--- a/core/src/test/java/brooklyn/util/BrooklynMavenArtifactsTest.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 brooklyn.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import brooklyn.test.Asserts;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.maven.MavenArtifact;
-import brooklyn.util.maven.MavenRetriever;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-@Test
-public class BrooklynMavenArtifactsTest {
-
-    private static final Logger log = LoggerFactory.getLogger(BrooklynMavenArtifactsTest.class);
-    
-    @Test(groups="Integration")
-    public void testUtilsCommon() {
-        ResourceUtils.create(this).checkUrlExists(BrooklynMavenArtifacts.localUrlForJar("brooklyn-utils-common"));
-    }
-
-    @Test(groups="Integration")
-    public void testExampleWar() {
-        String url = BrooklynMavenArtifacts.localUrl("example", "brooklyn-example-hello-world-sql-webapp", "war");
-        ResourceUtils.create(this).checkUrlExists(url);
-        log.info("found example war at: "+url);
-    }
-
-    @Test(groups="Integration")
-    // runs without internet but doesn't assert what it should, and can take a long time, so integration
-    public void testBadExampleWar() {
-        String url = BrooklynMavenArtifacts.localUrl("example", "brooklyn-example-GOODBYE-world-sql-webapp", "war");
-        Assert.assertFalse(ResourceUtils.create(this).doesUrlExist(url), "should not exist: "+url);
-    }
-
-    public void testHostedIsHttp() {
-        String common = BrooklynMavenArtifacts.hostedUrlForJar("brooklyn-utils-common");
-        log.info("online should be at: "+common);
-        Assert.assertTrue(common.startsWith("http"));
-    }
-
-    @Test(groups="Integration")
-    public void testHistoricHosted() {
-        // NB: this should be a version known to be up at sonatype or maven central, NOT necessarily the current version!
-        String snapshot = MavenRetriever.hostedUrl(MavenArtifact.fromCoordinate("org.apache.brooklyn:brooklyn-utils-common:jar:0.7.0-SNAPSHOT"));
-        log.info("Sample snapshot URL is: "+snapshot);
-        checkValidArchive(snapshot);
-        ResourceUtils.create(this).checkUrlExists(snapshot);
-        
-        // NB: this should be a version known to be up at sonatype or maven central, NOT necessarily the current version!
-        String release = MavenRetriever.hostedUrl(MavenArtifact.fromCoordinate("io.brooklyn:brooklyn-utils-common:jar:0.6.0"));
-        log.info("Sample release URL is: "+release);
-        checkValidArchive(release);
-    }
-
-    private void checkValidArchive(final String url) {
-        // Note have seen response code 500 from repository.apache.org, for
-        //   https://repository.apache.org/service/local/artifact/maven/redirect?r=snapshots&v=0.7.0-SNAPSHOT&g=org.apache.brooklyn&a=brooklyn-utils-common&e=jar
-        // Therefore willing to retry, rather than failing immediately.
-        Asserts.succeedsEventually(new Runnable() {
-            @Override public void run() {
-                try {
-                    byte[] bytes = Streams.readFully(ResourceUtils.create(this).getResourceFromUrl(url));
-                    // confirm this follow redirects!
-                    Assert.assertTrue(bytes.length > 100*1000, "download of "+url+" is suspect ("+Strings.makeSizeString(bytes.length)+")");
-                    // (could also check it is a zip etc)
-                } catch (Exception e) {
-                    throw Exceptions.propagate(e);
-                }
-            }});
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/ResourceUtilsHttpTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/ResourceUtilsHttpTest.java b/core/src/test/java/brooklyn/util/ResourceUtilsHttpTest.java
deleted file mode 100644
index daac00a..0000000
--- a/core/src/test/java/brooklyn/util/ResourceUtilsHttpTest.java
+++ /dev/null
@@ -1,196 +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 brooklyn.util;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.http.HttpException;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.localserver.RequestBasicAuth;
-import org.apache.http.localserver.ResponseBasicUnauthorized;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.protocol.HttpRequestHandler;
-import org.apache.http.protocol.ResponseServer;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import brooklyn.test.TestHttpRequestHandler;
-import brooklyn.test.TestHttpServer;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.text.Strings;
-
-public class ResourceUtilsHttpTest {
-    private ResourceUtils utils;
-    private TestHttpServer server;
-    private String baseUrl;
-
-    @BeforeClass(alwaysRun=true)
-    public void setUp() throws Exception {
-        utils = ResourceUtils.create(this, "mycontext");
-        server = new TestHttpServer()
-            .interceptor(new ResponseServer())
-            .interceptor(new ResponseBasicUnauthorized())
-            .interceptor(new RequestBasicAuth())
-            .handler("/simple", new TestHttpRequestHandler().response("OK"))
-            .handler("/empty", new TestHttpRequestHandler().code(HttpStatus.SC_NO_CONTENT))
-            .handler("/missing", new TestHttpRequestHandler().code(HttpStatus.SC_NOT_FOUND).response("Missing"))
-            .handler("/redirect", new TestHttpRequestHandler().code(HttpStatus.SC_MOVED_TEMPORARILY).response("Redirect").header("Location", "/simple"))
-            .handler("/cycle", new TestHttpRequestHandler().code(HttpStatus.SC_MOVED_TEMPORARILY).response("Redirect").header("Location", "/cycle"))
-            .handler("/secure", new TestHttpRequestHandler().code(HttpStatus.SC_MOVED_TEMPORARILY).response("Redirect").header("Location", "https://0.0.0.0/"))
-            .handler("/auth", new AuthHandler("test", "test", "OK"))
-            .handler("/auth_escape", new AuthHandler("test@me:/", "test", "OK"))
-            .handler("/auth_escape2", new AuthHandler("test@me:test", "", "OK"))
-            .handler("/no_credentials", new CheckNoCredentials())
-            .start();
-        baseUrl = server.getUrl();
-    }
-
-    @AfterClass(alwaysRun=true)
-    public void tearDown() throws Exception {
-        server.stop();
-    }
-
-    @Test
-    public void testGet() throws Exception {
-        InputStream stream = utils.getResourceFromUrl(baseUrl + "/simple");
-        assertEquals(Streams.readFullyString(stream), "OK");
-    }
-
-    @Test
-    public void testGetEmpty() throws Exception {
-        InputStream stream = utils.getResourceFromUrl(baseUrl + "/empty");
-        assertEquals(Streams.readFullyString(stream), "");
-    }
-
-    @Test
-    public void testGetProtected() throws Exception {
-        String url = baseUrl.replace("http://", "http://test:test@") + "/auth";
-        InputStream stream = utils.getResourceFromUrl(url);
-        assertEquals(Streams.readFullyString(stream), "OK");
-    }
-
-    @Test
-    public void testGetProtectedEscape() throws Exception {
-        String url = baseUrl.replace("http://", "http://test%40me%3A%2F:test@") + "/auth_escape";
-        InputStream stream = utils.getResourceFromUrl(url);
-        assertEquals(Streams.readFullyString(stream), "OK");
-    }
-
-    @Test
-    public void testGetProtectedEscape2() throws Exception {
-        String url = baseUrl.replace("http://", "http://test%40me%3Atest@") + "/auth_escape2";
-        InputStream stream = utils.getResourceFromUrl(url);
-        assertEquals(Streams.readFullyString(stream), "OK");
-    }
-
-    @Test(expectedExceptions = RuntimeException.class)
-    public void testProtectedFailsWithoutCredentials() throws Exception {
-        utils.getResourceFromUrl(baseUrl + "/auth");
-    }
-
-    @Test
-    public void testInvalidCredentialsNotPassed() throws Exception {
-        String url = baseUrl + "/no_credentials?no:auth@needed";
-        InputStream stream = utils.getResourceFromUrl(url);
-        assertEquals(Streams.readFullyString(stream), "OK");
-    }
-
-    @Test
-    public void testRedirect() throws Exception {
-        InputStream stream = utils.getResourceFromUrl(baseUrl + "/redirect");
-        assertEquals(Streams.readFullyString(stream), "OK");
-    }
-
-    @Test(expectedExceptions = RuntimeException.class)
-    public void testCycleRedirect() throws Exception {
-        InputStream stream = utils.getResourceFromUrl(baseUrl + "/cycle");
-        assertEquals(Streams.readFullyString(stream), "OK");
-    }
-
-    @Test(expectedExceptions = RuntimeException.class)
-    public void testGetMissing() throws Exception {
-        utils.getResourceFromUrl(baseUrl + "/missing");
-    }
-
-    @Test(expectedExceptions = RuntimeException.class)
-    public void testFollowsProtoChange() throws Exception {
-        utils.getResourceFromUrl(baseUrl + "/secure");
-    }
-
-    // See https://github.com/brooklyncentral/brooklyn/issues/1338
-    @Test(groups={"Integration"})
-    public void testResourceFromUrlFollowsRedirect() throws Exception {
-        String contents = new ResourceUtils(this).getResourceAsString("http://bit.ly/brooklyn-visitors-creation-script");
-        assertFalse(contents.contains("bit.ly"), "contents="+contents);
-    }
-
-    private static class AuthHandler implements HttpRequestHandler {
-        private String username;
-        private String password;
-        private String responseBody;
-
-        public AuthHandler(String username, String password, String response) {
-            this.username = username;
-            this.password = password;
-            this.responseBody = response;
-        }
-
-        @Override
-        public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
-            String creds = (String) context.getAttribute("creds");
-            if (creds == null || !creds.equals(getExpectedCredentials())) {
-                response.setStatusCode(HttpStatus.SC_UNAUTHORIZED);
-            } else {
-                response.setEntity(new StringEntity(responseBody));
-            }
-        }
-
-        private String getExpectedCredentials() {
-            if (Strings.isEmpty(password)) {
-                return username;
-            } else {
-                return username + ":" + password;
-            }
-        }
-
-    }
-
-    private static class CheckNoCredentials implements HttpRequestHandler {
-
-        @Override
-        public void handle(HttpRequest request, HttpResponse response,
-                HttpContext context) throws HttpException, IOException {
-            String creds = (String) context.getAttribute("creds");
-            if (creds == null) {
-                response.setEntity(new StringEntity("OK"));
-            } else {
-                response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
-            }
-        }
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/ResourceUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/ResourceUtilsTest.java b/core/src/test/java/brooklyn/util/ResourceUtilsTest.java
deleted file mode 100644
index de54ebb..0000000
--- a/core/src/test/java/brooklyn/util/ResourceUtilsTest.java
+++ /dev/null
@@ -1,189 +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 brooklyn.util;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Properties;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import brooklyn.util.net.Urls;
-import brooklyn.util.os.Os;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.text.Identifiers;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.io.Files;
-
-public class ResourceUtilsTest {
-
-    private static final Logger log = LoggerFactory.getLogger(ResourceUtilsTest.class);
-    
-    private String tempFileContents = "abc";
-    private ResourceUtils utils;
-    private File tempFile;
-    
-    @BeforeClass(alwaysRun=true)
-    public void setUp() throws Exception {
-        utils = ResourceUtils.create(this, "mycontext");
-        tempFile = Os.writeToTempFile(new ByteArrayInputStream(tempFileContents.getBytes()), "resourceutils-test", ".txt");
-    }
-    
-    @AfterClass(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (tempFile != null) tempFile.delete();
-    }
-
-    @Test
-    public void testWriteStreamToTempFile() throws Exception {
-        File tempFileLocal = Os.writeToTempFile(new ByteArrayInputStream("mycontents".getBytes()), "resourceutils-test", ".txt");
-        try {
-            List<String> lines = Files.readLines(tempFileLocal, Charsets.UTF_8);
-            assertEquals(lines, ImmutableList.of("mycontents"));
-        } finally {
-            tempFileLocal.delete();
-        }
-    }
-
-    @Test
-    public void testPropertiesStreamToTempFile() throws Exception {
-        Properties props = new Properties();
-        props.setProperty("mykey", "myval");
-        File tempFileLocal = Os.writePropertiesToTempFile(props, "resourceutils-test", ".txt");
-        FileInputStream fis = null;
-        try {
-            fis = new FileInputStream(tempFileLocal);
-            Properties props2 = new Properties();
-            props2.load(fis);
-            assertEquals(props2.getProperty("mykey"), "myval");
-        } finally {
-            Streams.closeQuietly(fis);
-            tempFileLocal.delete();
-        }
-    }
-
-    @Test
-    public void testGetResourceViaClasspathWithPrefix() throws Exception {
-        InputStream stream = utils.getResourceFromUrl("classpath://brooklyn/config/sample.properties");
-        assertNotNull(stream);
-    }
-    
-    @Test
-    public void testGetResourceViaClasspathWithoutPrefix() throws Exception {
-        InputStream stream = utils.getResourceFromUrl("/brooklyn/config/sample.properties");
-        assertNotNull(stream);
-    }
-
-    @Test
-    public void testGetResourceViaFileWithPrefix() throws Exception {
-        // The correct format for file URLs is file:///<absolute path>.
-        // On UNIX file:///tmp.
-        // On Windows both file:/C:/temp and file:///C:/temp are supported by Java, 
-        // while Windows itself supports the latter only. 
-        // Note that file://C:/temp is *wrong*, because C: is interpreted as the host
-        InputStream stream = utils.getResourceFromUrl(tempFile.toURI().toURL().toString());
-        assertEquals(Streams.readFullyString(stream), tempFileContents);
-    }
-    
-    @Test
-    public void testGetResourceViaFileWithoutPrefix() throws Exception {
-        InputStream stream = utils.getResourceFromUrl(tempFile.getAbsolutePath());
-        assertEquals(Streams.readFullyString(stream), tempFileContents);
-    }
-
-    @Test
-    public void testClassLoaderDir() throws Exception {
-        String d = utils.getClassLoaderDir();
-        log.info("Found resource "+this+" in: "+d);
-        assertTrue(new File(d, "brooklyn/util/").exists());
-    }
-
-    @Test
-    public void testClassLoaderDirFromJar() throws Exception {
-        String d = utils.getClassLoaderDir("java/lang/Object.class");
-        log.info("Found Object in: "+d);
-        assertTrue(d.toLowerCase().endsWith(".jar"));
-    }
-
-    @Test
-    public void testClassLoaderDirFromJarWithSlash() throws Exception {
-        String d = utils.getClassLoaderDir("/java/lang/Object.class");
-        log.info("Found Object in: "+d);
-        assertTrue(d.toLowerCase().endsWith(".jar"));
-    }
-
-    @Test(expectedExceptions={NoSuchElementException.class})
-    public void testClassLoaderDirNotFound() throws Exception {
-        String d = utils.getClassLoaderDir("/somewhere/not/found/XXX.xxx");
-        // above should fail
-        log.warn("Uh oh found imaginary resource in: "+d);
-    }
-
-    @Test(groups="Integration")
-    public void testGetResourceViaSftp() throws Exception {
-        InputStream stream = utils.getResourceFromUrl("sftp://localhost:"+tempFile.getAbsolutePath());
-        assertEquals(Streams.readFullyString(stream), tempFileContents);
-    }
-    
-    @Test(groups="Integration")
-    public void testGetResourceViaSftpWithUsername() throws Exception {
-        String user = System.getProperty("user.name");
-        InputStream stream = utils.getResourceFromUrl("sftp://"+user+"@localhost:"+tempFile.getAbsolutePath());
-        assertEquals(Streams.readFullyString(stream), tempFileContents);
-    }
-
-    @Test
-    public void testDataUrl() throws Exception {
-        assertEquals(utils.getResourceAsString("data:,hello"), "hello");
-        assertEquals(utils.getResourceAsString("data:,hello%20world"), "hello world");
-        // above is correct. below are not valid ... but we accept them anyway
-        assertEquals(utils.getResourceAsString("data:hello"), "hello");
-        assertEquals(utils.getResourceAsString("data://hello"), "hello");
-        assertEquals(utils.getResourceAsString("data:hello world"), "hello world");
-        assertEquals(utils.getResourceAsString(Urls.asDataUrlBase64("hello world")), "hello world");
-        
-        String longString = Identifiers.makeRandomId(256);
-        for (int a=32; a<128; a++) longString += (char)a;
-        assertEquals(utils.getResourceAsString(Urls.asDataUrlBase64(longString)), longString);
-    }
-
-    @Test
-    public void testGetResources() {
-        Iterable<URL> manifests = ResourceUtils.create().getResources("META-INF/MANIFEST.MF");
-        assertFalse(Iterables.isEmpty(manifests));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/config/ConfigBagTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/config/ConfigBagTest.java b/core/src/test/java/brooklyn/util/config/ConfigBagTest.java
deleted file mode 100644
index 93cf6ed..0000000
--- a/core/src/test/java/brooklyn/util/config/ConfigBagTest.java
+++ /dev/null
@@ -1,191 +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 brooklyn.util.config;
-
-import static org.testng.Assert.assertEquals;
-
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.time.Duration;
-
-public class ConfigBagTest {
-
-    @SuppressWarnings("unused")
-    private static final Logger log = LoggerFactory.getLogger(ConfigBagTest.class);
-    
-    private static final ConfigKey<String> K1 = ConfigKeys.newStringConfigKey("k1");
-    private static final ConfigKey<String> K2 = ConfigKeys.newStringConfigKey("k2");
-    private static final ConfigKey<String> K3 = ConfigKeys.newStringConfigKey("k3");
-    
-    @Test
-    public void testPutAndGet() {
-        ConfigBag bag = ConfigBag.newInstance();
-        bag.put(K1, "v1");
-        assertEquals(bag.get(K1), "v1");
-    }
-    
-    @Test
-    public void testPutStringAndGet() {
-        ConfigBag bag = ConfigBag.newInstance();
-        bag.putAsStringKey(K1.getName(), "v1");
-        assertEquals(bag.get(K1), "v1");
-    }
-    
-    @Test
-    public void testUnused() {
-        ConfigBag bag = ConfigBag.newInstance();
-        bag.put(K1, "v1");
-        bag.put(K2, "v2a");
-        assertEquals(bag.get(K1), "v1");
-        assertEquals(bag.getUnusedConfig().size(), 1);
-        assertEquals(bag.peek(K2), "v2a");
-        assertEquals(bag.getUnusedConfig().size(), 1);
-        assertEquals(bag.get(K2), "v2a");
-        Assert.assertTrue(bag.getUnusedConfig().isEmpty());
-    }
-
-    @Test
-    public void testOrder() {
-        ConfigBag bag = ConfigBag.newInstance();
-        bag.put(K1, "v1");
-        bag.put(K2, "v2");
-        bag.put(K3, "v3");
-        Assert.assertEquals(MutableList.copyOf(bag.getAllConfig().keySet()), MutableList.of(K1.getName(), K2.getName(), K3.getName()));
-        Assert.assertEquals(MutableList.copyOf(bag.getAllConfig().values()), MutableList.of("v1", "v2", "v3"));
-    }
-        
-    @Test
-    public void testCopyOverwriteAndGet() {
-        ConfigBag bag1 = ConfigBag.newInstance();
-        bag1.put(K1, "v1");
-        bag1.put(K2, "v2a");
-        bag1.put(K3, "v3");
-        assertEquals(bag1.get(K1), "v1");
-        
-        ConfigBag bag2 = ConfigBag.newInstanceCopying(bag1).putAll(MutableMap.of(K2, "v2b"));
-        assertEquals(bag1.getUnusedConfig().size(), 2);
-        assertEquals(bag2.getUnusedConfig().size(), 2);
-        
-        assertEquals(bag2.get(K1), "v1");
-        assertEquals(bag1.get(K2), "v2a");
-        assertEquals(bag1.getUnusedConfig().size(), 1);
-        assertEquals(bag2.getUnusedConfig().size(), 2);
-        
-        assertEquals(bag2.get(K2), "v2b");
-        assertEquals(bag2.getUnusedConfig().size(), 1);
-        
-        assertEquals(bag2.get(K3), "v3");
-        assertEquals(bag2.getUnusedConfig().size(), 0);
-        assertEquals(bag1.getUnusedConfig().size(), 1);
-    }
-    
-    @Test
-    public void testCopyExtendingAndGet() {
-        ConfigBag bag1 = ConfigBag.newInstance();
-        bag1.put(K1, "v1");
-        bag1.put(K2, "v2a");
-        bag1.put(K3, "v3");
-        assertEquals(bag1.get(K1), "v1");
-        
-        ConfigBag bag2 = ConfigBag.newInstanceExtending(bag1, null).putAll(MutableMap.of(K2, "v2b"));
-        assertEquals(bag1.getUnusedConfig().size(), 2);
-        assertEquals(bag2.getUnusedConfig().size(), 2, "unused are: "+bag2.getUnusedConfig());
-        
-        assertEquals(bag2.get(K1), "v1");
-        assertEquals(bag1.get(K2), "v2a");
-        assertEquals(bag1.getUnusedConfig().size(), 1);
-        assertEquals(bag2.getUnusedConfig().size(), 2);
-        
-        assertEquals(bag2.get(K2), "v2b");
-        assertEquals(bag2.getUnusedConfig().size(), 1);
-        
-        assertEquals(bag2.get(K3), "v3");
-        assertEquals(bag2.getUnusedConfig().size(), 0);
-        // when extended, the difference is that parent is also marked
-        assertEquals(bag1.getUnusedConfig().size(), 0);
-    }
-
-    @Test
-    public void testConcurrent() throws InterruptedException {
-        ConfigBag bag = ConfigBag.newInstance();
-        bag.put(K1, "v1");
-        bag.put(K2, "v2");
-        bag.put(K3, "v3");
-        runConcurrentTest(bag, 10, Duration.millis(50));
-    }
-    
-    @Test(groups="Integration")
-    public void testConcurrentBig() throws InterruptedException {
-        ConfigBag bag = ConfigBag.newInstance();
-        bag.put(K1, "v1");
-        bag.put(K2, "v2");
-        bag.put(K3, "v3");
-        runConcurrentTest(bag, 20, Duration.seconds(5));
-    }
-    
-    private void runConcurrentTest(final ConfigBag bag, int numThreads, Duration time) throws InterruptedException {
-        List<Thread> threads = MutableList.of();
-        final Map<Thread,Exception> exceptions = new ConcurrentHashMap<Thread,Exception>();
-        final AtomicInteger successes = new AtomicInteger();
-        for (int i=0; i<numThreads; i++) {
-            Thread t = new Thread() {
-                @Override
-                public void run() {
-                    try {
-                        while (!interrupted()) {
-                            if (Math.random()<0.9)
-                                bag.put(ConfigKeys.newStringConfigKey("k"+((int)(10*Math.random()))), "v"+((int)(10*Math.random())));
-                            if (Math.random()<0.8)
-                                bag.get(ConfigKeys.newStringConfigKey("k"+((int)(10*Math.random()))));
-                            if (Math.random()<0.2)
-                                bag.copy(bag);
-                            if (Math.random()<0.6)
-                                bag.remove(ConfigKeys.newStringConfigKey("k"+((int)(10*Math.random()))));
-                            successes.incrementAndGet();
-                        }
-                    } catch (Exception e) {
-                        exceptions.put(Thread.currentThread(), e);
-                        Exceptions.propagateIfFatal(e);
-                    }
-                }
-            };
-            t.setName("ConfigBagTest-concurrent-thread-"+i);
-            threads.add(t);
-        }
-        for (Thread t: threads) t.start();
-        time.countdownTimer().waitForExpiry();
-        for (Thread t: threads) t.interrupt();
-        for (Thread t: threads) t.join();
-        Assert.assertTrue(exceptions.isEmpty(), "Got "+exceptions.size()+"/"+numThreads+" exceptions ("+successes.get()+" successful): "+exceptions);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/crypto/SecureKeysAndSignerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/crypto/SecureKeysAndSignerTest.java b/core/src/test/java/brooklyn/util/crypto/SecureKeysAndSignerTest.java
deleted file mode 100644
index 1bdb0a3..0000000
--- a/core/src/test/java/brooklyn/util/crypto/SecureKeysAndSignerTest.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 brooklyn.util.crypto;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.nio.charset.Charset;
-import java.security.KeyPair;
-import java.security.PublicKey;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.crypto.SecureKeys.PassphraseProblem;
-import brooklyn.util.os.Os;
-
-import com.google.common.io.Files;
-
-public class SecureKeysAndSignerTest {
-
-    // a bit slow, so marked as integration (but possibly due to leftover rebind-cleanup, benign failures writing to /tmp/xx)
-    @Test(groups="Integration")
-    public void testGenerateSignedKeys() throws Exception {
-        FluentKeySigner signer = new FluentKeySigner("the-root").
-            validForYears(2).
-            selfsign();
-        X509Certificate signerCert = signer.getAuthorityCertificate();
-
-        KeyPair aKey = SecureKeys.newKeyPair();
-        X509Certificate aCert = signer.newCertificateFor("A", aKey);
-        
-        KeyPair bKey = SecureKeys.newKeyPair();
-        X509Certificate bCert = signer.newCertificateFor("B", bKey);
-
-        FluentKeySigner selfSigner1 = new FluentKeySigner("self1").selfsign();
-        X509Certificate selfCert1 = selfSigner1.getAuthorityCertificate();
-
-        SecureKeys.getTrustManager(aCert).checkClientTrusted(new X509Certificate[] { aCert }, "RSA");
-        SecureKeys.getTrustManager(signerCert).checkClientTrusted(new X509Certificate[] { signerCert }, "RSA");
-        
-        try {
-            SecureKeys.getTrustManager(aCert).checkClientTrusted(new X509Certificate[] { bCert }, "RSA");
-            Assert.fail("Trust manager for A should not accept B");
-        } catch (CertificateException e) { /* expected */ }
-        
-//        SecureKeys.getTrustManager(signerCert).checkClientTrusted(new X509Certificate[] { aCert }, "RSA");
-        // NB, the above failes; we have to convert to a canonical implementation, handled by the following
-        
-        Assert.assertTrue(SecureKeys.isCertificateAuthorizedBy(signerCert, signerCert));
-        Assert.assertTrue(SecureKeys.isCertificateAuthorizedBy(aCert, signerCert));
-        Assert.assertTrue(SecureKeys.isCertificateAuthorizedBy(bCert, signerCert));
-        Assert.assertFalse(SecureKeys.isCertificateAuthorizedBy(signerCert, aCert));
-        Assert.assertFalse(SecureKeys.isCertificateAuthorizedBy(bCert, aCert));
-        
-        Assert.assertTrue(SecureKeys.isCertificateAuthorizedBy(selfCert1, selfCert1));
-        Assert.assertFalse(SecureKeys.isCertificateAuthorizedBy(selfCert1, signerCert));
-    }
-
-    @Test
-    public void testInjectCertificateAuthority() throws Exception {
-        KeyPair caKey = SecureKeys.newKeyPair();
-        X509Certificate caCert = new FluentKeySigner("the-root", caKey).selfsign().getAuthorityCertificate();
-
-        FluentKeySigner signer = new FluentKeySigner(caCert, caKey);
-        Assert.assertEquals("the-root", signer.getCommonName());
-        
-        KeyPair aKey = SecureKeys.newKeyPair();
-        X509Certificate aCert = signer.newCertificateFor("A", aKey);
-        
-        Assert.assertTrue(SecureKeys.isCertificateAuthorizedBy(aCert, caCert));
-    }
-
-    @Test
-    public void testReadRsaKey() throws Exception {
-        KeyPair key = SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa.pem"), null);
-        checkNonTrivial(key);
-    }
-
-    @Test(expectedExceptions=IllegalStateException.class)
-    public void testReadRsaPublicKeyAsPemFails() throws Exception {
-        // should fail; see next test
-        SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa.pem.pub"), null);
-    }
-    
-    @Test
-    public void testReadRsaPublicKeyAsAuthKeysWorks() throws Exception {
-        PublicKey key = AuthorizedKeysParser.decodePublicKey(
-            ResourceUtils.create(this).getResourceAsString("classpath://brooklyn/util/crypto/sample_rsa.pem.pub"));
-        KeyPair fromPem = SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa.pem"), null);        
-        Assert.assertEquals(key, fromPem.getPublic());
-    }
-
-    @Test
-    public void testEncodeDecodeRsaPublicKey() throws Exception {
-        String data = ResourceUtils.create(this).getResourceAsString("classpath://brooklyn/util/crypto/sample_rsa.pem.pub");
-        PublicKey key = AuthorizedKeysParser.decodePublicKey(data);
-        String data2 = AuthorizedKeysParser.encodePublicKey(key);
-        Assert.assertTrue(data.contains(data2), "Expected to find '"+data2+"' in '"+data+"'");
-        PublicKey key2 = AuthorizedKeysParser.decodePublicKey(data2);
-        Assert.assertEquals(key2, key);
-    }
-
-    @Test
-    public void testEncodeDecodeDsaPublicKey() throws Exception {
-        String data = ResourceUtils.create(this).getResourceAsString("classpath://brooklyn/util/crypto/sample_dsa.pem.pub");
-        PublicKey key = AuthorizedKeysParser.decodePublicKey(data);
-        String data2 = AuthorizedKeysParser.encodePublicKey(key);
-        Assert.assertTrue(data.contains(data2), "Expected to find '"+data2+"' in '"+data+"'");
-        PublicKey key2 = AuthorizedKeysParser.decodePublicKey(data2);
-        Assert.assertEquals(key2, key);
-    }
-
-    @Test
-    public void testReadDsaKey() throws Exception {
-        KeyPair key = SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_dsa.pem"), null);
-        checkNonTrivial(key);
-    }
-
-    @Test(expectedExceptions=Exception.class)
-    public void testCantReadRsaPassphraseKeyWithoutPassphrase() throws Exception {
-        KeyPair key = SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa_passphrase.pem"), null);
-        checkNonTrivial(key);
-    }
-
-    @Test(expectedExceptions=PassphraseProblem.class)
-    public void testReadRsaPassphraseWithoutKeyFails() throws Exception {
-        SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa_passphrase.pem"), null);
-    }
-    
-    @Test
-    public void testReadRsaPassphraseKeyAndWriteWithoutPassphrase() throws Exception {
-        KeyPair key = SecureKeys.readPem(ResourceUtils.create(this).getResourceFromUrl("classpath://brooklyn/util/crypto/sample_rsa_passphrase.pem"), "passphrase");
-        checkNonTrivial(key);
-        File f = Os.newTempFile(getClass(), "brooklyn-sample_rsa_passphrase_without_passphrase.pem");
-        Files.write(SecureKeys.stringPem(key), f, Charset.defaultCharset());
-        KeyPair key2 = SecureKeys.readPem(new FileInputStream(f), null);
-        checkNonTrivial(key2);
-        Assert.assertEquals(key2.getPrivate().getEncoded(), key.getPrivate().getEncoded());
-        Assert.assertEquals(key2.getPublic().getEncoded(), key.getPublic().getEncoded());
-    }
-
-    private void checkNonTrivial(KeyPair key) {
-        Assert.assertNotEquals(key.getPrivate().getEncoded().length, 0);
-        Assert.assertNotEquals(key.getPublic().getEncoded().length, 0);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java b/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java
deleted file mode 100644
index 6469f5a..0000000
--- a/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java
+++ /dev/null
@@ -1,193 +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 brooklyn.util.file;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import javax.annotation.Nullable;
-
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import brooklyn.util.collections.MutableSet;
-import brooklyn.util.os.Os;
-import brooklyn.util.text.Identifiers;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.io.Files;
-
-/**
- * Test the operation of the {@link ArchiveBuilder} class.
- */
-@Test
-public class ArchiveBuilderTest {
-
-    private File parentDir, tmpDir, tmpDir2;
-    private Predicate<ZipEntry> isDirectory = new Predicate<ZipEntry>() {
-                @Override
-                public boolean apply(@Nullable ZipEntry input) {
-                    return input.isDirectory();
-                }
-            };
-
-    @BeforeClass
-    public void createTmpDirAndFiles() throws IOException {
-        parentDir = Os.newTempDir(getClass().getSimpleName());
-        Os.deleteOnExitRecursively(parentDir);
-        tmpDir = new File(parentDir, Identifiers.makeRandomId(4));
-        Os.mkdirs(tmpDir);
-        Files.write("abcdef", new File(tmpDir, "data01.txt"), Charsets.US_ASCII);
-        Files.write("123456", new File(tmpDir, "data02.txt"), Charsets.US_ASCII);
-        Files.write("qqqqqq", new File(tmpDir, "data03.txt"), Charsets.US_ASCII);
-        
-        tmpDir2 = new File(parentDir, Identifiers.makeRandomId(4));
-        Os.mkdirs(tmpDir2);
-        Files.write("zzzzzz", new File(tmpDir2, "data04.txt"), Charsets.US_ASCII);
-    }
-    
-    @Test
-    public void testCreateZipFromDir() throws Exception {
-        File archive = ArchiveBuilder.zip().addDirContentsAt(tmpDir, ".").create();
-        archive.deleteOnExit();
-
-        List<ZipEntry> entries = Lists.newArrayList();
-        ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
-        ZipEntry entry = input.getNextEntry();
-        while (entry != null) {
-            entries.add(entry);
-            entry = input.getNextEntry();
-        }
-        assertEquals(entries.size(), 4);
-        Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
-        Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
-        assertEquals(Iterables.size(directories), 1);
-        assertEquals(Iterables.size(files), 3);
-        String dirName = Iterables.getOnlyElement(directories).getName();
-        assertEquals(dirName, "./");
-        
-        Set<String> names = MutableSet.of();
-        for (ZipEntry file : files) {
-            assertTrue(file.getName().startsWith(dirName));
-            names.add(file.getName());
-        }
-        assertTrue(names.contains("./data01.txt"));
-        assertFalse(names.contains("./data04.txt"));
-        input.close();
-    }
-
-    @Test
-    public void testCreateZipFromTwoDirs() throws Exception {
-        File archive = ArchiveBuilder.zip().addDirContentsAt(tmpDir, ".").addDirContentsAt(tmpDir2, ".").create();
-        archive.deleteOnExit();
-
-        List<ZipEntry> entries = Lists.newArrayList();
-        ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
-        ZipEntry entry = input.getNextEntry();
-        while (entry != null) {
-            entries.add(entry);
-            entry = input.getNextEntry();
-        }
-        assertEquals(entries.size(), 5);
-        Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
-        Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
-        assertEquals(Iterables.size(directories), 1);
-        assertEquals(Iterables.size(files), 4);
-        String dirName = Iterables.getOnlyElement(directories).getName();
-        assertEquals(dirName, "./");
-        
-        Set<String> names = MutableSet.of();
-        for (ZipEntry file : files) {
-            assertTrue(file.getName().startsWith(dirName));
-            names.add(file.getName());
-        }
-        assertTrue(names.contains("./data01.txt"));
-        assertTrue(names.contains("./data04.txt"));
-        input.close();
-    }
-    @Test
-    public void testCreateZipFromFiles() throws Exception {
-        ArchiveBuilder builder = ArchiveBuilder.zip();
-        for (String fileName : Arrays.asList("data01.txt", "data02.txt", "data03.txt")) {
-            builder.addAt(new File(tmpDir, fileName), ".");
-        }
-        File archive = builder.create();
-        archive.deleteOnExit();
-
-        List<ZipEntry> entries = Lists.newArrayList();
-        ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
-        ZipEntry entry = input.getNextEntry();
-        while (entry != null) {
-            entries.add(entry);
-            entry = input.getNextEntry();
-        }
-        assertEquals(entries.size(), 3);
-        Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
-        Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
-        assertTrue(Iterables.isEmpty(directories));
-        assertEquals(Iterables.size(files), 3);
-        for (ZipEntry file : files) {
-            assertTrue(file.getName().startsWith(Os.mergePathsUnix(".", "data")));
-        }
-        input.close();
-    }
-
-    @Test
-    public void testCreateZipFromFilesWithBaseDir() throws Exception {
-        ArchiveBuilder builder = ArchiveBuilder.zip();
-        String baseDir = tmpDir.getName();
-        for (String fileName : Arrays.asList("data01.txt", "data02.txt", "data03.txt")) {
-            builder.addFromLocalBaseDir(parentDir, Os.mergePaths(baseDir, fileName));
-        }
-        File archive = builder.create();
-        archive.deleteOnExit();
-
-        List<ZipEntry> entries = Lists.newArrayList();
-        ZipInputStream input = new ZipInputStream(new FileInputStream(archive));
-        ZipEntry entry = input.getNextEntry();
-        while (entry != null) {
-            entries.add(entry);
-            entry = input.getNextEntry();
-        }
-        assertEquals(entries.size(), 3);
-        Iterable<ZipEntry> directories = Iterables.filter(entries, isDirectory);
-        Iterable<ZipEntry> files = Iterables.filter(entries, Predicates.not(isDirectory));
-        assertTrue(Iterables.isEmpty(directories));
-        assertEquals(Iterables.size(files), 3);
-        for (ZipEntry file : files) {
-            assertTrue(file.getName().startsWith(Os.mergePathsUnix(".", baseDir)));
-        }
-        input.close();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/file/ArchiveUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/file/ArchiveUtilsTest.java b/core/src/test/java/brooklyn/util/file/ArchiveUtilsTest.java
deleted file mode 100644
index 6715444..0000000
--- a/core/src/test/java/brooklyn/util/file/ArchiveUtilsTest.java
+++ /dev/null
@@ -1,135 +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 brooklyn.util.file;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-
-import java.io.File;
-import java.util.Map;
-
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.BrooklynAppUnitTestSupport;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.os.Os;
-
-import com.google.api.client.repackaged.com.google.common.base.Joiner;
-import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.io.Files;
-
-// Test are integration, because relies on ssh/scp via SshMachineLocation
-public class ArchiveUtilsTest extends BrooklynAppUnitTestSupport {
-    
-    private SshMachineLocation machine;
-    private ResourceUtils resourceUtils;
-
-    private Map<String, String> archiveContents = ImmutableMap.of("a.txt", "mya");
-    private File destDir;
-    private File origZip;
-    private File origJar;
-
-    @BeforeClass(alwaysRun=true)
-    public void setUpClass() throws Exception {
-        origZip = newZip(archiveContents);
-        origJar = Os.newTempFile(ArchiveUtilsTest.class, ".jar");
-        Files.copy(origZip, origJar);
-    }
-    
-    @AfterClass(alwaysRun=true)
-    public void tearDownClass() throws Exception {
-        if (origZip != null) origZip.delete();
-        if (origJar != null) origJar.delete();
-    }
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        machine = app.newLocalhostProvisioningLocation().obtain();
-        resourceUtils = ResourceUtils.create(ArchiveUtilsTest.class);
-        destDir = Os.newTempDir(getClass().getSimpleName());
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    @Override
-    public void tearDown() throws Exception {
-        super.tearDown();
-        if (destDir != null) Os.deleteRecursively(destDir);
-    }
-    
-    @Test(groups="Integration")
-    public void testDeployZipWithNoOptionalArgsSupplied() throws Exception {
-        boolean result = ArchiveUtils.deploy(resourceUtils, ImmutableMap.<String, Object>of(), origZip.getAbsolutePath(), machine, destDir.getAbsolutePath(), true, null, null);
-        assertTrue(result);
-        assertFilesEqual(new File(destDir, origZip.getName()), origZip);
-        assertSubFilesEqual(destDir, archiveContents);
-    }
-    
-    @Test(groups="Integration")
-    public void testDeployZipDeletingArchiveAfterUnpack() throws Exception {
-        boolean result = ArchiveUtils.deploy(resourceUtils, ImmutableMap.<String, Object>of(), origZip.getAbsolutePath(), machine, destDir.getAbsolutePath(), false, null, null);
-        assertTrue(result);
-        assertFalse(new File(destDir, origZip.getName()).exists());
-        assertSubFilesEqual(destDir, archiveContents);
-    }
-    
-    @Test(groups="Integration")
-    public void testDeployJarNotUnpacked() throws Exception {
-        ArchiveUtils.deploy(origJar.getAbsolutePath(), machine, destDir.getAbsolutePath());
-        assertFilesEqual(new File(destDir, origJar.getName()), origJar);
-    }
-    
-    @Test(groups="Integration")
-    public void testDeployExplicitDestFile() throws Exception {
-        String destFile = "custom-destFile.jar";
-        ArchiveUtils.deploy(origJar.getAbsolutePath(), machine, destDir.getAbsolutePath(), destFile);
-        assertFilesEqual(new File(destDir, destFile), origJar);
-    }
-    
-    private File newZip(Map<String, String> files) throws Exception {
-        File parentDir = Os.newTempDir(getClass().getSimpleName()+"-archive");
-        for (Map.Entry<String, String> entry : files.entrySet()) {
-            File subFile = new File(Os.mergePaths(parentDir.getAbsolutePath(), entry.getKey()));
-            subFile.getParentFile().mkdirs();
-            Files.write(entry.getValue(), subFile, Charsets.UTF_8);
-        }
-        return ArchiveBuilder.zip().addDirContentsAt(parentDir, ".").create();
-    }
-    
-    private void assertFilesEqual(File f1, File f2) throws Exception {
-        byte[] bytes1 = Files.asByteSource(f1).read();
-        byte[] bytes2 = Files.asByteSource(f1).read();
-        assertEquals(bytes1, bytes2, "f1="+f1+"; f2="+f2);
-    }
-    
-    private void assertSubFilesEqual(File parentDir, Map<String, String> files) throws Exception {
-        for (Map.Entry<String, String> entry : archiveContents.entrySet()) {
-            File subFile = new File(Os.mergePaths(parentDir.getAbsolutePath(), entry.getKey()));
-            assertEquals(Joiner.on("\n").join(Files.readLines(subFile, Charsets.UTF_8)), entry.getValue());
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/flags/MethodCoercionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/flags/MethodCoercionsTest.java b/core/src/test/java/brooklyn/util/flags/MethodCoercionsTest.java
deleted file mode 100644
index 4d06ca4..0000000
--- a/core/src/test/java/brooklyn/util/flags/MethodCoercionsTest.java
+++ /dev/null
@@ -1,146 +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 brooklyn.util.flags;
-
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.guava.Maybe;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-
-import java.lang.reflect.Method;
-import java.util.List;
-
-import static org.testng.Assert.*;
-
-public class MethodCoercionsTest {
-
-    private Method singleParameterMethod;
-    private Method multiParameterMethod;
-    private Method singleCollectionParameterMethod;
-
-    @BeforeClass
-    public void testFixtureSetUp() {
-        try {
-            singleParameterMethod = TestClass.class.getMethod("singleParameterMethod", int.class);
-            multiParameterMethod = TestClass.class.getMethod("multiParameterMethod", boolean.class, int.class);
-            singleCollectionParameterMethod = TestClass.class.getMethod("singleCollectionParameterMethod", List.class);
-        } catch (NoSuchMethodException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    @Test
-    public void testMatchSingleParameterMethod() throws Exception {
-        Predicate<Method> predicate = MethodCoercions.matchSingleParameterMethod("singleParameterMethod", "42");
-        assertTrue(predicate.apply(singleParameterMethod));
-        assertFalse(predicate.apply(multiParameterMethod));
-        assertFalse(predicate.apply(singleCollectionParameterMethod));
-    }
-
-    @Test
-    public void testTryFindAndInvokeSingleParameterMethod() throws Exception {
-        TestClass instance = new TestClass();
-        Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleParameterMethod(instance, "singleParameterMethod", "42");
-        assertTrue(maybe.isPresent());
-        assertTrue(instance.wasSingleParameterMethodCalled());
-    }
-
-    @Test
-    public void testMatchMultiParameterMethod() throws Exception {
-        Predicate<Method> predicate = MethodCoercions.matchMultiParameterMethod("multiParameterMethod", ImmutableList.of("true", "42"));
-        assertFalse(predicate.apply(singleParameterMethod));
-        assertTrue(predicate.apply(multiParameterMethod));
-        assertFalse(predicate.apply(singleCollectionParameterMethod));
-    }
-
-    @Test
-    public void testTryFindAndInvokeMultiParameterMethod() throws Exception {
-        TestClass instance = new TestClass();
-        Maybe<?> maybe = MethodCoercions.tryFindAndInvokeMultiParameterMethod(instance, "multiParameterMethod", ImmutableList.of("true", "42"));
-        assertTrue(maybe.isPresent());
-        assertTrue(instance.wasMultiParameterMethodCalled());
-    }
-
-    @Test
-    public void testTryFindAndInvokeBestMatchingMethod() throws Exception {
-        TestClass instance = new TestClass();
-        Maybe<?> maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "singleParameterMethod", "42");
-        assertTrue(maybe.isPresent());
-        assertTrue(instance.wasSingleParameterMethodCalled());
-
-        instance = new TestClass();
-        maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "multiParameterMethod", ImmutableList.of("true", "42"));
-        assertTrue(maybe.isPresent());
-        assertTrue(instance.wasMultiParameterMethodCalled());
-
-        instance = new TestClass();
-        maybe = MethodCoercions.tryFindAndInvokeBestMatchingMethod(instance, "singleCollectionParameterMethod", ImmutableList.of("fred", "joe"));
-        assertTrue(maybe.isPresent());
-        assertTrue(instance.wasSingleCollectionParameterMethodCalled());
-    }
-/*
-    @Test
-    public void testMatchSingleCollectionParameterMethod() throws Exception {
-        Predicate<Method> predicate = MethodCoercions.matchSingleCollectionParameterMethod("singleCollectionParameterMethod", ImmutableList.of("42"));
-        assertFalse(predicate.apply(singleParameterMethod));
-        assertFalse(predicate.apply(multiParameterMethod));
-        assertTrue(predicate.apply(singleCollectionParameterMethod));
-    }
-
-    @Test
-    public void testTryFindAndInvokeSingleCollectionParameterMethod() throws Exception {
-        TestClass instance = new TestClass();
-        Maybe<?> maybe = MethodCoercions.tryFindAndInvokeSingleCollectionParameterMethod(instance, "singleCollectionParameterMethod", ImmutableList.of("42"));
-        assertTrue(maybe.isPresent());
-        assertTrue(instance.wasSingleCollectionParameterMethodCalled());
-    }
-*/
-    public static class TestClass {
-
-        private boolean singleParameterMethodCalled;
-        private boolean multiParameterMethodCalled;
-        private boolean singleCollectionParameterMethodCalled;
-
-        public void singleParameterMethod(int parameter) {
-            singleParameterMethodCalled = true;
-        }
-
-        public void multiParameterMethod(boolean parameter1, int parameter2) {
-            multiParameterMethodCalled = true;
-        }
-
-        public void singleCollectionParameterMethod(List<String> parameter) {
-            singleCollectionParameterMethodCalled = true;
-        }
-
-        public boolean wasSingleParameterMethodCalled() {
-            return singleParameterMethodCalled;
-        }
-
-        public boolean wasMultiParameterMethodCalled() {
-            return multiParameterMethodCalled;
-        }
-
-        public boolean wasSingleCollectionParameterMethodCalled() {
-            return singleCollectionParameterMethodCalled;
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/http/BetterMockWebServer.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/http/BetterMockWebServer.java b/core/src/test/java/brooklyn/util/http/BetterMockWebServer.java
deleted file mode 100644
index fb76903..0000000
--- a/core/src/test/java/brooklyn/util/http/BetterMockWebServer.java
+++ /dev/null
@@ -1,138 +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 brooklyn.util.http;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.Proxy;
-import java.net.URL;
-
-import javax.net.ssl.SSLSocketFactory;
-
-import com.google.common.base.Throwables;
-import com.google.mockwebserver.Dispatcher;
-import com.google.mockwebserver.MockResponse;
-import com.google.mockwebserver.MockWebServer;
-import com.google.mockwebserver.RecordedRequest;
-
-/** like MockWebServer (and delegating) but:
- * <li> allows subclassing
- * <li> easy way to create instance which returns localhost for {@link #getHostName()}
- *      (since otherwise you can get failures on networks which misconfigure hostname) 
- * */
-public class BetterMockWebServer {
-
-    final MockWebServer delegate = new MockWebServer();
-    String hostname = null;
-    boolean isHttps = false;
-    
-    public static BetterMockWebServer newInstanceLocalhost() {
-        return new BetterMockWebServer().setHostName("localhost");
-    }
-    
-    /** use {@link #newInstanceLocalhost()} or subclass */
-    protected BetterMockWebServer() {}
-
-    public BetterMockWebServer setHostName(String hostname) {
-        this.hostname = hostname;
-        return this;
-    }
-
-
-    // --- delegate methods (unchanged)
-    
-    public void enqueue(MockResponse response) {
-        delegate.enqueue(response);
-    }
-
-    public boolean equals(Object obj) {
-        return delegate.equals(obj);
-    }
-
-    public String getCookieDomain() {
-        return delegate.getCookieDomain();
-    }
-
-    public String getHostName() {
-        if (hostname!=null) return hostname;
-        return delegate.getHostName();
-    }
-
-    public int getPort() {
-        return delegate.getPort();
-    }
-
-    public int getRequestCount() {
-        return delegate.getRequestCount();
-    }
-
-    public URL getUrl(String path) {
-        try {
-            return isHttps
-                ? new URL("https://" + getHostName() + ":" + getPort() + path)
-                : new URL("http://" + getHostName() + ":" + getPort() + path);
-        } catch (MalformedURLException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-
-    public int hashCode() {
-        return delegate.hashCode();
-    }
-
-    public void play() throws IOException {
-        delegate.play();
-    }
-
-    public void play(int port) throws IOException {
-        delegate.play(port);
-    }
-
-    public void setBodyLimit(int maxBodyLength) {
-        delegate.setBodyLimit(maxBodyLength);
-    }
-
-    public void setDispatcher(Dispatcher dispatcher) {
-        delegate.setDispatcher(dispatcher);
-    }
-
-    public void shutdown() throws IOException {
-        delegate.shutdown();
-    }
-
-    public RecordedRequest takeRequest() throws InterruptedException {
-        return delegate.takeRequest();
-    }
-
-    public Proxy toProxyAddress() {
-        return delegate.toProxyAddress();
-    }
-
-    public String toString() {
-        return delegate.toString();
-    }
-
-    public void useHttps(SSLSocketFactory sslSocketFactory, boolean tunnelProxy) {
-        isHttps = true;
-        delegate.useHttps(sslSocketFactory, tunnelProxy);
-    }
-    
-    
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/http/HttpToolIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/http/HttpToolIntegrationTest.java b/core/src/test/java/brooklyn/util/http/HttpToolIntegrationTest.java
deleted file mode 100644
index dc9fc31..0000000
--- a/core/src/test/java/brooklyn/util/http/HttpToolIntegrationTest.java
+++ /dev/null
@@ -1,98 +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 brooklyn.util.http;
-
-import static org.testng.Assert.assertTrue;
-
-import java.net.URI;
-
-import org.apache.http.client.HttpClient;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.test.HttpService;
-
-import com.google.common.collect.ImmutableMap;
-
-public class HttpToolIntegrationTest {
-
-    // TODO Expand test coverage for credentials etc
-    
-    private HttpService httpService;
-    private HttpService httpsService;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        httpService = new HttpService(PortRanges.fromString("9000+"), false).start();
-        httpsService = new HttpService(PortRanges.fromString("9000+"), true).start();
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (httpService != null) httpService.shutdown();
-        if (httpsService != null) httpsService.shutdown();
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testHttpGet() throws Exception {
-        URI baseUri = new URI(httpService.getUrl());
-
-        HttpClient client = HttpTool.httpClientBuilder().build();
-        HttpToolResponse result = HttpTool.httpGet(client, baseUri, ImmutableMap.<String,String>of());
-        assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testHttpRedirect() throws Exception {
-        URI baseUri = new URI(httpService.getUrl() + "hello/redirectAbsolute");
-
-        HttpClient client = HttpTool.httpClientBuilder().laxRedirect(true).build();
-        HttpToolResponse result = HttpTool.httpGet(client, baseUri, ImmutableMap.<String,String>of());
-        assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testHttpPost() throws Exception {
-        URI baseUri = new URI(httpService.getUrl());
-
-        HttpClient client = HttpTool.httpClientBuilder().build();
-        HttpToolResponse result = HttpTool.httpPost(client, baseUri, ImmutableMap.<String,String>of(), new byte[0]);
-        assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testHttpsGetWithTrustAll() throws Exception {
-        URI baseUri = new URI(httpsService.getUrl());
-
-        HttpClient client = HttpTool.httpClientBuilder().https(true).trustAll().build();
-        HttpToolResponse result = HttpTool.httpGet(client, baseUri, ImmutableMap.<String,String>of());
-        assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testHttpsPostWithTrustSelfSigned() throws Exception {
-        URI baseUri = new URI(httpsService.getUrl());
-
-        HttpClient client = HttpTool.httpClientBuilder().https(true).trustSelfSigned().build();
-        HttpToolResponse result = HttpTool.httpPost(client, baseUri, ImmutableMap.<String,String>of(), new byte[0]);
-        assertTrue(new String(result.getContent()).contains("Hello, World"), "val="+new String(result.getContent()));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/FlagUtilsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/FlagUtilsTest.java b/core/src/test/java/brooklyn/util/internal/FlagUtilsTest.java
deleted file mode 100644
index ed98dba..0000000
--- a/core/src/test/java/brooklyn/util/internal/FlagUtilsTest.java
+++ /dev/null
@@ -1,314 +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 brooklyn.util.internal;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-
-import java.lang.reflect.Field;
-import java.net.InetAddress;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.brooklyn.api.entity.trait.Configurable;
-import org.apache.brooklyn.api.management.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.Test;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.config.ConfigKey.HasConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.SetFromFlag;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-public class FlagUtilsTest {
-
-    public static final Logger log = LoggerFactory.getLogger(FlagUtilsTest.class);
-    
-    @Test
-    public void testGetAllFields() {
-        log.info("types {}", FlagUtils.getAllAssignableTypes(Baz.class));
-        assertEquals(FlagUtils.getAllAssignableTypes(Baz.class), ImmutableList.of(Baz.class, Foo.class, Bar.class));
-        List<Field> fs = FlagUtils.getAllFields(Baz.class);
-        for (Field f : fs) {
-            log.info("field {}    {}", f.getName(), f);
-        }
-        List<String> fsn = ImmutableList.copyOf(Iterables.transform(fs, new Function<Field, String>() {
-            @Override public String apply(Field f) {
-                return f.getName();
-            }}));
-        assertTrue(fsn.indexOf("A") >= 0);
-        assertTrue(fsn.indexOf("w") > fsn.indexOf("A")); 
-        assertTrue(fsn.indexOf("x") > fsn.indexOf("A") );
-        assertTrue(fsn.indexOf("yNotY") > fsn.indexOf("A")); 
-        assertTrue(fsn.indexOf("Z") > fsn.indexOf("yNotY") );
-    }    
-    
-    @Test
-    public void testSetFieldsFromFlags() {
-        Foo f = new Foo();
-        Map<?,?> m = MutableMap.of("w", 3, "x", 1, "y", 7, "z", 9);
-        Map<?, ?> unused = FlagUtils.setFieldsFromFlags(m, f);
-        assertEquals(f.w, 3);
-        assertEquals(f.x, 1);
-        assertEquals(f.yNotY, 7);
-        assertEquals(unused, ImmutableMap.of("z", 9));
-        Map<?,?> m2 = FlagUtils.getFieldsWithValues(f);
-        m.remove("z");
-        assertEquals(m2, m);
-    }
-    
-    @Test
-    public void testCollectionCoercionOnSetFromFlags() {
-        WithSpecialFieldTypes s = new WithSpecialFieldTypes();
-        Map<?,?> m = ImmutableMap.of("set", ImmutableSet.of(1));
-        FlagUtils.setFieldsFromFlags(m, s);
-        assertEquals(s.set, ImmutableSet.of(1));
-    }
-
-    @Test
-    public void testInetAddressCoercionOnSetFromFlags() {
-        WithSpecialFieldTypes s = new WithSpecialFieldTypes();
-        Map<?,?> m = ImmutableMap.of("inet", "127.0.0.1");
-        FlagUtils.setFieldsFromFlags(m, s);
-        assertEquals(s.inet.getHostAddress(), "127.0.0.1");
-    }
-
-    @Test
-    public void testNonImmutableField() {
-        Foo f = new Foo();
-        FlagUtils.setFieldsFromFlags(ImmutableMap.of("w", 8), f);
-        assertEquals(f.w, 8);
-        FlagUtils.setFieldsFromFlags(ImmutableMap.of("w", 9), f);
-        assertEquals(f.w, 9);
-    }
-
-    @Test
-    public void testImmutableIntField() {
-        Foo f = new Foo();
-        FlagUtils.setFieldsFromFlags(ImmutableMap.of("x", 8), f);
-        assertEquals(f.x, 8);
-        boolean succeededWhenShouldntHave = false; 
-        try {
-            FlagUtils.setFieldsFromFlags(ImmutableMap.of("x", 9), f);
-            succeededWhenShouldntHave = true;
-        } catch (IllegalStateException e) {
-            //expected
-        }
-        assertFalse(succeededWhenShouldntHave);
-        assertEquals(f.x, 8);
-    }
-
-    @Test
-    public void testImmutableObjectField() {
-        WithImmutableNonNullableObject o = new WithImmutableNonNullableObject();
-        FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a", "b", "b"), o);
-        assertEquals(o.a, "a");
-        assertEquals(o.b, "b");
-        
-        FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a2"), o);
-        assertEquals(o.a, "a2");
-        
-        boolean succeededWhenShouldntHave = false;
-        try {
-            FlagUtils.setFieldsFromFlags(ImmutableMap.of("b", "b2"), o);
-            succeededWhenShouldntHave = true;
-        } catch (IllegalStateException e) {
-            //expected
-        }
-        assertFalse(succeededWhenShouldntHave);
-        assertEquals(o.b, "b");
-    }
-
-    @Test
-    public void testNonNullable() {
-        WithImmutableNonNullableObject o = new WithImmutableNonNullableObject();
-        //allowed
-        FlagUtils.setFieldsFromFlags(MutableMap.of("a", null), o);
-        assertEquals(o.a, null);
-        assertEquals(o.b, null);
-        //not allowed
-        boolean succeededWhenShouldntHave = false;
-        try {
-            FlagUtils.setFieldsFromFlags(MutableMap.of("b", null), o);
-            succeededWhenShouldntHave = true;
-        } catch (IllegalArgumentException e) {
-            //expected
-        }
-        assertFalse(succeededWhenShouldntHave);
-        assertEquals(o.b, null);
-    }
-    
-    @Test
-    public void testGetAnnotatedFields() throws Exception {
-        Map<Field, SetFromFlag> fm = FlagUtils.getAnnotatedFields(WithImmutableNonNullableObject.class);
-        assertEquals(fm.keySet().size(), 2);
-        assertTrue(fm.get(WithImmutableNonNullableObject.class.getDeclaredField("b")).immutable());
-    }
-
-    @Test
-    public void testCheckRequired() {
-        WithImmutableNonNullableObject f = new WithImmutableNonNullableObject();
-        FlagUtils.setFieldsFromFlags(ImmutableMap.of("a", "a is a"), f);
-        assertEquals(f.a, "a is a");
-        assertEquals(f.b, null);
-        int exceptions = 0;
-        try {
-            FlagUtils.checkRequiredFields(f);
-        } catch (IllegalStateException e) {
-            exceptions++;
-        }
-        assertEquals(exceptions, 1);
-    }
-
-    @Test
-    public void testSetConfigKeys() {
-        FooCK f = new FooCK();
-        Map<?,?> unused = FlagUtils.setFieldsFromFlags(ImmutableMap.of("f1", 9, "ck1", "do-set", "ck2", "dont-set", "c3", "do-set"), f);
-        assertEquals(f.bag.get(FooCK.CK1), "do-set");
-        assertEquals(f.bag.get(FooCK.CK3), "do-set");
-        assertEquals(f.f1, 9);
-        assertEquals(f.bag.containsKey(FooCK.CK2), false);
-        assertEquals(unused, ImmutableMap.of("ck2", "dont-set"));
-    }
-    
-    @Test
-    public void testSetAllConfigKeys() {
-        FooCK f = new FooCK();
-        Map<?,?> unused = FlagUtils.setAllConfigKeys(ImmutableMap.of("f1", 9, "ck1", "do-set", "ck2", "do-set-2", "c3", "do-set"), f, true);
-        assertEquals(f.bag.get(FooCK.CK1), "do-set");
-        assertEquals(f.bag.get(FooCK.CK3), "do-set");
-        assertEquals(f.bag.containsKey(FooCK.CK2), true);
-        assertEquals(f.bag.get(FooCK.CK2), "do-set-2");
-        assertEquals(unused, ImmutableMap.of("f1", 9));
-    }
-
-    @Test
-    public void testSetFromConfigKeys() {
-        FooCK f = new FooCK();
-        Map<?, ?> unused = FlagUtils.setFieldsFromFlags(ImmutableMap.of(new BasicConfigKey<Integer>(Integer.class, "f1"), 9, "ck1", "do-set", "ck2", "dont-set"), f);
-        assertEquals(f.bag.get(FooCK.CK1), "do-set");
-        assertEquals(f.f1, 9);
-        assertEquals(f.bag.containsKey(FooCK.CK2), false);
-        assertEquals(unused, ImmutableMap.of("ck2", "dont-set"));
-    }
-
-    public static class Foo {
-        @SetFromFlag
-        int w;
-        
-        @SetFromFlag(immutable=true)
-        private int x;
-        
-        @SetFromFlag("y")
-        public int yNotY;
-    }
-    
-    public static interface Bar {
-        static final String Z = "myzval";
-    }
-    
-    public static class Baz extends Foo implements Bar {
-        @SuppressWarnings("unused")  //inspected by reflection
-        private static int A;
-    }
-    
-    public static class WithImmutableNonNullableObject {
-        @SetFromFlag
-        Object a;
-        @SetFromFlag(immutable=true, nullable=false)
-        public Object b;
-    }
-    
-    public static class WithSpecialFieldTypes {
-        @SetFromFlag Set<?> set;
-        @SetFromFlag InetAddress inet;
-    }
-    
-    public static class FooCK implements Configurable {
-        @SetFromFlag
-        public static ConfigKey<String> CK1 = ConfigKeys.newStringConfigKey("ck1");
-        
-        public static ConfigKey<String> CK2 = ConfigKeys.newStringConfigKey("ck2");
-
-        @SetFromFlag("c3")
-        public static ConfigKey<String> CK3 = ConfigKeys.newStringConfigKey("ck3");
-
-        @SetFromFlag
-        int f1;
-        
-        ConfigBag bag = new ConfigBag();
-        BasicConfigurationSupport configSupport = new BasicConfigurationSupport();
-        
-        @Override
-        public ConfigurationSupport config() {
-            return configSupport;
-        }
-        
-        public <T> T setConfig(ConfigKey<T> key, T val) {
-            return config().set(key, val);
-        }
-        
-        private class BasicConfigurationSupport implements ConfigurationSupport {
-            @Override
-            public <T> T get(ConfigKey<T> key) {
-                return bag.get(key);
-            }
-
-            @Override
-            public <T> T get(HasConfigKey<T> key) {
-                return get(key.getConfigKey());
-            }
-
-            @Override
-            public <T> T set(ConfigKey<T> key, T val) {
-                T old = bag.get(key);
-                bag.configure(key, val);
-                return old;
-            }
-
-            @Override
-            public <T> T set(HasConfigKey<T> key, T val) {
-                return set(key.getConfigKey(), val);
-            }
-
-            @Override
-            public <T> T set(ConfigKey<T> key, Task<T> val) {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public <T> T set(HasConfigKey<T> key, Task<T> val) {
-                return set(key.getConfigKey(), val);
-            }
-        }
-    }
-}
\ No newline at end of file


[42/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/policy

Posted by he...@apache.org.
[BROOKLYN-162] Refactor package in ./core/policy


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

Branch: refs/heads/master
Commit: 54f5c36369438f6e25c68d04333310221306aa62
Parents: 699b3f6
Author: Hadrian Zbarcea <ha...@apache.org>
Authored: Mon Aug 17 02:03:16 2015 -0400
Committer: Hadrian Zbarcea <ha...@apache.org>
Committed: Mon Aug 17 02:03:16 2015 -0400

----------------------------------------------------------------------
 .../main/java/brooklyn/basic/BrooklynTypes.java |   2 +-
 .../enricher/basic/AbstractEnricher.java        |   2 +-
 .../brooklyn/entity/basic/AbstractEntity.java   |   6 +-
 .../group/AbstractMembershipTrackingPolicy.java |   2 +-
 .../entity/proxying/InternalEntityFactory.java  |   2 +-
 .../entity/proxying/InternalPolicyFactory.java  |   2 +-
 .../AbstractBrooklynObjectRebindSupport.java    |   2 +-
 .../entity/rebind/BasicEntityRebindSupport.java |   2 +-
 .../entity/rebind/BasicPolicyRebindSupport.java |   3 +-
 .../brooklyn/entity/rebind/RebindIteration.java |   2 +-
 .../entity/rebind/dto/MementosGenerators.java   |   2 +-
 .../java/brooklyn/event/feed/AbstractFeed.java  |   2 +-
 .../policy/basic/AbstractEntityAdjunct.java     | 510 -------------------
 .../brooklyn/policy/basic/AbstractPolicy.java   | 119 -----
 .../java/brooklyn/policy/basic/AdjunctType.java | 174 -------
 .../brooklyn/policy/basic/ConfigMapImpl.java    | 140 -----
 .../policy/basic/GeneralPurposePolicy.java      |  36 --
 .../java/brooklyn/policy/basic/Policies.java    |  73 ---
 .../policy/basic/PolicyDynamicType.java         |  44 --
 .../policy/basic/PolicyTypeSnapshot.java        |  40 --
 .../policy/basic/AbstractEntityAdjunct.java     | 510 +++++++++++++++++++
 .../core/policy/basic/AbstractPolicy.java       | 119 +++++
 .../brooklyn/core/policy/basic/AdjunctType.java | 174 +++++++
 .../core/policy/basic/ConfigMapImpl.java        | 140 +++++
 .../core/policy/basic/GeneralPurposePolicy.java |  36 ++
 .../brooklyn/core/policy/basic/Policies.java    |  73 +++
 .../core/policy/basic/PolicyDynamicType.java    |  44 ++
 .../core/policy/basic/PolicyTypeSnapshot.java   |  40 ++
 .../entity/EntityPreManagementTest.java         |   2 +-
 .../brooklyn/entity/basic/EntitySpecTest.java   |   2 +-
 .../entity/basic/PolicyRegistrationTest.java    |   2 +-
 .../entity/group/GroupPickUpEntitiesTest.java   |   2 +-
 .../entity/rebind/RebindCatalogItemTest.java    |   3 +-
 .../entity/rebind/RebindFailuresTest.java       |   2 +-
 .../entity/rebind/RebindPolicyTest.java         |   2 +-
 .../brooklyn/policy/basic/BasicPolicyTest.java  |  89 ----
 .../brooklyn/policy/basic/EnricherTypeTest.java |  59 ---
 .../brooklyn/policy/basic/PolicyConfigTest.java | 202 --------
 .../policy/basic/PolicySubscriptionTest.java    | 125 -----
 .../brooklyn/policy/basic/PolicyTypeTest.java   |  58 ---
 .../java/brooklyn/test/policy/TestPolicy.java   |   2 +-
 .../core/policy/basic/BasicPolicyTest.java      |  90 ++++
 .../core/policy/basic/EnricherTypeTest.java     |  59 +++
 .../core/policy/basic/PolicyConfigTest.java     | 202 ++++++++
 .../policy/basic/PolicySubscriptionTest.java    | 128 +++++
 .../core/policy/basic/PolicyTypeTest.java       |  59 +++
 .../policy/os/AdvertiseWinrmLoginPolicy.java    |   3 +-
 .../brooklyn/policy/os/CreateUserPolicy.java    |   2 +-
 .../policy/autoscaling/AutoScalerPolicy.java    |   2 +-
 .../policy/followthesun/FollowTheSunPolicy.java |   2 +-
 .../policy/ha/AbstractFailureDetector.java      |   2 +-
 .../policy/ha/ConditionalSuspendPolicy.java     |   2 +-
 .../brooklyn/policy/ha/ServiceReplacer.java     |   2 +-
 .../brooklyn/policy/ha/ServiceRestarter.java    |   2 +-
 .../loadbalancing/LoadBalancingPolicy.java      |   2 +-
 .../camp/brooklyn/TestReferencingPolicy.java    |   2 +-
 .../apache/brooklyn/cli/lister/ClassFinder.java |   2 +-
 .../brooklyn/rest/resources/PolicyResource.java |   4 +-
 .../rest/transform/PolicyTransformer.java       |   2 +-
 .../rest/util/BrooklynRestResourceUtils.java    |   2 +-
 .../rest/testing/mocks/CapitalizePolicy.java    |   3 +-
 .../testing/mocks/RestMockSimplePolicy.java     |   2 +-
 .../util/BrooklynRestResourceUtilsTest.java     |   2 +-
 .../java/brooklyn/osgi/tests/SimplePolicy.java  |   2 +-
 .../brooklyn/osgi/tests/more/MorePolicy.java    |   3 +-
 .../brooklyn/osgi/tests/more/MorePolicy.java    |   2 +-
 66 files changed, 1716 insertions(+), 1718 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/basic/BrooklynTypes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/BrooklynTypes.java b/core/src/main/java/brooklyn/basic/BrooklynTypes.java
index 64dbcd0..780349f 100644
--- a/core/src/main/java/brooklyn/basic/BrooklynTypes.java
+++ b/core/src/main/java/brooklyn/basic/BrooklynTypes.java
@@ -26,11 +26,11 @@ import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.core.policy.basic.PolicyDynamicType;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.EnricherDynamicType;
 import brooklyn.entity.basic.EntityDynamicType;
-import brooklyn.policy.basic.PolicyDynamicType;
 import brooklyn.util.exceptions.Exceptions;
 
 import com.google.common.collect.Maps;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
index 5bca143..651ea56 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.mementos.EnricherMemento;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EnricherType;
+import org.apache.brooklyn.core.policy.basic.AbstractEntityAdjunct;
 import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import brooklyn.config.ConfigKey;
@@ -36,7 +37,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.rebind.BasicEnricherRebindSupport;
-import brooklyn.policy.basic.AbstractEntityAdjunct;
 
 import com.google.common.base.Objects;
 import com.google.common.collect.Maps;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
index 4bdae46..b004754 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -60,6 +60,9 @@ import org.apache.brooklyn.core.management.internal.EffectorUtils;
 import org.apache.brooklyn.core.management.internal.EntityManagementSupport;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.management.internal.SubscriptionTracker;
+import org.apache.brooklyn.core.policy.basic.AbstractEntityAdjunct;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
+import org.apache.brooklyn.core.policy.basic.AbstractEntityAdjunct.AdjunctTagSupport;
 import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.core.util.flags.FlagUtils;
 import org.apache.brooklyn.core.util.flags.TypeCoercions;
@@ -88,9 +91,6 @@ import brooklyn.internal.storage.impl.BasicReference;
 
 import org.apache.brooklyn.location.basic.Locations;
 
-import brooklyn.policy.basic.AbstractEntityAdjunct;
-import brooklyn.policy.basic.AbstractEntityAdjunct.AdjunctTagSupport;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java b/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
index 5647975..400506f 100644
--- a/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
+++ b/core/src/main/java/brooklyn/entity/group/AbstractMembershipTrackingPolicy.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,7 +38,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.DynamicGroup;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.javalang.JavaClassNames;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
index 1c1a920..eb601ed 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalEntityFactory.java
@@ -37,6 +37,7 @@ import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.FlagUtils;
 import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
@@ -48,7 +49,6 @@ import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java b/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
index 7c53404..c174dcb 100644
--- a/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
+++ b/core/src/main/java/brooklyn/entity/proxying/InternalPolicyFactory.java
@@ -27,12 +27,12 @@ import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.basic.AbstractEntity;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java
index 19a6cd6..000a651 100644
--- a/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/AbstractBrooklynObjectRebindSupport.java
@@ -22,12 +22,12 @@ import org.apache.brooklyn.api.entity.rebind.RebindContext;
 import org.apache.brooklyn.api.entity.rebind.RebindSupport;
 import org.apache.brooklyn.api.mementos.Memento;
 import org.apache.brooklyn.api.policy.EntityAdjunct;
+import org.apache.brooklyn.core.policy.basic.AbstractEntityAdjunct.AdjunctTagSupport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.basic.AbstractBrooklynObject;
 import brooklyn.entity.rebind.dto.MementosGenerators;
-import brooklyn.policy.basic.AbstractEntityAdjunct.AdjunctTagSupport;
 import brooklyn.util.text.Strings;
 
 public abstract class AbstractBrooklynObjectRebindSupport<T extends Memento> implements RebindSupport<T> {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
index 3a29595..f059a83 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicEntityRebindSupport.java
@@ -31,6 +31,7 @@ import org.apache.brooklyn.api.entity.rebind.RebindContext;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mementos.EntityMemento;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,7 +42,6 @@ import brooklyn.entity.basic.AbstractGroupImpl;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.rebind.dto.MementosGenerators;
 import brooklyn.event.feed.AbstractFeed;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.exceptions.Exceptions;
 
 import com.google.common.base.Throwables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java b/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
index 4623225..e511ce2 100644
--- a/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
+++ b/core/src/main/java/brooklyn/entity/rebind/BasicPolicyRebindSupport.java
@@ -20,11 +20,10 @@ package brooklyn.entity.rebind;
 
 import org.apache.brooklyn.api.entity.rebind.RebindContext;
 import org.apache.brooklyn.api.mementos.PolicyMemento;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.core.util.flags.FlagUtils;
 
-import brooklyn.policy.basic.AbstractPolicy;
-
 public class BasicPolicyRebindSupport extends AbstractBrooklynObjectRebindSupport<PolicyMemento> {
 
     private final AbstractPolicy policy;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
index 67d20ae..eb1a461 100644
--- a/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
+++ b/core/src/main/java/brooklyn/entity/rebind/RebindIteration.java
@@ -73,6 +73,7 @@ import org.apache.brooklyn.core.management.internal.EntityManagerInternal;
 import org.apache.brooklyn.core.management.internal.LocationManagerInternal;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.management.internal.ManagementTransitionMode;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.FlagUtils;
 
 import brooklyn.config.BrooklynLogging;
@@ -92,7 +93,6 @@ import brooklyn.event.feed.AbstractFeed;
 import org.apache.brooklyn.location.basic.AbstractLocation;
 import org.apache.brooklyn.location.basic.LocationInternal;
 
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java b/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
index 5c52788..301211d 100644
--- a/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
+++ b/core/src/main/java/brooklyn/entity/rebind/dto/MementosGenerators.java
@@ -50,6 +50,7 @@ import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EntityAdjunct;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.catalog.internal.CatalogItemDo;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.core.util.flags.FlagUtils;
 
@@ -64,7 +65,6 @@ import brooklyn.event.feed.AbstractFeed;
 
 import org.apache.brooklyn.location.basic.LocationInternal;
 
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableMap;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/event/feed/AbstractFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/AbstractFeed.java b/core/src/main/java/brooklyn/event/feed/AbstractFeed.java
index 23037a7..59ed4f7 100644
--- a/core/src/main/java/brooklyn/event/feed/AbstractFeed.java
+++ b/core/src/main/java/brooklyn/event/feed/AbstractFeed.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.rebind.RebindSupport;
 import org.apache.brooklyn.api.mementos.FeedMemento;
 import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
+import org.apache.brooklyn.core.policy.basic.AbstractEntityAdjunct;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,7 +35,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.rebind.BasicFeedRebindSupport;
-import brooklyn.policy.basic.AbstractEntityAdjunct;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
deleted file mode 100644
index afa015f..0000000
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ /dev/null
@@ -1,510 +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 brooklyn.policy.basic;
-
-import static brooklyn.util.GroovyJavaMethods.truth;
-import static com.google.common.base.Preconditions.checkState;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.Group;
-import org.apache.brooklyn.api.entity.basic.EntityLocal;
-import org.apache.brooklyn.api.entity.trait.Configurable;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.api.event.Sensor;
-import org.apache.brooklyn.api.event.SensorEventListener;
-import org.apache.brooklyn.api.management.ExecutionContext;
-import org.apache.brooklyn.api.management.SubscriptionContext;
-import org.apache.brooklyn.api.management.SubscriptionHandle;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.policy.EntityAdjunct;
-import org.apache.brooklyn.core.management.internal.SubscriptionTracker;
-import org.apache.brooklyn.core.util.config.ConfigBag;
-import org.apache.brooklyn.core.util.flags.FlagUtils;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-import org.apache.brooklyn.core.util.flags.TypeCoercions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.basic.AbstractBrooklynObject;
-import brooklyn.basic.BrooklynObjectInternal;
-import brooklyn.config.ConfigKey;
-import brooklyn.config.ConfigKey.HasConfigKey;
-import brooklyn.config.ConfigMap;
-import brooklyn.enricher.basic.AbstractEnricher;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.EntityInternal;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.text.Strings;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-
-
-/**
- * Common functionality for policies and enrichers
- */
-public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject implements BrooklynObjectInternal, EntityAdjunct, Configurable {
-    private static final Logger log = LoggerFactory.getLogger(AbstractEntityAdjunct.class);
-
-    private boolean _legacyNoConstructionInit;
-
-    /**
-     * @deprecated since 0.7.0; leftover properties are put into config, since when coming from yaml this is normal.
-     */
-    @Deprecated
-    protected Map<String,Object> leftoverProperties = Maps.newLinkedHashMap();
-
-    protected transient ExecutionContext execution;
-
-    private final BasicConfigurationSupport config = new BasicConfigurationSupport();
-    
-    /**
-     * The config values of this entity. Updating this map should be done
-     * via {@link #config()}.
-     * 
-     * @deprecated since 0.7.0; use {@link #config()} instead; this field may be made private or deleted in a future release.
-     */
-    @Deprecated
-    protected final ConfigMapImpl configsInternal = new ConfigMapImpl(this);
-
-    /**
-     * @deprecated since 0.7.0; use {@link #getAdjunctType()} instead; this field may be made private or deleted in a future release.
-     */
-    @Deprecated
-    protected final AdjunctType adjunctType = new AdjunctType(this);
-
-    @SetFromFlag
-    protected String name;
-    
-    protected transient EntityLocal entity;
-    
-    /** not for direct access; refer to as 'subscriptionTracker' via getter so that it is initialized */
-    protected transient SubscriptionTracker _subscriptionTracker;
-    
-    private AtomicBoolean destroyed = new AtomicBoolean(false);
-    
-    @SetFromFlag(value="uniqueTag")
-    protected String uniqueTag;
-
-    public AbstractEntityAdjunct() {
-        this(Collections.emptyMap());
-    }
-    
-    public AbstractEntityAdjunct(@SuppressWarnings("rawtypes") Map properties) {
-        super(properties);
-        _legacyNoConstructionInit = (properties != null) && Boolean.TRUE.equals(properties.get("noConstructionInit"));
-        
-        if (isLegacyConstruction()) {
-            AbstractBrooklynObject checkWeGetThis = configure(properties);
-            assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead of "+this;
-
-            boolean deferConstructionChecks = (properties.containsKey("deferConstructionChecks") && TypeCoercions.coerce(properties.get("deferConstructionChecks"), Boolean.class));
-            if (!deferConstructionChecks) {
-                FlagUtils.checkRequiredFields(this);
-            }
-        }
-    }
-
-    /**
-     * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
-     */
-    @Override
-    @Deprecated
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public AbstractEntityAdjunct configure(Map flags) {
-        // TODO only set on first time through
-        boolean isFirstTime = true;
-        
-        // allow config keys, and fields, to be set from these flags if they have a SetFromFlag annotation
-        // or if the value is a config key
-        for (Iterator<Map.Entry> iter = flags.entrySet().iterator(); iter.hasNext();) {
-            Map.Entry entry = iter.next();
-            if (entry.getKey() instanceof ConfigKey) {
-                ConfigKey key = (ConfigKey)entry.getKey();
-                if (adjunctType.getConfigKeys().contains(key)) {
-                    setConfig(key, entry.getValue());
-                } else {
-                    log.warn("Unknown configuration key {} for policy {}; ignoring", key, this);
-                    iter.remove();
-                }
-            }
-        }
-
-        ConfigBag bag = new ConfigBag().putAll(flags);
-        FlagUtils.setFieldsFromFlags(this, bag, isFirstTime);
-        FlagUtils.setAllConfigKeys(this, bag, false);
-        leftoverProperties.putAll(bag.getUnusedConfig());
-
-        //replace properties _contents_ with leftovers so subclasses see leftovers only
-        flags.clear();
-        flags.putAll(leftoverProperties);
-        leftoverProperties = flags;
-        
-        if (!truth(name) && flags.containsKey("displayName")) {
-            //TODO inconsistent with entity and location, where name is legacy and displayName is encouraged!
-            //'displayName' is a legacy way to refer to a policy's name
-            Preconditions.checkArgument(flags.get("displayName") instanceof CharSequence, "'displayName' property should be a string");
-            setDisplayName(flags.remove("displayName").toString());
-        }
-        
-        // set leftover flags should as config items; particularly useful when these have come from a brooklyn.config map 
-        for (Object flag: flags.keySet()) {
-            ConfigKey<Object> key = ConfigKeys.newConfigKey(Object.class, Strings.toString(flag));
-            if (config().getRaw(key).isPresent()) {
-                log.warn("Config '"+flag+"' on "+this+" conflicts with key already set; ignoring");
-            } else {
-                config().set(key, flags.get(flag));
-            }
-        }
-        
-        return this;
-    }
-    
-    /**
-     * Used for legacy-style policies/enrichers on rebind, to indicate that init() should not be called.
-     * Will likely be deleted in a future release; should not be called apart from by framework code.
-     */
-    @Beta
-    protected boolean isLegacyNoConstructionInit() {
-        return _legacyNoConstructionInit;
-    }
-
-    @Override
-    public ConfigurationSupportInternal config() {
-        return config;
-    }
-
-    private class BasicConfigurationSupport implements ConfigurationSupportInternal {
-
-        @Override
-        public <T> T get(ConfigKey<T> key) {
-            return configsInternal.getConfig(key);
-        }
-
-        @Override
-        public <T> T get(HasConfigKey<T> key) {
-            return get(key.getConfigKey());
-        }
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public <T> T set(ConfigKey<T> key, T val) {
-            if (entity != null && isRunning()) {
-                doReconfigureConfig(key, val);
-            }
-            T result = (T) configsInternal.setConfig(key, val);
-            onChanged();
-            return result;
-        }
-
-        @Override
-        public <T> T set(HasConfigKey<T> key, T val) {
-            return setConfig(key.getConfigKey(), val);
-        }
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public <T> T set(ConfigKey<T> key, Task<T> val) {
-            if (entity != null && isRunning()) {
-                // TODO Support for AbstractEntityAdjunct
-                throw new UnsupportedOperationException();
-            }
-            T result = (T) configsInternal.setConfig(key, val);
-            onChanged();
-            return result;
-        }
-
-        @Override
-        public <T> T set(HasConfigKey<T> key, Task<T> val) {
-            return set(key.getConfigKey(), val);
-        }
-
-        @Override
-        public ConfigBag getBag() {
-            return getLocalBag();
-        }
-
-        @Override
-        public ConfigBag getLocalBag() {
-            return ConfigBag.newInstance(configsInternal.getAllConfig());
-        }
-
-        @Override
-        public Maybe<Object> getRaw(ConfigKey<?> key) {
-            return configsInternal.getConfigRaw(key, true);
-        }
-
-        @Override
-        public Maybe<Object> getRaw(HasConfigKey<?> key) {
-            return getRaw(key.getConfigKey());
-        }
-
-        @Override
-        public Maybe<Object> getLocalRaw(ConfigKey<?> key) {
-            return configsInternal.getConfigRaw(key, false);
-        }
-
-        @Override
-        public Maybe<Object> getLocalRaw(HasConfigKey<?> key) {
-            return getLocalRaw(key.getConfigKey());
-        }
-
-        @Override
-        public void addToLocalBag(Map<String, ?> vals) {
-            configsInternal.addToLocalBag(vals);
-        }
-        
-        @Override
-        public void removeFromLocalBag(String key) {
-            configsInternal.removeFromLocalBag(key);
-        }
-        
-        @Override
-        public void refreshInheritedConfig() {
-            // no-op for location
-        }
-        
-        @Override
-        public void refreshInheritedConfigOfChildren() {
-            // no-op for location
-        }
-    }
-
-    public <T> T getConfig(ConfigKey<T> key) {
-        return config().get(key);
-    }
-    
-    protected <K> K getRequiredConfig(ConfigKey<K> key) {
-        K result = config().get(key);
-        if (result==null) 
-            throw new NullPointerException("Value required for '"+key.getName()+"' in "+this);
-        return result;
-    }
-
-    @Override
-    @Deprecated
-    public <T> T setConfig(ConfigKey<T> key, T val) {
-        return config().set(key, val);
-    }
-    
-    // TODO make immutable
-    /** for inspection only */
-    @Beta
-    @Deprecated
-    public ConfigMap getConfigMap() {
-        return configsInternal;
-    }
-    
-    /**
-     * Invoked whenever a config change is applied after management is started.
-     * Default implementation throws an exception to disallow the change. 
-     * Can be overridden to return (allowing the change) or to make other changes 
-     * (if necessary), and of course it can do this selectively and call the super to disallow any others. */
-    protected <T> void doReconfigureConfig(ConfigKey<T> key, T val) {
-        throw new UnsupportedOperationException("reconfiguring "+key+" unsupported for "+this);
-    }
-    
-    @Override
-    protected void onTagsChanged() {
-        onChanged();
-    }
-    
-    protected abstract void onChanged();
-    
-    protected AdjunctType getAdjunctType() {
-        return adjunctType;
-    }
-    
-    @Override
-    public String getDisplayName() {
-        if (name!=null && name.length()>0) return name;
-        return getClass().getCanonicalName();
-    }
-    
-    public void setDisplayName(String name) {
-        this.name = name;
-    }
-
-    public void setEntity(EntityLocal entity) {
-        if (destroyed.get()) throw new IllegalStateException("Cannot set entity on a destroyed entity adjunct");
-        this.entity = entity;
-        if (entity!=null && getCatalogItemId() == null) {
-            setCatalogItemId(entity.getCatalogItemId());
-        }
-    }
-    
-    /** @deprecated since 0.7.0 only {@link AbstractEnricher} has emit convenience */
-    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) {
-            entity.setAttribute((AttributeSensor<T>)sensor, newVal);
-        } else { 
-            entity.emit(sensor, newVal);
-        }
-    }
-
-    protected synchronized SubscriptionTracker getSubscriptionTracker() {
-        if (_subscriptionTracker!=null) return _subscriptionTracker;
-        if (entity==null) return null;
-        _subscriptionTracker = new SubscriptionTracker(((EntityInternal)entity).getManagementSupport().getSubscriptionContext());
-        return _subscriptionTracker;
-    }
-    
-    /** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */
-    protected <T> SubscriptionHandle subscribe(Entity producer, Sensor<T> sensor, SensorEventListener<? super T> listener) {
-        if (!checkCanSubscribe()) return null;
-        return getSubscriptionTracker().subscribe(producer, sensor, listener);
-    }
-
-    /** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */
-    protected <T> SubscriptionHandle subscribeToMembers(Group producerGroup, Sensor<T> sensor, SensorEventListener<? super T> listener) {
-        if (!checkCanSubscribe(producerGroup)) return null;
-        return getSubscriptionTracker().subscribeToMembers(producerGroup, sensor, listener);
-    }
-
-    /** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */
-    protected <T> SubscriptionHandle subscribeToChildren(Entity producerParent, Sensor<T> sensor, SensorEventListener<? super T> listener) {
-        if (!checkCanSubscribe(producerParent)) return null;
-        return getSubscriptionTracker().subscribeToChildren(producerParent, sensor, listener);
-    }
-
-    /** @deprecated since 0.7.0 use {@link #checkCanSubscribe(Entity)} */
-    @Deprecated
-    protected boolean check(Entity requiredEntity) {
-        return checkCanSubscribe(requiredEntity);
-    }
-    /** returns false if deleted, throws exception if invalid state, otherwise true.
-     * okay if entity is not yet managed (but not if entity is no longer managed). */
-    protected boolean checkCanSubscribe(Entity producer) {
-        if (destroyed.get()) return false;
-        if (producer==null) throw new IllegalStateException(this+" given a null target for subscription");
-        if (entity==null) throw new IllegalStateException(this+" cannot subscribe to "+producer+" because it is not associated to an entity");
-        if (((EntityInternal)entity).getManagementSupport().isNoLongerManaged()) throw new IllegalStateException(this+" cannot subscribe to "+producer+" because the associated entity "+entity+" is no longer managed");
-        return true;
-    }
-    protected boolean checkCanSubscribe() {
-        if (destroyed.get()) return false;
-        if (entity==null) throw new IllegalStateException(this+" cannot subscribe because it is not associated to an entity");
-        if (((EntityInternal)entity).getManagementSupport().isNoLongerManaged()) throw new IllegalStateException(this+" cannot subscribe because the associated entity "+entity+" is no longer managed");
-        return true;
-    }
-        
-    /**
-     * Unsubscribes the given producer.
-     *
-     * @see SubscriptionContext#unsubscribe(SubscriptionHandle)
-     */
-    protected boolean unsubscribe(Entity producer) {
-        if (destroyed.get()) return false;
-        return getSubscriptionTracker().unsubscribe(producer);
-    }
-
-    /**
-    * Unsubscribes the given producer.
-    *
-    * @see SubscriptionContext#unsubscribe(SubscriptionHandle)
-    */
-   protected boolean unsubscribe(Entity producer, SubscriptionHandle handle) {
-       if (destroyed.get()) return false;
-       return getSubscriptionTracker().unsubscribe(producer, handle);
-   }
-
-    /**
-    * @return a list of all subscription handles
-    */
-    protected Collection<SubscriptionHandle> getAllSubscriptions() {
-        SubscriptionTracker tracker = getSubscriptionTracker();
-        return (tracker != null) ? tracker.getAllSubscriptions() : Collections.<SubscriptionHandle>emptyList();
-    }
-    
-    /** 
-     * Unsubscribes and clears all managed subscriptions; is called by the owning entity when a policy is removed
-     * and should always be called by any subclasses overriding this method
-     */
-    public void destroy() {
-        destroyed.set(true);
-        SubscriptionTracker tracker = getSubscriptionTracker();
-        if (tracker != null) tracker.unsubscribeAll();
-    }
-    
-    @Override
-    public boolean isDestroyed() {
-        return destroyed.get();
-    }
-    
-    @Override
-    public boolean isRunning() {
-        return !isDestroyed();
-    }
-
-    @Override
-    public String getUniqueTag() {
-        return uniqueTag;
-    }
-
-    public TagSupport tags() {
-        return new AdjunctTagSupport();
-    }
-
-    public class AdjunctTagSupport extends BasicTagSupport {
-        @Override
-        public Set<Object> getTags() {
-            ImmutableSet.Builder<Object> rb = ImmutableSet.builder().addAll(super.getTags());
-            if (getUniqueTag()!=null) rb.add(getUniqueTag());
-            return rb.build();
-        }
-        public String getUniqueTag() {
-            return AbstractEntityAdjunct.this.getUniqueTag();
-        }
-        public void setUniqueTag(String uniqueTag) {
-            AbstractEntityAdjunct.this.uniqueTag = uniqueTag;
-        }
-    }
-
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(getClass()).omitNullValues()
-                .add("name", name)
-                .add("uniqueTag", uniqueTag)
-                .add("running", isRunning())
-                .add("entity", entity)
-                .add("id", getId())
-                .toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java b/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.java
deleted file mode 100644
index e935e4b..0000000
--- a/core/src/main/java/brooklyn/policy/basic/AbstractPolicy.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 brooklyn.policy.basic;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.brooklyn.api.entity.rebind.RebindSupport;
-import org.apache.brooklyn.api.entity.trait.Configurable;
-import org.apache.brooklyn.api.mementos.PolicyMemento;
-import org.apache.brooklyn.api.policy.Policy;
-import org.apache.brooklyn.api.policy.PolicyType;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.rebind.BasicPolicyRebindSupport;
-
-import com.google.common.base.Objects;
-
-/**
- * Base {@link Policy} implementation; all policies should extend this or its children
- */
-public abstract class AbstractPolicy extends AbstractEntityAdjunct implements Policy, Configurable {
-    @SuppressWarnings("unused")
-    private static final Logger log = LoggerFactory.getLogger(AbstractPolicy.class);
-
-    protected String policyStatus;
-    protected AtomicBoolean suspended = new AtomicBoolean(false);
-
-    private final PolicyDynamicType policyType;
-    
-    public AbstractPolicy() {
-        this(Collections.emptyMap());
-    }
-    
-    public AbstractPolicy(Map<?,?> flags) {
-        super(flags);
-        
-        // TODO Don't let `this` reference escape during construction
-        policyType = new PolicyDynamicType(this);
-        
-        if (isLegacyConstruction() && !isLegacyNoConstructionInit()) {
-            init();
-        }
-    }
-
-    @Override
-    public PolicyType getPolicyType() {
-        return policyType.getSnapshot();
-    }
-
-    @Override
-    public void suspend() {
-        suspended.set(true);
-    }
-
-    @Override
-    public void resume() {
-        suspended.set(false);
-    }
-
-    @Override
-    public boolean isSuspended() {
-        if (suspended==null) {
-            // only if accessed during construction in super, e.g. by a call to toString in configure
-            return true;
-        }
-        return suspended.get();
-    }
-
-    @Override
-    public void destroy(){
-        suspend();
-        super.destroy();
-    }
-
-    @Override
-    public boolean isRunning() {
-        return !isSuspended() && !isDestroyed();
-    }
-
-    @Override
-    protected void onChanged() {
-        // currently changes simply trigger re-persistence; there is no intermediate listener as we do for EntityChangeListener
-        if (getManagementContext() != null) {
-            getManagementContext().getRebindManager().getChangeListener().onChanged(this);
-        }
-    }
-    
-    @Override
-    public RebindSupport<PolicyMemento> getRebindSupport() {
-        return new BasicPolicyRebindSupport(this);
-    }
-
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(getClass())
-                .add("name", name)
-                .add("running", isRunning())
-                .toString();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/policy/basic/AdjunctType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/AdjunctType.java b/core/src/main/java/brooklyn/policy/basic/AdjunctType.java
deleted file mode 100644
index f53f822..0000000
--- a/core/src/main/java/brooklyn/policy/basic/AdjunctType.java
+++ /dev/null
@@ -1,174 +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 brooklyn.policy.basic;
-
-import java.io.Serializable;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.brooklyn.api.policy.EntityAdjunct;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.config.ConfigKey.HasConfigKey;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Maps;
-
-/**
- * This is the actual type of a policy instance at runtime.
- */
-public class AdjunctType implements Serializable {
-    private static final long serialVersionUID = -662979234559595903L;
-
-    private static final Logger LOG = LoggerFactory.getLogger(AdjunctType.class);
-
-    private final String name;
-    private final Map<String, ConfigKey<?>> configKeys;
-    private final Set<ConfigKey<?>> configKeysSet;
-
-    public AdjunctType(AbstractEntityAdjunct adjunct) {
-        this(adjunct.getClass(), adjunct);
-    }
-    
-    protected AdjunctType(Class<? extends EntityAdjunct> clazz) {
-        this(clazz, null);
-    }
-    
-    private AdjunctType(Class<? extends EntityAdjunct> clazz, AbstractEntityAdjunct adjunct) {
-        name = clazz.getCanonicalName();
-        configKeys = Collections.unmodifiableMap(findConfigKeys(clazz, null));
-        configKeysSet = ImmutableSet.copyOf(this.configKeys.values());
-        if (LOG.isTraceEnabled())
-            LOG.trace("Policy {} config keys: {}", name, Joiner.on(", ").join(configKeys.keySet()));
-    }
-    
-    AdjunctType(String name, Map<String, ConfigKey<?>> configKeys) {
-        this.name = name;
-        this.configKeys = ImmutableMap.copyOf(configKeys);
-        this.configKeysSet = ImmutableSet.copyOf(this.configKeys.values());
-    }
-
-    public String getName() {
-        return name;
-    }
-    
-    public Set<ConfigKey<?>> getConfigKeys() {
-        return configKeysSet;
-    }
-    
-    public ConfigKey<?> getConfigKey(String name) {
-        return configKeys.get(name);
-    }
-    
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(name, configKeys);
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (getClass() != obj.getClass()) return false;
-        AdjunctType o = (AdjunctType) obj;
-        if (!Objects.equal(name, o.getName())) return false;
-        if (!Objects.equal(getConfigKeys(), o.getConfigKeys())) return false;
-        return true;
-    }
-    
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(name)
-                .add("configKeys", configKeys)
-                .toString();
-    }
-    
-    /**
-     * Finds the config keys defined on the entity's class, statics and optionally any non-static (discouraged).
-     */
-    // TODO Remove duplication from EntityDynamicType
-    protected static Map<String,ConfigKey<?>> findConfigKeys(Class<? extends EntityAdjunct> clazz, EntityAdjunct optionalInstance) {
-        try {
-            Map<String,ConfigKey<?>> result = Maps.newLinkedHashMap();
-            Map<String,Field> configFields = Maps.newLinkedHashMap();
-            for (Field f : clazz.getFields()) {
-                boolean isConfigKey = ConfigKey.class.isAssignableFrom(f.getType());
-                if (!isConfigKey) {
-                    if (!HasConfigKey.class.isAssignableFrom(f.getType())) {
-                        // neither ConfigKey nor HasConfigKey
-                        continue;
-                    }
-                }
-                if (!Modifier.isStatic(f.getModifiers())) {
-                    // require it to be static or we have an instance
-                    LOG.warn("Discouraged use of non-static config key "+f+" defined in " + (optionalInstance!=null ? optionalInstance : clazz));
-                    if (optionalInstance==null) continue;
-                }
-                ConfigKey<?> k = isConfigKey ? (ConfigKey<?>) f.get(optionalInstance) : 
-                    ((HasConfigKey<?>)f.get(optionalInstance)).getConfigKey();
-
-                Field alternativeField = configFields.get(k.getName());
-                // Allow overriding config keys (e.g. to set default values) when there is an assignable-from relationship between classes
-                Field definitiveField = alternativeField != null ? inferSubbestField(alternativeField, f) : f;
-                boolean skip = false;
-                if (definitiveField != f) {
-                    // If they refer to the _same_ instance, just keep the one we already have
-                    if (alternativeField.get(optionalInstance) == f.get(optionalInstance)) skip = true;
-                }
-                if (skip) {
-                    //nothing
-                } else if (definitiveField == f) {
-                    result.put(k.getName(), k);
-                    configFields.put(k.getName(), f);
-                } else if (definitiveField != null) {
-                    if (LOG.isDebugEnabled()) LOG.debug("multiple definitions for config key {} on {}; preferring that in sub-class: {} to {}", new Object[] {
-                            k.getName(), optionalInstance!=null ? optionalInstance : clazz, alternativeField, f});
-                } else if (definitiveField == null) {
-                    LOG.warn("multiple definitions for config key {} on {}; preferring {} to {}", new Object[] {
-                            k.getName(), optionalInstance!=null ? optionalInstance : clazz, alternativeField, f});
-                }
-            }
-            
-            return result;
-        } catch (IllegalAccessException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-    
-    /**
-     * Gets the field that is in the sub-class; or null if one field does not come from a sub-class of the other field's class
-     */
-    // TODO Remove duplication from EntityDynamicType
-    private static Field inferSubbestField(Field f1, Field f2) {
-        Class<?> c1 = f1.getDeclaringClass();
-        Class<?> c2 = f2.getDeclaringClass();
-        boolean isSuper1 = c1.isAssignableFrom(c2);
-        boolean isSuper2 = c2.isAssignableFrom(c1);
-        return (isSuper1) ? (isSuper2 ? null : f2) : (isSuper2 ? f1 : null);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/policy/basic/ConfigMapImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/ConfigMapImpl.java b/core/src/main/java/brooklyn/policy/basic/ConfigMapImpl.java
deleted file mode 100644
index 467eb05..0000000
--- a/core/src/main/java/brooklyn/policy/basic/ConfigMapImpl.java
+++ /dev/null
@@ -1,140 +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 brooklyn.policy.basic;
-
-import static brooklyn.util.GroovyJavaMethods.elvis;
-
-import java.util.Collections;
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.basic.EntityLocal;
-import org.apache.brooklyn.api.management.ExecutionContext;
-import org.apache.brooklyn.core.util.flags.TypeCoercions;
-import org.apache.brooklyn.core.util.internal.ConfigKeySelfExtracting;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Maps;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.config.internal.AbstractConfigMapImpl;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.EntityInternal;
-import brooklyn.entity.basic.Sanitizer;
-import brooklyn.event.basic.StructuredConfigKey;
-import brooklyn.util.guava.Maybe;
-
-public class ConfigMapImpl extends AbstractConfigMapImpl {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ConfigMapImpl.class);
-
-    /** policy against which config resolution / task execution will occur */
-    private final AbstractEntityAdjunct adjunct;
-
-    /*
-     * TODO An alternative implementation approach would be to have:
-     *   setParent(Entity o, Map<ConfigKey,Object> inheritedConfig=[:])
-     * The idea is that the parent could in theory decide explicitly what in its config
-     * would be shared.
-     * I (Aled) am undecided as to whether that would be better...
-     * 
-     * (Alex) i lean toward the config key getting to make the decision
-     */
-
-    public ConfigMapImpl(AbstractEntityAdjunct adjunct) {
-        this.adjunct = Preconditions.checkNotNull(adjunct, "AbstractEntityAdjunct must be specified");
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <T> T getConfig(ConfigKey<T> key, T defaultValue) {
-        // FIXME What about inherited task in config?!
-        //              alex says: think that should work, no?
-        // FIXME What if someone calls getConfig on a task, before setting parent app?
-        //              alex says: not supported (throw exception, or return the task)
-        
-        // In case this entity class has overridden the given key (e.g. to set default), then retrieve this entity's key
-        // TODO If ask for a config value that's not in our configKeys, should we really continue with rest of method and return key.getDefaultValue?
-        //      e.g. SshBasedJavaAppSetup calls setAttribute(JMX_USER), which calls getConfig(JMX_USER)
-        //           but that example doesn't have a default...
-        ConfigKey<T> ownKey = adjunct!=null ? (ConfigKey<T>)elvis(adjunct.getAdjunctType().getConfigKey(key.getName()), key) : key;
-        
-        // Don't use groovy truth: if the set value is e.g. 0, then would ignore set value and return default!
-        if (ownKey instanceof ConfigKeySelfExtracting) {
-            if (((ConfigKeySelfExtracting<T>)ownKey).isSet(ownConfig)) {
-                // FIXME Should we support config from futures? How to get execution context before setEntity?
-                EntityLocal entity = adjunct.entity;
-                ExecutionContext exec = (entity != null) ? ((EntityInternal)entity).getExecutionContext() : null;
-                return ((ConfigKeySelfExtracting<T>)ownKey).extractValue(ownConfig, exec);
-            }
-        } else {
-            LOG.warn("Config key {} of {} is not a ConfigKeySelfExtracting; cannot retrieve value; returning default", ownKey, this);
-        }
-        return TypeCoercions.coerce((defaultValue != null) ? defaultValue : ownKey.getDefaultValue(), key.getTypeToken());
-    }
-    
-    @Override
-    public Maybe<Object> getConfigRaw(ConfigKey<?> key, boolean includeInherited) {
-        if (ownConfig.containsKey(key)) return Maybe.of(ownConfig.get(key));
-        return Maybe.absent();
-    }
-    
-    /** returns the config of this policy */
-    @Override
-    public Map<ConfigKey<?>,Object> getAllConfig() {
-        // Don't use ImmutableMap because valide for values to be null
-        return Collections.unmodifiableMap(Maps.newLinkedHashMap(ownConfig));
-    }
-
-    public Object setConfig(ConfigKey<?> key, Object v) {
-        Object val = coerceConfigVal(key, v);
-        if (key instanceof StructuredConfigKey) {
-            return ((StructuredConfigKey)key).applyValueToMap(val, ownConfig);
-        } else {
-            return ownConfig.put(key, val);
-        }
-    }
-    
-    public void addToLocalBag(Map<String, ?> vals) {
-        for (Map.Entry<String, ?> entry : vals.entrySet()) {
-            setConfig(ConfigKeys.newConfigKey(Object.class, entry.getKey()), entry.getValue());
-        }
-    }
-
-    public void removeFromLocalBag(String key) {
-        ownConfig.remove(key);
-    }
-
-    @Override
-    public ConfigMapImpl submap(Predicate<ConfigKey<?>> filter) {
-        ConfigMapImpl m = new ConfigMapImpl(adjunct);
-        for (Map.Entry<ConfigKey<?>,Object> entry: ownConfig.entrySet())
-            if (filter.apply(entry.getKey()))
-                m.ownConfig.put(entry.getKey(), entry.getValue());
-        return m;
-    }
-
-    @Override
-    public String toString() {
-        return super.toString()+"[own="+Sanitizer.sanitize(ownConfig)+"]";
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/policy/basic/GeneralPurposePolicy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/GeneralPurposePolicy.java b/core/src/main/java/brooklyn/policy/basic/GeneralPurposePolicy.java
deleted file mode 100644
index 0600006..0000000
--- a/core/src/main/java/brooklyn/policy/basic/GeneralPurposePolicy.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 brooklyn.policy.basic;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * @deprecated since 0.7.0; will be either deleted or moved to tests
- */
-@Deprecated
-public class GeneralPurposePolicy extends AbstractPolicy {
-    public GeneralPurposePolicy() {
-        this(Collections.emptyMap());
-    }
-    public GeneralPurposePolicy(Map properties) {
-        super(properties);
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/policy/basic/Policies.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/Policies.java b/core/src/main/java/brooklyn/policy/basic/Policies.java
deleted file mode 100644
index 887546a..0000000
--- a/core/src/main/java/brooklyn/policy/basic/Policies.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 brooklyn.policy.basic;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.basic.EntityLocal;
-import org.apache.brooklyn.api.event.Sensor;
-import org.apache.brooklyn.api.event.SensorEvent;
-import org.apache.brooklyn.api.event.SensorEventListener;
-import org.apache.brooklyn.api.policy.Policy;
-
-import groovy.lang.Closure;
-import brooklyn.entity.basic.Lifecycle;
-import brooklyn.policy.basic.AbstractPolicy;
-
-@SuppressWarnings({"rawtypes","unchecked"})
-public class Policies {
-
-    public static SensorEventListener listenerFromValueClosure(final Closure code) {
-        return new SensorEventListener() {
-            @Override
-            public void onEvent(SensorEvent event) {
-                code.call(event.getValue());
-            }
-        };
-    }
-    
-    public static <T> Policy newSingleSensorValuePolicy(final Sensor<T> sensor, final Closure code) {
-        return new AbstractPolicy() {
-            @Override
-            public void setEntity(EntityLocal entity) {
-                super.setEntity(entity);
-                entity.subscribe(entity, sensor, listenerFromValueClosure(code));
-            }
-        };
-    }
-    
-    public static <S,T> Policy newSingleSensorValuePolicy(final Entity remoteEntity, final Sensor<T> remoteSensor, 
-            final Closure code) {
-        return new AbstractPolicy() {
-            @Override
-            public void setEntity(EntityLocal entity) {
-                super.setEntity(entity);
-                entity.subscribe(remoteEntity, remoteSensor, listenerFromValueClosure(code));
-            }
-        };
-    }
-
-    public static Lifecycle getPolicyStatus(Policy p) {
-        if (p.isRunning()) return Lifecycle.RUNNING;
-        if (p.isDestroyed()) return Lifecycle.DESTROYED;
-        if (p.isSuspended()) return Lifecycle.STOPPED;
-        // TODO could policy be in an error state?
-        return Lifecycle.CREATED;        
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/policy/basic/PolicyDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/PolicyDynamicType.java b/core/src/main/java/brooklyn/policy/basic/PolicyDynamicType.java
deleted file mode 100644
index b6d3c6d..0000000
--- a/core/src/main/java/brooklyn/policy/basic/PolicyDynamicType.java
+++ /dev/null
@@ -1,44 +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 brooklyn.policy.basic;
-
-import org.apache.brooklyn.api.policy.Policy;
-import org.apache.brooklyn.api.policy.PolicyType;
-
-import brooklyn.basic.BrooklynDynamicType;
-
-public class PolicyDynamicType extends BrooklynDynamicType<Policy, AbstractPolicy> {
-
-    public PolicyDynamicType(Class<? extends Policy> type) {
-        super(type);
-    }
-    
-    public PolicyDynamicType(AbstractPolicy policy) {
-        super(policy);
-    }
-    
-    public PolicyType getSnapshot() {
-        return (PolicyType) super.getSnapshot();
-    }
-
-    @Override
-    protected PolicyTypeSnapshot newSnapshot() {
-        return new PolicyTypeSnapshot(name, value(configKeys));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/brooklyn/policy/basic/PolicyTypeSnapshot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/policy/basic/PolicyTypeSnapshot.java b/core/src/main/java/brooklyn/policy/basic/PolicyTypeSnapshot.java
deleted file mode 100644
index b6d2f33..0000000
--- a/core/src/main/java/brooklyn/policy/basic/PolicyTypeSnapshot.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 brooklyn.policy.basic;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.policy.PolicyType;
-
-import brooklyn.basic.BrooklynTypeSnapshot;
-import brooklyn.config.ConfigKey;
-
-public class PolicyTypeSnapshot extends BrooklynTypeSnapshot implements PolicyType {
-    private static final long serialVersionUID = 4670930188951106009L;
-    
-    PolicyTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) {
-        super(name, configKeys);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) return true;
-        return (obj instanceof PolicyTypeSnapshot) && super.equals(obj);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractEntityAdjunct.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractEntityAdjunct.java b/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractEntityAdjunct.java
new file mode 100644
index 0000000..eda106f
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractEntityAdjunct.java
@@ -0,0 +1,510 @@
+/*
+ * 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.policy.basic;
+
+import static brooklyn.util.GroovyJavaMethods.truth;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.Group;
+import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.api.entity.trait.Configurable;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.api.event.Sensor;
+import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.api.management.SubscriptionContext;
+import org.apache.brooklyn.api.management.SubscriptionHandle;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.policy.EntityAdjunct;
+import org.apache.brooklyn.core.management.internal.SubscriptionTracker;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.basic.AbstractBrooklynObject;
+import brooklyn.basic.BrooklynObjectInternal;
+import brooklyn.config.ConfigKey;
+import brooklyn.config.ConfigKey.HasConfigKey;
+import brooklyn.config.ConfigMap;
+import brooklyn.enricher.basic.AbstractEnricher;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.text.Strings;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+
+
+/**
+ * Common functionality for policies and enrichers
+ */
+public abstract class AbstractEntityAdjunct extends AbstractBrooklynObject implements BrooklynObjectInternal, EntityAdjunct, Configurable {
+    private static final Logger log = LoggerFactory.getLogger(AbstractEntityAdjunct.class);
+
+    private boolean _legacyNoConstructionInit;
+
+    /**
+     * @deprecated since 0.7.0; leftover properties are put into config, since when coming from yaml this is normal.
+     */
+    @Deprecated
+    protected Map<String,Object> leftoverProperties = Maps.newLinkedHashMap();
+
+    protected transient ExecutionContext execution;
+
+    private final BasicConfigurationSupport config = new BasicConfigurationSupport();
+    
+    /**
+     * The config values of this entity. Updating this map should be done
+     * via {@link #config()}.
+     * 
+     * @deprecated since 0.7.0; use {@link #config()} instead; this field may be made private or deleted in a future release.
+     */
+    @Deprecated
+    protected final ConfigMapImpl configsInternal = new ConfigMapImpl(this);
+
+    /**
+     * @deprecated since 0.7.0; use {@link #getAdjunctType()} instead; this field may be made private or deleted in a future release.
+     */
+    @Deprecated
+    protected final AdjunctType adjunctType = new AdjunctType(this);
+
+    @SetFromFlag
+    protected String name;
+    
+    protected transient EntityLocal entity;
+    
+    /** not for direct access; refer to as 'subscriptionTracker' via getter so that it is initialized */
+    protected transient SubscriptionTracker _subscriptionTracker;
+    
+    private AtomicBoolean destroyed = new AtomicBoolean(false);
+    
+    @SetFromFlag(value="uniqueTag")
+    protected String uniqueTag;
+
+    public AbstractEntityAdjunct() {
+        this(Collections.emptyMap());
+    }
+    
+    public AbstractEntityAdjunct(@SuppressWarnings("rawtypes") Map properties) {
+        super(properties);
+        _legacyNoConstructionInit = (properties != null) && Boolean.TRUE.equals(properties.get("noConstructionInit"));
+        
+        if (isLegacyConstruction()) {
+            AbstractBrooklynObject checkWeGetThis = configure(properties);
+            assert this.equals(checkWeGetThis) : this+" configure method does not return itself; returns "+checkWeGetThis+" instead of "+this;
+
+            boolean deferConstructionChecks = (properties.containsKey("deferConstructionChecks") && TypeCoercions.coerce(properties.get("deferConstructionChecks"), Boolean.class));
+            if (!deferConstructionChecks) {
+                FlagUtils.checkRequiredFields(this);
+            }
+        }
+    }
+
+    /**
+     * @deprecated since 0.7.0; only used for legacy brooklyn types where constructor is called directly
+     */
+    @Override
+    @Deprecated
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public AbstractEntityAdjunct configure(Map flags) {
+        // TODO only set on first time through
+        boolean isFirstTime = true;
+        
+        // allow config keys, and fields, to be set from these flags if they have a SetFromFlag annotation
+        // or if the value is a config key
+        for (Iterator<Map.Entry> iter = flags.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = iter.next();
+            if (entry.getKey() instanceof ConfigKey) {
+                ConfigKey key = (ConfigKey)entry.getKey();
+                if (adjunctType.getConfigKeys().contains(key)) {
+                    setConfig(key, entry.getValue());
+                } else {
+                    log.warn("Unknown configuration key {} for policy {}; ignoring", key, this);
+                    iter.remove();
+                }
+            }
+        }
+
+        ConfigBag bag = new ConfigBag().putAll(flags);
+        FlagUtils.setFieldsFromFlags(this, bag, isFirstTime);
+        FlagUtils.setAllConfigKeys(this, bag, false);
+        leftoverProperties.putAll(bag.getUnusedConfig());
+
+        //replace properties _contents_ with leftovers so subclasses see leftovers only
+        flags.clear();
+        flags.putAll(leftoverProperties);
+        leftoverProperties = flags;
+        
+        if (!truth(name) && flags.containsKey("displayName")) {
+            //TODO inconsistent with entity and location, where name is legacy and displayName is encouraged!
+            //'displayName' is a legacy way to refer to a policy's name
+            Preconditions.checkArgument(flags.get("displayName") instanceof CharSequence, "'displayName' property should be a string");
+            setDisplayName(flags.remove("displayName").toString());
+        }
+        
+        // set leftover flags should as config items; particularly useful when these have come from a brooklyn.config map 
+        for (Object flag: flags.keySet()) {
+            ConfigKey<Object> key = ConfigKeys.newConfigKey(Object.class, Strings.toString(flag));
+            if (config().getRaw(key).isPresent()) {
+                log.warn("Config '"+flag+"' on "+this+" conflicts with key already set; ignoring");
+            } else {
+                config().set(key, flags.get(flag));
+            }
+        }
+        
+        return this;
+    }
+    
+    /**
+     * Used for legacy-style policies/enrichers on rebind, to indicate that init() should not be called.
+     * Will likely be deleted in a future release; should not be called apart from by framework code.
+     */
+    @Beta
+    protected boolean isLegacyNoConstructionInit() {
+        return _legacyNoConstructionInit;
+    }
+
+    @Override
+    public ConfigurationSupportInternal config() {
+        return config;
+    }
+
+    private class BasicConfigurationSupport implements ConfigurationSupportInternal {
+
+        @Override
+        public <T> T get(ConfigKey<T> key) {
+            return configsInternal.getConfig(key);
+        }
+
+        @Override
+        public <T> T get(HasConfigKey<T> key) {
+            return get(key.getConfigKey());
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T> T set(ConfigKey<T> key, T val) {
+            if (entity != null && isRunning()) {
+                doReconfigureConfig(key, val);
+            }
+            T result = (T) configsInternal.setConfig(key, val);
+            onChanged();
+            return result;
+        }
+
+        @Override
+        public <T> T set(HasConfigKey<T> key, T val) {
+            return setConfig(key.getConfigKey(), val);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T> T set(ConfigKey<T> key, Task<T> val) {
+            if (entity != null && isRunning()) {
+                // TODO Support for AbstractEntityAdjunct
+                throw new UnsupportedOperationException();
+            }
+            T result = (T) configsInternal.setConfig(key, val);
+            onChanged();
+            return result;
+        }
+
+        @Override
+        public <T> T set(HasConfigKey<T> key, Task<T> val) {
+            return set(key.getConfigKey(), val);
+        }
+
+        @Override
+        public ConfigBag getBag() {
+            return getLocalBag();
+        }
+
+        @Override
+        public ConfigBag getLocalBag() {
+            return ConfigBag.newInstance(configsInternal.getAllConfig());
+        }
+
+        @Override
+        public Maybe<Object> getRaw(ConfigKey<?> key) {
+            return configsInternal.getConfigRaw(key, true);
+        }
+
+        @Override
+        public Maybe<Object> getRaw(HasConfigKey<?> key) {
+            return getRaw(key.getConfigKey());
+        }
+
+        @Override
+        public Maybe<Object> getLocalRaw(ConfigKey<?> key) {
+            return configsInternal.getConfigRaw(key, false);
+        }
+
+        @Override
+        public Maybe<Object> getLocalRaw(HasConfigKey<?> key) {
+            return getLocalRaw(key.getConfigKey());
+        }
+
+        @Override
+        public void addToLocalBag(Map<String, ?> vals) {
+            configsInternal.addToLocalBag(vals);
+        }
+        
+        @Override
+        public void removeFromLocalBag(String key) {
+            configsInternal.removeFromLocalBag(key);
+        }
+        
+        @Override
+        public void refreshInheritedConfig() {
+            // no-op for location
+        }
+        
+        @Override
+        public void refreshInheritedConfigOfChildren() {
+            // no-op for location
+        }
+    }
+
+    public <T> T getConfig(ConfigKey<T> key) {
+        return config().get(key);
+    }
+    
+    protected <K> K getRequiredConfig(ConfigKey<K> key) {
+        K result = config().get(key);
+        if (result==null) 
+            throw new NullPointerException("Value required for '"+key.getName()+"' in "+this);
+        return result;
+    }
+
+    @Override
+    @Deprecated
+    public <T> T setConfig(ConfigKey<T> key, T val) {
+        return config().set(key, val);
+    }
+    
+    // TODO make immutable
+    /** for inspection only */
+    @Beta
+    @Deprecated
+    public ConfigMap getConfigMap() {
+        return configsInternal;
+    }
+    
+    /**
+     * Invoked whenever a config change is applied after management is started.
+     * Default implementation throws an exception to disallow the change. 
+     * Can be overridden to return (allowing the change) or to make other changes 
+     * (if necessary), and of course it can do this selectively and call the super to disallow any others. */
+    protected <T> void doReconfigureConfig(ConfigKey<T> key, T val) {
+        throw new UnsupportedOperationException("reconfiguring "+key+" unsupported for "+this);
+    }
+    
+    @Override
+    protected void onTagsChanged() {
+        onChanged();
+    }
+    
+    protected abstract void onChanged();
+    
+    protected AdjunctType getAdjunctType() {
+        return adjunctType;
+    }
+    
+    @Override
+    public String getDisplayName() {
+        if (name!=null && name.length()>0) return name;
+        return getClass().getCanonicalName();
+    }
+    
+    public void setDisplayName(String name) {
+        this.name = name;
+    }
+
+    public void setEntity(EntityLocal entity) {
+        if (destroyed.get()) throw new IllegalStateException("Cannot set entity on a destroyed entity adjunct");
+        this.entity = entity;
+        if (entity!=null && getCatalogItemId() == null) {
+            setCatalogItemId(entity.getCatalogItemId());
+        }
+    }
+    
+    /** @deprecated since 0.7.0 only {@link AbstractEnricher} has emit convenience */
+    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) {
+            entity.setAttribute((AttributeSensor<T>)sensor, newVal);
+        } else { 
+            entity.emit(sensor, newVal);
+        }
+    }
+
+    protected synchronized SubscriptionTracker getSubscriptionTracker() {
+        if (_subscriptionTracker!=null) return _subscriptionTracker;
+        if (entity==null) return null;
+        _subscriptionTracker = new SubscriptionTracker(((EntityInternal)entity).getManagementSupport().getSubscriptionContext());
+        return _subscriptionTracker;
+    }
+    
+    /** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */
+    protected <T> SubscriptionHandle subscribe(Entity producer, Sensor<T> sensor, SensorEventListener<? super T> listener) {
+        if (!checkCanSubscribe()) return null;
+        return getSubscriptionTracker().subscribe(producer, sensor, listener);
+    }
+
+    /** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */
+    protected <T> SubscriptionHandle subscribeToMembers(Group producerGroup, Sensor<T> sensor, SensorEventListener<? super T> listener) {
+        if (!checkCanSubscribe(producerGroup)) return null;
+        return getSubscriptionTracker().subscribeToMembers(producerGroup, sensor, listener);
+    }
+
+    /** @see SubscriptionContext#subscribe(Entity, Sensor, SensorEventListener) */
+    protected <T> SubscriptionHandle subscribeToChildren(Entity producerParent, Sensor<T> sensor, SensorEventListener<? super T> listener) {
+        if (!checkCanSubscribe(producerParent)) return null;
+        return getSubscriptionTracker().subscribeToChildren(producerParent, sensor, listener);
+    }
+
+    /** @deprecated since 0.7.0 use {@link #checkCanSubscribe(Entity)} */
+    @Deprecated
+    protected boolean check(Entity requiredEntity) {
+        return checkCanSubscribe(requiredEntity);
+    }
+    /** returns false if deleted, throws exception if invalid state, otherwise true.
+     * okay if entity is not yet managed (but not if entity is no longer managed). */
+    protected boolean checkCanSubscribe(Entity producer) {
+        if (destroyed.get()) return false;
+        if (producer==null) throw new IllegalStateException(this+" given a null target for subscription");
+        if (entity==null) throw new IllegalStateException(this+" cannot subscribe to "+producer+" because it is not associated to an entity");
+        if (((EntityInternal)entity).getManagementSupport().isNoLongerManaged()) throw new IllegalStateException(this+" cannot subscribe to "+producer+" because the associated entity "+entity+" is no longer managed");
+        return true;
+    }
+    protected boolean checkCanSubscribe() {
+        if (destroyed.get()) return false;
+        if (entity==null) throw new IllegalStateException(this+" cannot subscribe because it is not associated to an entity");
+        if (((EntityInternal)entity).getManagementSupport().isNoLongerManaged()) throw new IllegalStateException(this+" cannot subscribe because the associated entity "+entity+" is no longer managed");
+        return true;
+    }
+        
+    /**
+     * Unsubscribes the given producer.
+     *
+     * @see SubscriptionContext#unsubscribe(SubscriptionHandle)
+     */
+    protected boolean unsubscribe(Entity producer) {
+        if (destroyed.get()) return false;
+        return getSubscriptionTracker().unsubscribe(producer);
+    }
+
+    /**
+    * Unsubscribes the given producer.
+    *
+    * @see SubscriptionContext#unsubscribe(SubscriptionHandle)
+    */
+   protected boolean unsubscribe(Entity producer, SubscriptionHandle handle) {
+       if (destroyed.get()) return false;
+       return getSubscriptionTracker().unsubscribe(producer, handle);
+   }
+
+    /**
+    * @return a list of all subscription handles
+    */
+    protected Collection<SubscriptionHandle> getAllSubscriptions() {
+        SubscriptionTracker tracker = getSubscriptionTracker();
+        return (tracker != null) ? tracker.getAllSubscriptions() : Collections.<SubscriptionHandle>emptyList();
+    }
+    
+    /** 
+     * Unsubscribes and clears all managed subscriptions; is called by the owning entity when a policy is removed
+     * and should always be called by any subclasses overriding this method
+     */
+    public void destroy() {
+        destroyed.set(true);
+        SubscriptionTracker tracker = getSubscriptionTracker();
+        if (tracker != null) tracker.unsubscribeAll();
+    }
+    
+    @Override
+    public boolean isDestroyed() {
+        return destroyed.get();
+    }
+    
+    @Override
+    public boolean isRunning() {
+        return !isDestroyed();
+    }
+
+    @Override
+    public String getUniqueTag() {
+        return uniqueTag;
+    }
+
+    public TagSupport tags() {
+        return new AdjunctTagSupport();
+    }
+
+    public class AdjunctTagSupport extends BasicTagSupport {
+        @Override
+        public Set<Object> getTags() {
+            ImmutableSet.Builder<Object> rb = ImmutableSet.builder().addAll(super.getTags());
+            if (getUniqueTag()!=null) rb.add(getUniqueTag());
+            return rb.build();
+        }
+        public String getUniqueTag() {
+            return AbstractEntityAdjunct.this.getUniqueTag();
+        }
+        public void setUniqueTag(String uniqueTag) {
+            AbstractEntityAdjunct.this.uniqueTag = uniqueTag;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(getClass()).omitNullValues()
+                .add("name", name)
+                .add("uniqueTag", uniqueTag)
+                .add("running", isRunning())
+                .add("entity", entity)
+                .add("id", getId())
+                .toString();
+    }
+}



[25/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/flags/FlagUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/flags/FlagUtils.java b/core/src/main/java/org/apache/brooklyn/core/util/flags/FlagUtils.java
new file mode 100644
index 0000000..6f28f9b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/flags/FlagUtils.java
@@ -0,0 +1,587 @@
+/*
+ * 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.util.flags;
+
+import static brooklyn.util.GroovyJavaMethods.elvis;
+import static brooklyn.util.GroovyJavaMethods.truth;
+import static com.google.common.base.Preconditions.checkNotNull;
+import groovy.lang.Closure;
+import groovy.lang.GroovyObject;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.trait.Configurable;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.config.ConfigKey.HasConfigKey;
+import brooklyn.util.GroovyJavaMethods;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+
+/** class to help transfer values passed as named arguments to other well-known variables/fields/objects;
+ * see the test case for example usage */
+public class FlagUtils {
+
+    public static final Logger log = LoggerFactory.getLogger(FlagUtils.class);
+    
+    private FlagUtils() {}
+    
+    /** see {@link #setFieldsFromFlags(Object o, ConfigBag)} */
+    public static Map<?, ?> setPublicFieldsFromFlags(Map<?, ?> flags, Object o) {
+        return setFieldsFromFlagsInternal(o, Arrays.asList(o.getClass().getFields()), flags, null, true);
+    }
+
+    /** see {@link #setFieldsFromFlags(Object, ConfigBag)} */
+    public static Map<?, ?> setFieldsFromFlags(Map<?, ?> flags, Object o) {
+        return setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), flags, null, true);
+    }
+    
+    /** sets all fields (including private and static, local and inherited) annotated {@link SetFromFlag} on the given object, 
+     * from the given flags map, returning just those flag-value pairs passed in which do not correspond to SetFromFlags fields 
+     * annotated ConfigKey and HasConfigKey fields are _configured_ (and we assume the object in that case is {@link Configurable});
+     * keys should be ConfigKey, HasConfigKey, or String;
+     * default values are also applied unless that is specified false on one of the variants of this method which takes such an argument
+     */
+    public static void setFieldsFromFlags(Object o, ConfigBag configBag) {
+        setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), configBag.getAllConfig(), configBag, true);
+    }
+
+    /** as {@link #setFieldsFromFlags(Object, ConfigBag)}, but allowing control over whether default values should be set */
+    public static void setFieldsFromFlags(Object o, ConfigBag configBag, boolean setDefaultVals) {
+        setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), configBag.getAllConfig(), configBag, setDefaultVals);
+    }
+
+    /** as {@link #setFieldsFromFlags(Object, ConfigBag)}, but specifying a subset of flags to use */
+    public static void setFieldsFromFlagsWithBag(Object o, Map<?,?> flags, ConfigBag configBag, boolean setDefaultVals) {
+        setFieldsFromFlagsInternal(o, getAllFields(o.getClass()), flags, configBag, setDefaultVals);
+    }
+
+    /**
+     * Sets the field with the given flag (if it exists) to the given value.
+     * Will attempt to coerce the value to the required type.
+     * Will respect "nullable" on the SetFromFlag annotation.
+     * 
+     * @throws IllegalArgumentException If fieldVal is null and the SetFromFlag annotation set nullable=false
+     */
+    public static boolean setFieldFromFlag(Object o, String flagName, Object fieldVal) {
+        return setFieldFromFlagInternal(checkNotNull(flagName, "flagName"), fieldVal, o, getAllFields(o.getClass()));
+    }
+    
+    /** get all fields (including private and static) on the given object and all supertypes, 
+     * that are annotated with SetFromFlags. 
+     */
+    public static Map<String, ?> getFieldsWithFlags(Object o) {
+        return getFieldsWithFlagsInternal(o, getAllFields(o.getClass()));
+    }
+    
+    /**
+     * Finds the {@link Field} on the given object annotated with the given name flag.
+     */
+    public static Field findFieldForFlag(String flagName, Object o) {
+        return findFieldForFlagInternal(flagName, o, getAllFields(o.getClass()));
+    }
+
+    /** get all fields (including private and static) and their values on the given object and all supertypes, 
+     * where the field is annotated with SetFromFlags. 
+     */
+    public static Map<String, Object> getFieldsWithFlagsExcludingModifiers(Object o, int excludingModifiers) {
+        List<Field> filteredFields = Lists.newArrayList();
+        for (Field contender : getAllFields(o.getClass())) {
+            if ((contender.getModifiers() & excludingModifiers) == 0) {
+                filteredFields.add(contender);
+            }
+        }
+        return getFieldsWithFlagsInternal(o, filteredFields);
+    }
+    
+    /** get all fields with the given modifiers, and their values on the given object and all supertypes, 
+     * where the field is annotated with SetFromFlags. 
+     */
+    public static Map<String, Object> getFieldsWithFlagsWithModifiers(Object o, int requiredModifiers) {
+        List<Field> filteredFields = Lists.newArrayList();
+        for (Field contender : getAllFields(o.getClass())) {
+            if ((contender.getModifiers() & requiredModifiers) == requiredModifiers) {
+                filteredFields.add(contender);
+            }
+        }
+        return getFieldsWithFlagsInternal(o, filteredFields);
+    }
+    
+    /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, 
+     * using the indicated flags/config-bag 
+     * @deprecated since 0.7.0 use {@link #setAllConfigKeys(Map, Configurable, boolean)} */
+    public static Map<String, ?> setAllConfigKeys(Map<String, ?> flagsOrConfig, Configurable instance) {
+        return setAllConfigKeys(flagsOrConfig, instance, false);
+    }
+    /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, 
+     * using the indicated flags/config-bag */
+    public static Map<String, ?> setAllConfigKeys(Map<String, ?> flagsOrConfig, Configurable instance, boolean includeFlags) {
+        ConfigBag bag = new ConfigBag().putAll(flagsOrConfig);
+        setAllConfigKeys(instance, bag, includeFlags);
+        return bag.getUnusedConfigMutable();
+    }
+    
+    /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, 
+     * using the indicated flags/config-bag 
+    * @deprecated since 0.7.0 use {@link #setAllConfigKeys(Configurable, ConfigBag, boolean)} */
+    public static void setAllConfigKeys(Configurable o, ConfigBag bag) {
+        setAllConfigKeys(o, bag, false);
+    }
+    /** sets _all_ accessible _{@link ConfigKey}_ and {@link HasConfigKey} fields on the given object, 
+     * using the indicated flags/config-bag */
+    public static void setAllConfigKeys(Configurable o, ConfigBag bag, boolean includeFlags) {
+        for (Field f: getAllFields(o.getClass())) {
+            ConfigKey<?> key = getFieldAsConfigKey(o, f);
+            if (key!=null) {
+                FlagConfigKeyAndValueRecord record = getFlagConfigKeyRecord(f, key, bag);
+                if ((includeFlags && record.isValuePresent()) || record.getConfigKeyMaybeValue().isPresent()) {
+                    setField(o, f, record.getValueOrNullPreferringConfigKey(), null);
+                }
+            }
+        }
+    }
+    
+    public static class FlagConfigKeyAndValueRecord {
+        private String flagName = null;
+        private ConfigKey<?> configKey = null;
+        private Maybe<Object> flagValue = Maybe.absent();
+        private Maybe<Object> configKeyValue = Maybe.absent();
+        
+        public String getFlagName() {
+            return flagName;
+        }
+        public ConfigKey<?> getConfigKey() {
+            return configKey;
+        }
+        public Maybe<Object> getFlagMaybeValue() {
+            return flagValue;
+        }
+        public Maybe<Object> getConfigKeyMaybeValue() {
+            return configKeyValue;
+        }
+        public Object getValueOrNullPreferringConfigKey() {
+            return getConfigKeyMaybeValue().or(getFlagMaybeValue()).orNull();
+        }
+        public Object getValueOrNullPreferringFlag() {
+            return getFlagMaybeValue().or(getConfigKeyMaybeValue()).orNull();
+        }
+        /** true if value is present for either flag or config key */
+        public boolean isValuePresent() {
+            return flagValue.isPresent() || configKeyValue.isPresent();
+        }
+        
+        @Override
+        public String toString() {
+            return Objects.toStringHelper(this).omitNullValues()
+                .add("flag", flagName)
+                .add("configKey", configKey)
+                .add("flagValue", flagValue.orNull())
+                .add("configKeyValue", configKeyValue.orNull())
+                .toString();
+        }
+    }
+    
+    /** gets all the flags/keys in the given config bag which are applicable to the given type's config keys and flags */
+    public static <T> List<FlagConfigKeyAndValueRecord> findAllFlagsAndConfigKeys(T optionalInstance, Class<? extends T> type, ConfigBag input) {
+        List<FlagConfigKeyAndValueRecord> output = new ArrayList<FlagUtils.FlagConfigKeyAndValueRecord>();
+        for (Field f: getAllFields(type)) {
+            ConfigKey<?> key = getFieldAsConfigKey(optionalInstance, f);
+            FlagConfigKeyAndValueRecord record = getFlagConfigKeyRecord(f, key, input);
+            if (record.isValuePresent())
+                output.add(record);
+        }
+        return output;
+    }
+
+    /** returns the flag/config-key record for the given input */
+    private static FlagConfigKeyAndValueRecord getFlagConfigKeyRecord(Field f, ConfigKey<?> key, ConfigBag input) {
+        FlagConfigKeyAndValueRecord result = new FlagConfigKeyAndValueRecord(); 
+        result.configKey = key;
+        if (key!=null && input.containsKey(key))
+            result.configKeyValue = Maybe.<Object>of(input.getStringKey(key.getName()));
+        SetFromFlag flag = f.getAnnotation(SetFromFlag.class);
+        if (flag!=null) {
+            result.flagName = flag.value();
+            if (input.containsKey(flag.value()))
+                result.flagValue = Maybe.of(input.getStringKey(flag.value()));
+        }
+        return result;
+    }
+
+    /** returns all fields on the given class, superclasses, and interfaces thereof, in that order of preference,
+     * (excluding fields on Object) */
+    public static List<Field> getAllFields(Class<?> base, Closure<Boolean> filter) {
+        return getAllFields(base, GroovyJavaMethods.<Field>predicateFromClosure(filter));
+    }
+    public static List<Field> getAllFields(Class<?> base) {
+        return getAllFields(base, Predicates.<Field>alwaysTrue());
+    }
+    public static List<Field> getAllFields(Class<?> base, Predicate<Field> filter) {
+        return getLocalFields(getAllAssignableTypes(base), filter);
+    }
+    /** returns all fields explicitly declared on the given classes */
+    public static List<Field> getLocalFields(List<Class<?>> classes) {
+        return getLocalFields(classes, Predicates.<Field>alwaysTrue());
+    }
+    public static List<Field> getLocalFields(List<Class<?>> classes, Closure<Boolean> filter) {
+        return getLocalFields(classes, GroovyJavaMethods.<Field>predicateFromClosure(filter));
+    }
+    public static List<Field> getLocalFields(List<Class<?>> classes, Predicate<Field> filter) {
+        List<Field> fields = Lists.newArrayList();
+        for (Class<?> c : classes) {
+            for (Field f : c.getDeclaredFields()) {
+                if (filter.apply(f)) fields.add(f);
+            }
+        }
+        return fields;
+    }
+    
+    /** returns base, superclasses, then interfaces */
+    public static List<Class<?>> getAllAssignableTypes(Class<?> base) {
+        return getAllAssignableTypes(base, new Predicate<Class<?>>() {
+            @Override public boolean apply(Class<?> it) {
+                return (it != Object.class) && (it != GroovyObject.class);
+            }
+        });
+    }
+    public static List<Class<?>> getAllAssignableTypes(Class<?> base, Closure<Boolean> filter) {
+        return getAllAssignableTypes(base, GroovyJavaMethods.<Class<?>>predicateFromClosure(filter));
+    }
+    public static List<Class<?>> getAllAssignableTypes(Class<?> base, Predicate<Class<?>> filter) {
+        List<Class<?>> classes = Lists.newArrayList();
+        for (Class<?> c = base; c != null; c = c.getSuperclass()) {
+            if (filter.apply(c)) classes.add(c);
+        }
+        for (int i=0; i<classes.size(); i++) {
+            for (Class<?> interf : classes.get(i).getInterfaces()) {
+                if (filter.apply(interf) && !(classes.contains(interf))) classes.add(interf);
+            }
+        }
+        return classes;
+    }
+    
+    private static Map<String, Object> getFieldsWithFlagsInternal(Object o, Collection<Field> fields) {
+        Map<String, Object> result = Maps.newLinkedHashMap();
+        for (Field f: fields) {
+            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
+            if (cf != null) {
+                String flagName = elvis(cf.value(), f.getName());
+                if (truth(flagName)) {
+                    result.put(flagName, getField(o, f));
+                } else {
+                    log.warn("Ignoring field {} of object {} as no flag name available", f, o);
+                }
+            }
+        }
+        return result;
+    }
+
+    private static Field findFieldForFlagInternal(String flagName, Object o, Collection<Field> fields) {
+        for (Field f: fields) {
+            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
+            if (cf != null) {
+                String contenderName = elvis(cf.value(), f.getName());
+                if (flagName.equals(contenderName)) {
+                    return f;
+                }
+            }
+        }
+        throw new NoSuchElementException("Field with flag "+flagName+" not found on "+o+" of type "+(o != null ? o.getClass() : null));
+    }
+
+    private static boolean setFieldFromFlagInternal(String flagName, Object fieldVal, Object o, Collection<Field> fields) {
+        for (Field f: fields) {
+            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
+            if (cf != null && flagName.equals(elvis(cf.value(), f.getName()))) {
+                setField(o, f, fieldVal, cf);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static Map<String, ?> setFieldsFromFlagsInternal(Object o, Collection<Field> fields, Map<?,?> flagsOrConfig, ConfigBag bag, boolean setDefaultVals) {
+        if (bag==null) bag = new ConfigBag().putAll(flagsOrConfig);
+        for (Field f: fields) {
+            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
+            if (cf!=null) setFieldFromConfig(o, f, bag, cf, setDefaultVals);
+        }
+        return bag.getUnusedConfigMutable();
+    }
+
+    private static void setFieldFromConfig(Object o, Field f, ConfigBag bag, SetFromFlag optionalAnnotation, boolean setDefaultVals) {
+        String flagName = optionalAnnotation==null ? null : (String)elvis(optionalAnnotation.value(), f.getName());
+        // prefer flag name, if present
+        if (truth(flagName) && bag.containsKey(flagName)) {
+            setField(o, f, bag.getStringKey(flagName), optionalAnnotation);
+            return;
+        }
+        // first check whether it is a key
+        ConfigKey<?> key = getFieldAsConfigKey(o, f);
+        if (key!=null && bag.containsKey(key)) {
+            Object uncoercedValue = bag.getStringKey(key.getName());
+            setField(o, f, uncoercedValue, optionalAnnotation);
+            return;
+        }
+        if (setDefaultVals && optionalAnnotation!=null && truth(optionalAnnotation.defaultVal())) {
+            Object oldValue;
+            try {
+                f.setAccessible(true);
+                oldValue = f.get(o);
+                if (oldValue==null || oldValue.equals(getDefaultValueForType(f.getType()))) {
+                    setField(o, f, optionalAnnotation.defaultVal(), optionalAnnotation);
+                }
+            } catch (Exception e) {
+                Exceptions.propagate(e);
+            }
+            return;
+        }
+    }
+
+    /** returns the given field as a config key, if it is an accessible config key, otherwise null */
+    private static ConfigKey<?> getFieldAsConfigKey(Object optionalInstance, Field f) {
+        if (optionalInstance==null) {
+            if ((f.getModifiers() & Modifier.STATIC)==0)
+                // non-static field on null instance, can't be set
+                return null;
+        }
+        if (ConfigKey.class.isAssignableFrom(f.getType())) {
+            return (ConfigKey<?>) getField(optionalInstance, f);
+        } else if (HasConfigKey.class.isAssignableFrom(f.getType())) {
+            return ((HasConfigKey<?>)getField(optionalInstance, f)).getConfigKey();
+        }
+        return null;
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static void setConfig(Object objectOfField, ConfigKey<?> key, Object value, SetFromFlag optionalAnnotation) {
+        if (objectOfField instanceof Configurable) {
+            ((Configurable)objectOfField).setConfig((ConfigKey)key, value);
+            return;
+        } else {
+            if (optionalAnnotation==null) {
+                log.warn("Cannot set key "+key.getName()+" on "+objectOfField+": containing class is not Configurable");
+            } else if (!key.getName().equals(optionalAnnotation.value())) {
+                log.warn("Cannot set key "+key.getName()+" on "+objectOfField+" from flag "+optionalAnnotation.value()+": containing class is not Configurable");
+            } else {
+                // if key and flag are the same, then it will probably happen automatically
+                if (log.isDebugEnabled())
+                    log.debug("Cannot set key "+key.getName()+" on "+objectOfField+" from flag "+optionalAnnotation.value()+": containing class is not Configurable");
+            }
+            return;
+        }
+    }
+    
+    /** sets the field to the value, after checking whether the given value can be set 
+     * respecting the constraints of the annotation 
+     */
+    public static void setField(Object objectOfField, Field f, Object value, SetFromFlag optionalAnnotation) {
+        try {
+            ConfigKey<?> key = getFieldAsConfigKey(objectOfField, f);
+            if (key!=null) {
+                setConfig(objectOfField, key, value, optionalAnnotation);
+                return;
+            }
+            
+            if (!f.isAccessible()) f.setAccessible(true);
+            if (optionalAnnotation!=null && optionalAnnotation.immutable()) {
+                Object oldValue = f.get(objectOfField);
+                if (!Objects.equal(oldValue, getDefaultValueForType(f.getType())) && oldValue != value) {
+                    throw new IllegalStateException("Forbidden modification to immutable field "+
+                        f+" in "+objectOfField+": attempting to change to "+value+" when was already "+oldValue);
+                }
+            }
+            if (optionalAnnotation!=null && !optionalAnnotation.nullable() && value==null) {
+                throw new IllegalArgumentException("Forbidden null assignment to non-nullable field "+
+                        f+" in "+objectOfField);
+            }
+            if (optionalAnnotation!=null && (f.getModifiers() & Modifier.STATIC)==Modifier.STATIC)
+                log.warn("Setting static field "+f+" in "+objectOfField+" from flag "+optionalAnnotation.value()+": discouraged");
+
+            Object newValue;
+            try {
+                newValue = TypeCoercions.coerce(value, f.getType());
+            } catch (Exception e) {
+                throw new IllegalArgumentException("Cannot set "+f+" in "+objectOfField+" from type "+value.getClass()+" ("+value+"): "+e, e);
+            }
+            f.set(objectOfField, newValue);
+            if (log.isTraceEnabled()) log.trace("FlagUtils for "+objectOfField+", setting field="+f.getName()+"; val="+value+"; newVal="+newValue+"; key="+key);
+
+        } catch (IllegalAccessException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
+    /** gets the value of the field. 
+     */
+    public static Object getField(Object objectOfField, Field f) {
+        try {
+            if (!f.isAccessible()) f.setAccessible(true);
+            return f.get(objectOfField);
+        } catch (IllegalAccessException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+    
+    /** returns the default/inital value that is assigned to fields of the givien type;
+     * if the type is not primitive this value is null;
+     * for primitive types it is obvious but not AFAIK programmatically visible
+     * (e.g. 0 for int, false for boolean)  
+     */
+    public static Object getDefaultValueForType(Class<?> t) {
+        if (!t.isPrimitive()) return null;
+        if (t==Integer.TYPE) return (int)0;
+        if (t==Long.TYPE) return (long)0;
+        if (t==Double.TYPE) return (double)0;
+        if (t==Float.TYPE) return (float)0;
+        if (t==Byte.TYPE) return (byte)0;
+        if (t==Short.TYPE) return (short)0;
+        if (t==Character.TYPE) return (char)0;
+        if (t==Boolean.TYPE) return false;
+        //should never happen
+        throw new IllegalStateException("Class "+t+" is an unknown primitive.");
+    }
+
+    /** returns a map of all fields which are annotated 'SetFromFlag', along with the annotation */
+    public static Map<Field,SetFromFlag> getAnnotatedFields(Class<?> type) {
+        Map<Field, SetFromFlag> result = Maps.newLinkedHashMap();
+        for (Field f: getAllFields(type)) {
+            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
+            if (truth(cf)) result.put(f, cf);
+        }
+        return result;
+    }
+
+    /** returns a map of all {@link ConfigKey} fields which are annotated 'SetFromFlag', along with the annotation */
+    public static Map<ConfigKey<?>,SetFromFlag> getAnnotatedConfigKeys(Class<?> type) {
+        Map<ConfigKey<?>, SetFromFlag> result = Maps.newLinkedHashMap();
+        List<Field> fields = getAllFields(type, new Predicate<Field>() {
+            @Override public boolean apply(Field f) {
+                return (f != null) && ConfigKey.class.isAssignableFrom(f.getType()) && ((f.getModifiers() & Modifier.STATIC)!=0);
+            }});
+        for (Field f: fields) {
+            SetFromFlag cf = f.getAnnotation(SetFromFlag.class);
+            if (cf != null) {
+                ConfigKey<?> key = getFieldAsConfigKey(null, f);
+                if (key != null) {
+                    result.put(key, cf);
+                }
+            }
+        }
+        return result;
+    }
+
+    /** returns a map of all fields which are annotated 'SetFromFlag' with their current values;
+     * useful if you want to clone settings from one object
+     */
+    public static Map<String,Object> getFieldsWithValues(Object o) {
+        try {
+            Map<String, Object> result = Maps.newLinkedHashMap();
+            for (Map.Entry<Field, SetFromFlag> entry : getAnnotatedFields(o.getClass()).entrySet()) {
+                Field f = entry.getKey();
+                SetFromFlag cf = entry.getValue();
+                String flagName = elvis(cf.value(), f.getName());
+                if (truth(flagName)) {
+                    if (!f.isAccessible()) f.setAccessible(true);
+                    result.put(flagName, f.get(o));
+                }
+            }
+            return result;
+        } catch (IllegalAccessException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+        
+    /**
+     * @throws an IllegalStateException if there are fields required (nullable=false) which are unset 
+     * @throws wrapped IllegalAccessException
+     */
+    public static void checkRequiredFields(Object o) {
+        try {
+            Set<String> unsetFields = Sets.newLinkedHashSet();
+            for (Map.Entry<Field, SetFromFlag> entry : getAnnotatedFields(o.getClass()).entrySet()) {
+                Field f = entry.getKey();
+                SetFromFlag cf = entry.getValue();
+                if (!cf.nullable()) {
+                    String flagName = elvis(cf.value(), f.getName());
+                    if (!f.isAccessible()) f.setAccessible(true);
+                    Object v = f.get(o);
+                    if (v==null) unsetFields.add(flagName);
+                }
+            }
+            if (truth(unsetFields)) {
+                throw new IllegalStateException("Missing required "+(unsetFields.size()>1 ? "fields" : "field")+": "+unsetFields);
+            }
+        } catch (IllegalAccessException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
+//    /** sets all fields in target annotated with @SetFromFlag using the configuration in the given config bag */
+//    public static void setFieldsFromConfigFlags(Object target, ConfigBag configBag) {
+//        setFieldsFromConfigFlags(target, configBag.getAllConfig(), configBag);
+//    }
+//
+//    
+//    /** sets all fields in target annotated with @SetFromFlag using the configuration in the given configToUse,
+//     * marking used in the given configBag */
+//    public static void setFieldsFromConfigFlags(Object target, Map<?,?> configToUse, ConfigBag configBag) {
+//        for (Map.Entry<?,?> entry: configToUse.entrySet()) {
+//            setFieldFromConfigFlag(target, entry.getKey(), entry.getValue(), configBag);
+//        }
+//    }
+//
+//    public static void setFieldFromConfigFlag(Object target, Object key, Object value, ConfigBag optionalConfigBag) {
+//        String name = null;
+//        if (key instanceof String) name = (String)key;
+//        else if (key instanceof ConfigKey<?>) name = ((ConfigKey<?>)key).getName();
+//        else if (key instanceof HasConfigKey<?>) name = ((HasConfigKey<?>)key).getConfigKey().getName();
+//        else {
+//            if (key!=null) {
+//                log.warn("Invalid config type "+key.getClass().getCanonicalName()+" ("+key+") when configuring "+target+"; ignoring");
+//            }
+//            return;
+//        }
+//        if (setFieldFromFlag(name, value, target)) {
+//            if (optionalConfigBag!=null)
+//                optionalConfigBag.markUsed(name);
+//        }
+//    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/flags/MethodCoercions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/flags/MethodCoercions.java b/core/src/main/java/org/apache/brooklyn/core/util/flags/MethodCoercions.java
new file mode 100644
index 0000000..20116cf
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/flags/MethodCoercions.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.util.flags;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.reflect.TypeToken;
+
+import javax.annotation.Nullable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A way of binding a loosely-specified method call into a strongly-typed Java method call.
+ */
+public class MethodCoercions {
+
+    /**
+     * Returns a predicate that matches a method with the given name, and a single parameter that
+     * {@link org.apache.brooklyn.core.util.flags.TypeCoercions#tryCoerce(Object, com.google.common.reflect.TypeToken)} can process
+     * from the given argument.
+     *
+     * @param methodName name of the method
+     * @param argument argument that is intended to be given
+     * @return a predicate that will match a compatible method
+     */
+    public static Predicate<Method> matchSingleParameterMethod(final String methodName, final Object argument) {
+        checkNotNull(methodName, "methodName");
+        checkNotNull(argument, "argument");
+
+        return new Predicate<Method>() {
+            @Override
+            public boolean apply(@Nullable Method input) {
+                if (input == null) return false;
+                if (!input.getName().equals(methodName)) return false;
+                Type[] parameterTypes = input.getGenericParameterTypes();
+                return parameterTypes.length == 1
+                        && TypeCoercions.tryCoerce(argument, TypeToken.of(parameterTypes[0])).isPresentAndNonNull();
+
+            }
+        };
+    }
+
+    /**
+     * Tries to find a single-parameter method with a parameter compatible with (can be coerced to) the argument, and
+     * invokes it.
+     *
+     * @param instance the object to invoke the method on
+     * @param methodName the name of the method to invoke
+     * @param argument the argument to the method's parameter.
+     * @return the result of the method call, or {@link brooklyn.util.guava.Maybe#absent()} if method could not be matched.
+     */
+    public static Maybe<?> tryFindAndInvokeSingleParameterMethod(final Object instance, final String methodName, final Object argument) {
+        Class<?> clazz = instance.getClass();
+        Iterable<Method> methods = Arrays.asList(clazz.getMethods());
+        Optional<Method> matchingMethod = Iterables.tryFind(methods, matchSingleParameterMethod(methodName, argument));
+        if (matchingMethod.isPresent()) {
+            Method method = matchingMethod.get();
+            try {
+                Type paramType = method.getGenericParameterTypes()[0];
+                Object coercedArgument = TypeCoercions.coerce(argument, TypeToken.of(paramType));
+                return Maybe.of(method.invoke(instance, coercedArgument));
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw Exceptions.propagate(e);
+            }
+        } else {
+            return Maybe.absent();
+        }
+    }
+
+    /**
+     * Returns a predicate that matches a method with the given name, and parameters that
+     * {@link org.apache.brooklyn.core.util.flags.TypeCoercions#tryCoerce(Object, com.google.common.reflect.TypeToken)} can process
+     * from the given list of arguments.
+     *
+     * @param methodName name of the method
+     * @param arguments arguments that is intended to be given
+     * @return a predicate that will match a compatible method
+     */
+    public static Predicate<Method> matchMultiParameterMethod(final String methodName, final List<?> arguments) {
+        checkNotNull(methodName, "methodName");
+        checkNotNull(arguments, "arguments");
+
+        return new Predicate<Method>() {
+            @Override
+            public boolean apply(@Nullable Method input) {
+                if (input == null) return false;
+                if (!input.getName().equals(methodName)) return false;
+                int numOptionParams = arguments.size();
+                Type[] parameterTypes = input.getGenericParameterTypes();
+                if (parameterTypes.length != numOptionParams) return false;
+
+                for (int paramCount = 0; paramCount < numOptionParams; paramCount++) {
+                    if (!TypeCoercions.tryCoerce(((List) arguments).get(paramCount),
+                            TypeToken.of(parameterTypes[paramCount])).isPresentAndNonNull()) return false;
+                }
+                return true;
+            }
+        };
+    }
+
+    /**
+     * Tries to find a multiple-parameter method with each parameter compatible with (can be coerced to) the
+     * corresponding argument, and invokes it.
+     *
+     * @param instance the object to invoke the method on
+     * @param methodName the name of the method to invoke
+     * @param argument a list of the arguments to the method's parameters.
+     * @return the result of the method call, or {@link brooklyn.util.guava.Maybe#absent()} if method could not be matched.
+     */
+    public static Maybe<?> tryFindAndInvokeMultiParameterMethod(final Object instance, final String methodName, final List<?> arguments) {
+        Class<?> clazz = instance.getClass();
+        Iterable<Method> methods = Arrays.asList(clazz.getMethods());
+        Optional<Method> matchingMethod = Iterables.tryFind(methods, matchMultiParameterMethod(methodName, arguments));
+        if (matchingMethod.isPresent()) {
+            Method method = matchingMethod.get();
+            try {
+                int numOptionParams = ((List)arguments).size();
+                Object[] coercedArguments = new Object[numOptionParams];
+                for (int paramCount = 0; paramCount < numOptionParams; paramCount++) {
+                    Object argument = arguments.get(paramCount);
+                    Type paramType = method.getGenericParameterTypes()[paramCount];
+                    coercedArguments[paramCount] = TypeCoercions.coerce(argument, TypeToken.of(paramType));
+                }
+                return Maybe.of(method.invoke(instance, coercedArguments));
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw Exceptions.propagate(e);
+            }
+        } else {
+            return Maybe.absent();
+        }
+    }
+
+    /**
+     * Tries to find a method with each parameter compatible with (can be coerced to) the corresponding argument, and invokes it.
+     *
+     * @param instance the object to invoke the method on
+     * @param methodName the name of the method to invoke
+     * @param argument a list of the arguments to the method's parameters, or a single argument for a single-parameter method.
+     * @return the result of the method call, or {@link brooklyn.util.guava.Maybe#absent()} if method could not be matched.
+     */
+    public static Maybe<?> tryFindAndInvokeBestMatchingMethod(final Object instance, final String methodName, final Object argument) {
+        if (argument instanceof List) {
+            List<?> arguments = (List<?>) argument;
+
+            // ambiguous case: we can't tell if the user is using the multi-parameter syntax, or the single-parameter
+            // syntax for a method which takes a List parameter. So we try one, then fall back to the other.
+
+            Maybe<?> maybe = tryFindAndInvokeMultiParameterMethod(instance, methodName, arguments);
+            if (maybe.isAbsent())
+                maybe = tryFindAndInvokeSingleParameterMethod(instance, methodName, argument);
+
+            return maybe;
+        } else {
+            return tryFindAndInvokeSingleParameterMethod(instance, methodName, argument);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/flags/SetFromFlag.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/flags/SetFromFlag.java b/core/src/main/java/org/apache/brooklyn/core/util/flags/SetFromFlag.java
new file mode 100644
index 0000000..3b69c05
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/flags/SetFromFlag.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.core.util.flags;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Annotation to indicate that a variable may be set through the use of a named argument,
+ * looking for the name specified here or inferred from the annotated field/argument/object.
+ * <p>
+ * This is used to automate the processing where named arguments are passed in constructors
+ * and other methods, and the values of those named arguments should be transferred to
+ * other known fields/arguments/objects at runtime.
+ * <p>
+ * Fields on a class are typically set from values in a map with a call to
+ * {@link FlagUtils#setFieldsFromFlags(java.util.Map, Object)}.
+ * That method (and related, in the same class) will attend to the arguments here.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SetFromFlag {
+
+    /** the flag (key) which should be used to find the value; if empty defaults to field/argument/object name */
+    String value() default "";
+    
+    /** whether the object should not be changed once set; defaults to false
+     * <p>
+     * this is partially tested for in many routines, but not all;
+     * when nullable=false the testing (when done) is guaranteed.
+     * however if nullable is allowed we do not distinguish between null and unset
+     * so explicitly setting null then setting to a value is not detected as an illegal mutating.
+     */
+    boolean immutable() default false;
+    
+    /** whether the object is required & should not be set to null; defaults to true.
+     * (there is no 'required' parameter, but setting nullable false then invoking 
+     * e.g. {@link FlagUtils#checkRequiredFields(Object)} has the effect of requiring a value)
+     * <p>
+     * code should call that method explicitly to enforce nullable false;
+     * errors are not done during a call to setFieldsFromFlags 
+     * because fields may be initialised in multiple passes.) 
+     * <p>
+     * this is partially tested for in many routines, but not all
+     */
+    boolean nullable() default true;
+
+    /** The default value, if it is not explicitly set.
+     * <p>
+     * The value will be coerced from String where required, for types supported by {@link TypeCoercions}.
+     * <p>
+     * The field will be initialised with its default value on the first call to setFieldsFromFlags
+     * (or related).  (The field will not be initialised if that method is not called.) 
+     */
+    String defaultVal() default "";
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/flags/TypeCoercions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/flags/TypeCoercions.java b/core/src/main/java/org/apache/brooklyn/core/util/flags/TypeCoercions.java
new file mode 100644
index 0000000..2c03620
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/flags/TypeCoercions.java
@@ -0,0 +1,879 @@
+/*
+ * 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.util.flags;
+
+import groovy.lang.Closure;
+import groovy.time.TimeDuration;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.api.event.Sensor;
+import org.apache.brooklyn.core.internal.BrooklynInitialization;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.BrooklynTaskTags;
+import brooklyn.entity.basic.ClosureEntityFactory;
+import brooklyn.entity.basic.ConfigurableEntityFactory;
+import brooklyn.entity.basic.ConfigurableEntityFactoryFromEntityFactory;
+import brooklyn.event.basic.Sensors;
+import brooklyn.util.JavaGroovyEquivalents;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.collections.QuorumCheck;
+import brooklyn.util.collections.QuorumCheck.QuorumChecks;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.javalang.Enums;
+import brooklyn.util.net.Cidr;
+import brooklyn.util.net.Networking;
+import brooklyn.util.net.UserAndHostAndPort;
+import brooklyn.util.text.StringEscapes.JavaStringEscapes;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+import brooklyn.util.yaml.Yamls;
+
+import com.google.common.base.CaseFormat;
+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.collect.HashBasedTable;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+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.collect.Table;
+import com.google.common.net.HostAndPort;
+import com.google.common.primitives.Primitives;
+import com.google.common.reflect.TypeToken;
+
+@SuppressWarnings("rawtypes")
+public class TypeCoercions {
+
+    private static final Logger log = LoggerFactory.getLogger(TypeCoercions.class);
+    
+    private TypeCoercions() {}
+
+    /** Store the coercion {@link Function functions} in a {@link Table table}. */
+    @GuardedBy("TypeCoercions.class")
+    private static Table<Class, Class, Function> registry = HashBasedTable.create();
+
+    /**
+     * Attempts to coerce {@code value} to {@code targetType}.
+     * <p>
+     * Maintains a registry of adapter functions for type pairs in a {@link Table} which
+     * is searched after checking various strategies, including the following:
+     * <ul>
+     * <li>{@code value.asTargetType()}
+     * <li>{@code TargetType.fromType(value)} (if {@code value instanceof Type})
+     * <li>{@code value.targetTypeValue()} (handy for primitives)
+     * <li>{@code TargetType.valueOf(value)} (for enums)
+     * </ul>
+     * <p>
+     * A default set of adapters will handle most common Java-type coercions
+     * as well as <code>String</code> coercion to:
+     * <ul>
+     * <li> {@link Set}, {@link List}, {@link Map} and similar -- parses as YAML
+     * <li> {@link Date} -- parses using {@link Time#parseDate(String)}
+     * <li> {@link Duration} -- parses using {@link Duration#parse(String)}
+     * </ul>
+     */
+    public static <T> T coerce(Object value, Class<T> targetType) {
+        return coerce(value, TypeToken.of(targetType));
+    }
+
+    /** @see #coerce(Object, Class) */
+    public static <T> Maybe<T> tryCoerce(Object value, TypeToken<T> targetTypeToken) {
+        try {
+            return Maybe.of( coerce(value, targetTypeToken) );
+        } catch (Throwable t) {
+            Exceptions.propagateIfFatal(t);
+            return Maybe.absent(t); 
+        }
+    }
+    
+    /** @see #coerce(Object, Class) */
+    @SuppressWarnings({ "unchecked" })
+    public static <T> T coerce(Object value, TypeToken<T> targetTypeToken) {
+        if (value==null) return null;
+        Class<? super T> targetType = targetTypeToken.getRawType();
+
+        //recursive coercion of parameterized collections and map entries
+        if (targetTypeToken.getType() instanceof ParameterizedType) {
+            if (value instanceof Collection && Collection.class.isAssignableFrom(targetType)) {
+                Type[] arguments = ((ParameterizedType) targetTypeToken.getType()).getActualTypeArguments();
+                if (arguments.length != 1) {
+                    throw new IllegalStateException("Unexpected number of parameters in collection type: " + arguments);
+                }
+                Collection coerced = Lists.newLinkedList();
+                TypeToken<?> listEntryType = TypeToken.of(arguments[0]);
+                for (Object entry : (Iterable<?>) value) {
+                    coerced.add(coerce(entry, listEntryType));
+                }
+                if (Set.class.isAssignableFrom(targetType)) {
+                    return (T) Sets.newLinkedHashSet(coerced);
+                } else {
+                    return (T) Lists.newArrayList(coerced);
+                }
+            } else if (value instanceof Map && Map.class.isAssignableFrom(targetType)) {
+                Type[] arguments = ((ParameterizedType) targetTypeToken.getType()).getActualTypeArguments();
+                if (arguments.length != 2) {
+                    throw new IllegalStateException("Unexpected number of parameters in map type: " + arguments);
+                }
+                Map coerced = Maps.newLinkedHashMap();
+                TypeToken<?> mapKeyType = TypeToken.of(arguments[0]);
+                TypeToken<?> mapValueType = TypeToken.of(arguments[1]);
+                for (Map.Entry entry : ((Map<?,?>) value).entrySet()) {
+                    coerced.put(coerce(entry.getKey(), mapKeyType),  coerce(entry.getValue(), mapValueType));
+                }
+                return (T) Maps.newLinkedHashMap(coerced);
+            }
+        }
+
+        if (targetType.isInstance(value)) return (T) value;
+
+        // TODO use registry first?
+
+        //deal with primitive->primitive casting
+        if (isPrimitiveOrBoxer(targetType) && isPrimitiveOrBoxer(value.getClass())) {
+            // Don't just rely on Java to do its normal casting later; if caller writes
+            // long `l = coerce(new Integer(1), Long.class)` then letting java do its casting will fail,
+            // because an Integer will not automatically be unboxed and cast to a long
+            return castPrimitive(value, (Class<T>)targetType);
+        }
+
+        //deal with string->primitive
+        if (value instanceof String && isPrimitiveOrBoxer(targetType)) {
+            return stringToPrimitive((String)value, (Class<T>)targetType);
+        }
+
+        //deal with primitive->string
+        if (isPrimitiveOrBoxer(value.getClass()) && targetType.equals(String.class)) {
+            return (T) value.toString();
+        }
+
+        //look for value.asType where Type is castable to targetType
+        String targetTypeSimpleName = getVerySimpleName(targetType);
+        if (targetTypeSimpleName!=null && targetTypeSimpleName.length()>0) {
+            for (Method m: value.getClass().getMethods()) {
+                if (m.getName().startsWith("as") && m.getParameterTypes().length==0 &&
+                        targetType.isAssignableFrom(m.getReturnType()) ) {
+                    if (m.getName().equals("as"+getVerySimpleName(m.getReturnType()))) {
+                        try {
+                            return (T) m.invoke(value);
+                        } catch (Exception e) {
+                            throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): "+m.getName()+" adapting failed, "+e);
+                        }
+                    }
+                }
+            }
+        }
+        
+        //now look for static TargetType.fromType(Type t) where value instanceof Type  
+        for (Method m: targetType.getMethods()) {
+            if (((m.getModifiers()&Modifier.STATIC)==Modifier.STATIC) && 
+                    m.getName().startsWith("from") && m.getParameterTypes().length==1 &&
+                    m.getParameterTypes()[0].isInstance(value)) {
+                if (m.getName().equals("from"+getVerySimpleName(m.getParameterTypes()[0]))) {
+                    try {
+                        return (T) m.invoke(null, value);
+                    } catch (Exception e) {
+                        throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): "+m.getName()+" adapting failed, "+e);
+                    }
+                }
+            }
+        }
+        
+       //ENHANCEMENT could look in type hierarchy of both types for a conversion method...
+        
+        //primitives get run through again boxed up
+        Class boxedT = UNBOXED_TO_BOXED_TYPES.get(targetType);
+        Class boxedVT = UNBOXED_TO_BOXED_TYPES.get(value.getClass());
+        if (boxedT!=null || boxedVT!=null) {
+            try {
+                if (boxedT==null) boxedT=targetType;
+                Object boxedV;
+                if (boxedVT==null) { boxedV = value; }
+                else { boxedV = boxedVT.getConstructor(value.getClass()).newInstance(value); }
+                return (T) coerce(boxedV, boxedT);
+            } catch (Exception e) {
+                throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): unboxing failed, "+e);
+            }
+        }
+
+        //for enums call valueOf with the string representation of the value
+        if (targetType.isEnum()) {
+            T result = (T) stringToEnum((Class<Enum>) targetType, null).apply(String.valueOf(value));
+            if (result != null) return result;
+        }
+
+        //now look in registry
+        synchronized (TypeCoercions.class) {
+            Map<Class, Function> adapters = registry.row(targetType);
+            for (Map.Entry<Class, Function> entry : adapters.entrySet()) {
+                if (entry.getKey().isInstance(value)) {
+                    T result = (T) entry.getValue().apply(value);
+                    
+                    // Check if need to unwrap again (e.g. if want List<Integer> and are given a String "1,2,3"
+                    // then we'll have so far converted to List.of("1", "2", "3"). Call recursively.
+                    // First check that value has changed, to avoid stack overflow!
+                    if (!Objects.equal(value, result) && targetTypeToken.getType() instanceof ParameterizedType) {
+                        // Could duplicate check for `result instanceof Collection` etc; but recursive call
+                        // will be fine as if that doesn't match we'll safely reach `targetType.isInstance(value)`
+                        // and just return the result.
+                        return coerce(result, targetTypeToken);
+                    }
+                    return result;
+                }
+            }
+        }
+
+        //not found
+        throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): no adapter known");
+    }
+
+    /**
+     * Returns a function that does a type coercion to the given type. For example,
+     * {@code TypeCoercions.function(Double.class)} will return a function that will
+     * coerce its input value to a {@link Double} (or throw a {@link ClassCoercionException}
+     * if that is not possible).
+     */
+    public static <T> Function<Object, T> function(final Class<T> type) {
+        return new CoerceFunction<T>(type);
+    }
+    
+    private static class CoerceFunction<T> implements Function<Object, T> {
+        private final Class<T> type;
+
+        public CoerceFunction(Class<T> type) {
+            this.type = type;
+        }
+        @Override
+        public T apply(Object input) {
+            return coerce(input, type);
+        }
+    }
+
+    /**
+     * Type coercion {@link Function function} for {@link Enum enums}.
+     * <p>
+     * Tries to convert the string to {@link CaseFormat#UPPER_UNDERSCORE} first,
+     * handling all of the different {@link CaseFormat format} possibilites. Failing 
+     * that, it tries a case-insensitive comparison with the valid enum values.
+     * <p>
+     * Returns {@code defaultValue} if the string cannot be converted.
+     *
+     * @see TypeCoercions#coerce(Object, Class)
+     * @see Enum#valueOf(Class, String)
+     */
+    public static <E extends Enum<E>> Function<String, E> stringToEnum(final Class<E> type, @Nullable final E defaultValue) {
+        return new StringToEnumFunction<E>(type, defaultValue);
+    }
+    
+    private static class StringToEnumFunction<E extends Enum<E>> implements Function<String, E> {
+        private final Class<E> type;
+        private final E defaultValue;
+        
+        public StringToEnumFunction(Class<E> type, @Nullable E defaultValue) {
+            this.type = type;
+            this.defaultValue = defaultValue;
+        }
+        @Override
+        public E apply(String input) {
+            Preconditions.checkNotNull(input, "input");
+            List<String> options = ImmutableList.of(
+                    input,
+                    CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, input),
+                    CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, input),
+                    CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, input),
+                    CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, input));
+            for (String value : options) {
+                try {
+                    return Enum.valueOf(type, value);
+                } catch (IllegalArgumentException iae) {
+                    continue;
+                }
+            }
+            Maybe<E> result = Enums.valueOfIgnoreCase(type, input);
+            return (result.isPresent()) ? result.get() : defaultValue;
+        }
+    }
+
+    /**
+     * Sometimes need to explicitly cast primitives, rather than relying on Java casting.
+     * For example, when using generics then type-erasure means it doesn't actually cast,
+     * which causes tests to fail with 0 != 0.0
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T castPrimitive(Object value, Class<T> targetType) {
+        if (value==null) return null;
+        assert isPrimitiveOrBoxer(targetType) : "targetType="+targetType;
+        assert isPrimitiveOrBoxer(value.getClass()) : "value="+targetType+"; valueType="+value.getClass();
+
+        Class<?> sourceWrapType = Primitives.wrap(value.getClass());
+        Class<?> targetWrapType = Primitives.wrap(targetType);
+        
+        // optimization, for when already correct type
+        if (sourceWrapType == targetWrapType) {
+            return (T) value;
+        }
+        
+        if (targetWrapType == Boolean.class) {
+            // only char can be mapped to boolean
+            // (we could say 0=false, nonzero=true, but there is no compelling use case so better
+            // to encourage users to write as boolean)
+            if (sourceWrapType == Character.class)
+                return (T) stringToPrimitive(value.toString(), targetType);
+            
+            throw new ClassCoercionException("Cannot cast "+sourceWrapType+" ("+value+") to "+targetType);
+        } else if (sourceWrapType == Boolean.class) {
+            // boolean can't cast to anything else
+            
+            throw new ClassCoercionException("Cannot cast "+sourceWrapType+" ("+value+") to "+targetType);
+        }
+        
+        // for whole-numbers (where casting to long won't lose anything)...
+        long v = 0;
+        boolean islong = true;
+        if (sourceWrapType == Character.class) {
+            v = (long) ((Character)value).charValue();
+        } else if (sourceWrapType == Byte.class) {
+            v = (long) ((Byte)value).byteValue();
+        } else if (sourceWrapType == Short.class) {
+            v = (long) ((Short)value).shortValue();
+        } else if (sourceWrapType == Integer.class) {
+            v = (long) ((Integer)value).intValue();
+        } else if (sourceWrapType == Long.class) {
+            v = ((Long)value).longValue();
+        } else {
+            islong = false;
+        }
+        if (islong) {
+            if (targetWrapType == Character.class) return (T) Character.valueOf((char)v); 
+            if (targetWrapType == Byte.class) return (T) Byte.valueOf((byte)v); 
+            if (targetWrapType == Short.class) return (T) Short.valueOf((short)v); 
+            if (targetWrapType == Integer.class) return (T) Integer.valueOf((int)v); 
+            if (targetWrapType == Long.class) return (T) Long.valueOf((long)v); 
+            if (targetWrapType == Float.class) return (T) Float.valueOf((float)v); 
+            if (targetWrapType == Double.class) return (T) Double.valueOf((double)v);
+            throw new IllegalStateException("Unexpected: sourceType="+sourceWrapType+"; targetType="+targetWrapType);
+        }
+        
+        // for real-numbers (cast to double)...
+        double d = 0;
+        boolean isdouble = true;
+        if (sourceWrapType == Float.class) {
+            d = (double) ((Float)value).floatValue();
+        } else if (sourceWrapType == Double.class) {
+            d = (double) ((Double)value).doubleValue();
+        } else {
+            isdouble = false;
+        }
+        if (isdouble) {
+            if (targetWrapType == Character.class) return (T) Character.valueOf((char)d); 
+            if (targetWrapType == Byte.class) return (T) Byte.valueOf((byte)d); 
+            if (targetWrapType == Short.class) return (T) Short.valueOf((short)d); 
+            if (targetWrapType == Integer.class) return (T) Integer.valueOf((int)d); 
+            if (targetWrapType == Long.class) return (T) Long.valueOf((long)d); 
+            if (targetWrapType == Float.class) return (T) Float.valueOf((float)d); 
+            if (targetWrapType == Double.class) return (T) Double.valueOf((double)d);
+            throw new IllegalStateException("Unexpected: sourceType="+sourceWrapType+"; targetType="+targetWrapType);
+        } else {
+            throw new IllegalStateException("Unexpected: sourceType="+sourceWrapType+"; targetType="+targetWrapType);
+        }
+    }
+    
+    public static boolean isPrimitiveOrBoxer(Class<?> type) {
+        return Primitives.allPrimitiveTypes().contains(type) || Primitives.allWrapperTypes().contains(type);
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static <T> T stringToPrimitive(String value, Class<T> targetType) {
+        assert Primitives.allPrimitiveTypes().contains(targetType) || Primitives.allWrapperTypes().contains(targetType) : "targetType="+targetType;
+        // If char, then need to do explicit conversion
+        if (targetType == Character.class || targetType == char.class) {
+            if (value.length() == 1) {
+                return (T) (Character) value.charAt(0);
+            } else if (value.length() != 1) {
+                throw new ClassCoercionException("Cannot coerce type String to "+targetType.getCanonicalName()+" ("+value+"): adapting failed");
+            }
+        }
+        value = value.trim();
+        // For boolean we could use valueOf, but that returns false whereas we'd rather throw errors on bad values
+        if (targetType == Boolean.class || targetType == boolean.class) {
+            if ("true".equalsIgnoreCase(value)) return (T) Boolean.TRUE;
+            if ("false".equalsIgnoreCase(value)) return (T) Boolean.FALSE;
+            if ("yes".equalsIgnoreCase(value)) return (T) Boolean.TRUE;
+            if ("no".equalsIgnoreCase(value)) return (T) Boolean.FALSE;
+            if ("t".equalsIgnoreCase(value)) return (T) Boolean.TRUE;
+            if ("f".equalsIgnoreCase(value)) return (T) Boolean.FALSE;
+            if ("y".equalsIgnoreCase(value)) return (T) Boolean.TRUE;
+            if ("n".equalsIgnoreCase(value)) return (T) Boolean.FALSE;
+            
+            throw new ClassCoercionException("Cannot coerce type String to "+targetType.getCanonicalName()+" ("+value+"): adapting failed"); 
+        }
+        
+        // Otherwise can use valueOf reflectively
+        Class<?> wrappedType;
+        if (Primitives.allPrimitiveTypes().contains(targetType)) {
+            wrappedType = Primitives.wrap(targetType);
+        } else {
+            wrappedType = targetType;
+        }
+        
+        try {
+            return (T) wrappedType.getMethod("valueOf", String.class).invoke(null, value);
+        } catch (Exception e) {
+            ClassCoercionException tothrow = new ClassCoercionException("Cannot coerce "+JavaStringEscapes.wrapJavaString(value)+" to "+targetType.getCanonicalName()+" ("+value+"): adapting failed");
+            tothrow.initCause(e);
+            throw tothrow;
+        }
+    }
+    
+    /** returns the simple class name, and for any inner class the portion after the $ */
+    public static String getVerySimpleName(Class c) {
+        String s = c.getSimpleName();
+        if (s.indexOf('$')>=0)
+            s = s.substring(s.lastIndexOf('$')+1);
+        return s;
+    }
+    public static final Map<Class,Class> BOXED_TO_UNBOXED_TYPES = ImmutableMap.<Class,Class>builder().
+            put(Integer.class, Integer.TYPE).
+            put(Long.class, Long.TYPE).
+            put(Boolean.class, Boolean.TYPE).
+            put(Byte.class, Byte.TYPE).
+            put(Double.class, Double.TYPE).
+            put(Float.class, Float.TYPE).
+            put(Character.class, Character.TYPE).
+            put(Short.class, Short.TYPE).
+            build();
+    public static final Map<Class,Class> UNBOXED_TO_BOXED_TYPES = ImmutableMap.<Class,Class>builder().
+            put(Integer.TYPE, Integer.class).
+            put(Long.TYPE, Long.class).
+            put(Boolean.TYPE, Boolean.class).
+            put(Byte.TYPE, Byte.class).
+            put(Double.TYPE, Double.class).
+            put(Float.TYPE, Float.class).
+            put(Character.TYPE, Character.class).
+            put(Short.TYPE, Short.class).
+            build();
+    
+    /** for automatic conversion */
+    public static Object getMatchingConstructor(Class target, Object ...arguments) {
+        Constructor[] cc = target.getConstructors();
+        for (Constructor c: cc) {
+            if (c.getParameterTypes().length != arguments.length)
+                continue;
+            boolean matches = true;
+            Class[] tt = c.getParameterTypes();
+            for (int i=0; i<tt.length; i++) {
+                if (arguments[i]!=null && !tt[i].isInstance(arguments[i])) {
+                    matches=false;
+                    break;
+                }
+            }
+            if (matches) 
+                return c;
+        }
+        return null;
+    }
+
+    /** Registers an adapter for use with type coercion. Returns any old adapter. */
+    public synchronized static <A,B> Function registerAdapter(Class<A> sourceType, Class<B> targetType, Function<? super A,B> fn) {
+        return registry.put(targetType, sourceType, fn);
+    }
+
+    static { BrooklynInitialization.initTypeCoercionStandardAdapters(); }
+    
+    public static void initStandardAdapters() {
+        registerAdapter(CharSequence.class, String.class, new Function<CharSequence,String>() {
+            @Override
+            public String apply(CharSequence input) {
+                return input.toString();
+            }
+        });
+        registerAdapter(byte[].class, String.class, new Function<byte[],String>() {
+            @Override
+            public String apply(byte[] input) {
+                return new String(input);
+            }
+        });
+        registerAdapter(Collection.class, Set.class, new Function<Collection,Set>() {
+            @SuppressWarnings("unchecked")
+            @Override
+            public Set apply(Collection input) {
+                return Sets.newLinkedHashSet(input);
+            }
+        });
+        registerAdapter(Collection.class, List.class, new Function<Collection,List>() {
+            @SuppressWarnings("unchecked")
+            @Override
+            public List apply(Collection input) {
+                return Lists.newArrayList(input);
+            }
+        });
+        registerAdapter(String.class, InetAddress.class, new Function<String,InetAddress>() {
+            @Override
+            public InetAddress apply(String input) {
+                return Networking.getInetAddressWithFixedName(input);
+            }
+        });
+        registerAdapter(String.class, HostAndPort.class, new Function<String,HostAndPort>() {
+            @Override
+            public HostAndPort apply(String input) {
+                return HostAndPort.fromString(input);
+            }
+        });
+        registerAdapter(String.class, UserAndHostAndPort.class, new Function<String,UserAndHostAndPort>() {
+            @Override
+            public UserAndHostAndPort apply(String input) {
+                return UserAndHostAndPort.fromString(input);
+            }
+        });
+        registerAdapter(String.class, Cidr.class, new Function<String,Cidr>() {
+            @Override
+            public Cidr apply(String input) {
+                return new Cidr(input);
+            }
+        });
+        registerAdapter(String.class, URL.class, new Function<String,URL>() {
+            @Override
+            public URL apply(String input) {
+                try {
+                    return new URL(input);
+                } catch (Exception e) {
+                    throw Exceptions.propagate(e);
+                }
+            }
+        });
+        registerAdapter(String.class, URI.class, new Function<String,URI>() {
+            @Override
+            public URI apply(String input) {
+                return URI.create(input);
+            }
+        });
+        registerAdapter(Closure.class, ConfigurableEntityFactory.class, new Function<Closure,ConfigurableEntityFactory>() {
+            @SuppressWarnings("unchecked")
+            @Override
+            public ConfigurableEntityFactory apply(Closure input) {
+                return new ClosureEntityFactory(input);
+            }
+        });
+        @SuppressWarnings({"unused", "deprecation"})
+        Function<?,?> ignoredVarHereToAllowSuppressDeprecationWarning1 = registerAdapter(brooklyn.entity.basic.EntityFactory.class, ConfigurableEntityFactory.class, new Function<brooklyn.entity.basic.EntityFactory,ConfigurableEntityFactory>() {
+            @SuppressWarnings("unchecked")
+            @Override
+            public ConfigurableEntityFactory apply(brooklyn.entity.basic.EntityFactory input) {
+                if (input instanceof ConfigurableEntityFactory) return (ConfigurableEntityFactory)input;
+                return new ConfigurableEntityFactoryFromEntityFactory(input);
+            }
+        });
+        @SuppressWarnings({"unused", "deprecation"})
+        Function<?,?> ignoredVarHereToAllowSuppressDeprecationWarning2 = registerAdapter(Closure.class, brooklyn.entity.basic.EntityFactory.class, new Function<Closure,brooklyn.entity.basic.EntityFactory>() {
+            @SuppressWarnings("unchecked")
+            @Override
+            public brooklyn.entity.basic.EntityFactory apply(Closure input) {
+                return new ClosureEntityFactory(input);
+            }
+        });
+        registerAdapter(Closure.class, Predicate.class, new Function<Closure,Predicate>() {
+            @Override
+            public Predicate<?> apply(final Closure closure) {
+                return new Predicate<Object>() {
+                    @Override public boolean apply(Object input) {
+                        return (Boolean) closure.call(input);
+                    }
+                };
+            }
+        });
+        registerAdapter(Closure.class, Function.class, new Function<Closure,Function>() {
+            @Override
+            public Function apply(final Closure closure) {
+                return new Function() {
+                    @Override public Object apply(Object input) {
+                        return closure.call(input);
+                    }
+                };
+            }
+        });
+        registerAdapter(Object.class, Duration.class, new Function<Object,Duration>() {
+            @Override
+            public Duration apply(final Object input) {
+                return brooklyn.util.time.Duration.of(input);
+            }
+        });
+        registerAdapter(Object.class, TimeDuration.class, new Function<Object,TimeDuration>() {
+            @SuppressWarnings("deprecation")
+            @Override
+            public TimeDuration apply(final Object input) {
+                log.warn("deprecated automatic coercion of Object to TimeDuration (set breakpoint in TypeCoercions to inspect, convert to Duration)");
+                return JavaGroovyEquivalents.toTimeDuration(input);
+            }
+        });
+        registerAdapter(TimeDuration.class, Long.class, new Function<TimeDuration,Long>() {
+            @Override
+            public Long apply(final TimeDuration input) {
+                log.warn("deprecated automatic coercion of TimeDuration to Long (set breakpoint in TypeCoercions to inspect, use Duration instead of Long!)");
+                return input.toMilliseconds();
+            }
+        });
+        registerAdapter(Integer.class, AtomicLong.class, new Function<Integer,AtomicLong>() {
+            @Override public AtomicLong apply(final Integer input) {
+                return new AtomicLong(input);
+            }
+        });
+        registerAdapter(Long.class, AtomicLong.class, new Function<Long,AtomicLong>() {
+            @Override public AtomicLong apply(final Long input) {
+                return new AtomicLong(input);
+            }
+        });
+        registerAdapter(String.class, AtomicLong.class, new Function<String,AtomicLong>() {
+            @Override public AtomicLong apply(final String input) {
+                return new AtomicLong(Long.parseLong(input.trim()));
+            }
+        });
+        registerAdapter(Integer.class, AtomicInteger.class, new Function<Integer,AtomicInteger>() {
+            @Override public AtomicInteger apply(final Integer input) {
+                return new AtomicInteger(input);
+            }
+        });
+        registerAdapter(String.class, AtomicInteger.class, new Function<String,AtomicInteger>() {
+            @Override public AtomicInteger apply(final String input) {
+                return new AtomicInteger(Integer.parseInt(input.trim()));
+            }
+        });
+        /** This always returns a {@link Double}, cast as a {@link Number}; 
+         * however primitives and boxers get exact typing due to call in #stringToPrimitive */
+        registerAdapter(String.class, Number.class, new Function<String,Number>() {
+            @Override
+            public Number apply(String input) {
+                return Double.valueOf(input);
+            }
+        });
+        registerAdapter(BigDecimal.class, Double.class, new Function<BigDecimal,Double>() {
+            @Override
+            public Double apply(BigDecimal input) {
+                return input.doubleValue();
+            }
+        });
+        registerAdapter(BigInteger.class, Long.class, new Function<BigInteger,Long>() {
+            @Override
+            public Long apply(BigInteger input) {
+                return input.longValue();
+            }
+        });
+        registerAdapter(BigInteger.class, Integer.class, new Function<BigInteger,Integer>() {
+            @Override
+            public Integer apply(BigInteger input) {
+                return input.intValue();
+            }
+        });
+        registerAdapter(String.class, BigDecimal.class, new Function<String,BigDecimal>() {
+            @Override
+            public BigDecimal apply(String input) {
+                return new BigDecimal(input);
+            }
+        });
+        registerAdapter(Double.class, BigDecimal.class, new Function<Double,BigDecimal>() {
+            @Override
+            public BigDecimal apply(Double input) {
+                return BigDecimal.valueOf(input);
+            }
+        });
+        registerAdapter(String.class, BigInteger.class, new Function<String,BigInteger>() {
+            @Override
+            public BigInteger apply(String input) {
+                return new BigInteger(input);
+            }
+        });
+        registerAdapter(Long.class, BigInteger.class, new Function<Long,BigInteger>() {
+            @Override
+            public BigInteger apply(Long input) {
+                return BigInteger.valueOf(input);
+            }
+        });
+        registerAdapter(Integer.class, BigInteger.class, new Function<Integer,BigInteger>() {
+            @Override
+            public BigInteger apply(Integer input) {
+                return BigInteger.valueOf(input);
+            }
+        });
+        registerAdapter(String.class, Date.class, new Function<String,Date>() {
+            @Override
+            public Date apply(final String input) {
+                return Time.parseDate(input);
+            }
+        });
+        registerAdapter(String.class, Class.class, new Function<String,Class>() {
+            @Override
+            public Class apply(final String input) {
+                try {
+                    return Class.forName(input);
+                } catch (ClassNotFoundException e) {
+                    throw Exceptions.propagate(e);
+                }
+            }
+        });
+        registerAdapter(String.class, AttributeSensor.class, new Function<String,AttributeSensor>() {
+            @Override
+            public AttributeSensor apply(final String input) {
+                Entity entity = BrooklynTaskTags.getContextEntity(Tasks.current());
+                if (entity!=null) {
+                    Sensor<?> result = entity.getEntityType().getSensor(input);
+                    if (result instanceof AttributeSensor) 
+                        return (AttributeSensor) result;
+                }
+                return Sensors.newSensor(Object.class, input);
+            }
+        });
+        registerAdapter(String.class, Sensor.class, new Function<String,Sensor>() {
+            @Override
+            public AttributeSensor apply(final String input) {
+                Entity entity = BrooklynTaskTags.getContextEntity(Tasks.current());
+                if (entity!=null) {
+                    Sensor<?> result = entity.getEntityType().getSensor(input);
+                    if (result != null) 
+                        return (AttributeSensor) result;
+                }
+                return Sensors.newSensor(Object.class, input);
+            }
+        });
+        registerAdapter(String.class, List.class, new Function<String,List>() {
+            @Override
+            public List<String> apply(final String input) {
+                return JavaStringEscapes.unwrapJsonishListIfPossible(input);
+            }
+        });
+        registerAdapter(String.class, Set.class, new Function<String,Set>() {
+            @Override
+            public Set<String> apply(final String input) {
+                return MutableSet.copyOf(JavaStringEscapes.unwrapJsonishListIfPossible(input)).asUnmodifiable();
+            }
+        });
+        registerAdapter(String.class, QuorumCheck.class, new Function<String,QuorumCheck>() {
+            @Override
+            public QuorumCheck apply(final String input) {
+                return QuorumChecks.of(input);
+            }
+        });
+        registerAdapter(Iterable.class, String[].class, new Function<Iterable, String[]>() {
+            @Nullable
+            @Override
+            public String[] apply(@Nullable Iterable list) {
+                if (list == null) return null;
+                String[] result = new String[Iterables.size(list)];
+                int count = 0;
+                for (Object element : list) {
+                    result[count++] = coerce(element, String.class);
+                }
+                return result;
+            }
+        });
+        registerAdapter(Iterable.class, Integer[].class, new Function<Iterable, Integer[]>() {
+            @Nullable
+            @Override
+            public Integer[] apply(@Nullable Iterable list) {
+                if (list == null) return null;
+                Integer[] result = new Integer[Iterables.size(list)];
+                int count = 0;
+                for (Object element : list) {
+                    result[count++] = coerce(element, Integer.class);
+                }
+                return result;
+            }
+        });
+        registerAdapter(Iterable.class, int[].class, new Function<Iterable, int[]>() {
+            @Nullable
+            @Override
+            public int[] apply(@Nullable Iterable list) {
+                if (list == null) return null;
+                int[] result = new int[Iterables.size(list)];
+                int count = 0;
+                for (Object element : list) {
+                    result[count++] = coerce(element, int.class);
+                }
+                return result;
+            }
+        });
+        registerAdapter(String.class, Map.class, new Function<String,Map>() {
+            @Override
+            public Map apply(final String input) {
+                Exception error = null;
+                
+                // first try wrapping in braces if needed
+                if (!input.trim().startsWith("{")) {
+                    try {
+                        return apply("{ "+input+" }");
+                    } catch (Exception e) {
+                        Exceptions.propagateIfFatal(e);
+                        // prefer this error
+                        error = e;
+                        // fall back to parsing without braces, e.g. if it's multiline
+                    }
+                }
+
+                try {
+                    return Yamls.getAs( Yamls.parseAll(input), Map.class );
+                } catch (Exception e) {
+                    Exceptions.propagateIfFatal(e);
+                    if (error!=null && input.indexOf('\n')==-1) {
+                        // prefer the original error if it wasn't braced and wasn't multiline
+                        e = error;
+                    }
+                    throw new IllegalArgumentException("Cannot parse string as map with flexible YAML parsing; "+
+                        (e instanceof ClassCastException ? "yaml treats it as a string" : 
+                        (e instanceof IllegalArgumentException && Strings.isNonEmpty(e.getMessage())) ? e.getMessage() :
+                        ""+e) );
+                }
+
+                // NB: previously we supported this also, when we did json above;
+                // yaml support is better as it supports quotes (and better than json because it allows dropping quotes)
+                // snake-yaml, our parser, also accepts key=value -- although i'm not sure this is strictly yaml compliant;
+                // our tests will catch it if snake behaviour changes, and we can reinstate this
+                // (but note it doesn't do quotes; see http://code.google.com/p/guava-libraries/issues/detail?id=412 for that):
+//                return ImmutableMap.copyOf(Splitter.on(",").trimResults().omitEmptyStrings().withKeyValueSeparator("=").split(input));
+            }
+        });
+    }
+}


[41/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/policy

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractPolicy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractPolicy.java b/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractPolicy.java
new file mode 100644
index 0000000..9d809e3
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/AbstractPolicy.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.policy.basic;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.brooklyn.api.entity.rebind.RebindSupport;
+import org.apache.brooklyn.api.entity.trait.Configurable;
+import org.apache.brooklyn.api.mementos.PolicyMemento;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.policy.PolicyType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.rebind.BasicPolicyRebindSupport;
+
+import com.google.common.base.Objects;
+
+/**
+ * Base {@link Policy} implementation; all policies should extend this or its children
+ */
+public abstract class AbstractPolicy extends AbstractEntityAdjunct implements Policy, Configurable {
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(AbstractPolicy.class);
+
+    protected String policyStatus;
+    protected AtomicBoolean suspended = new AtomicBoolean(false);
+
+    private final PolicyDynamicType policyType;
+    
+    public AbstractPolicy() {
+        this(Collections.emptyMap());
+    }
+    
+    public AbstractPolicy(Map<?,?> flags) {
+        super(flags);
+        
+        // TODO Don't let `this` reference escape during construction
+        policyType = new PolicyDynamicType(this);
+        
+        if (isLegacyConstruction() && !isLegacyNoConstructionInit()) {
+            init();
+        }
+    }
+
+    @Override
+    public PolicyType getPolicyType() {
+        return policyType.getSnapshot();
+    }
+
+    @Override
+    public void suspend() {
+        suspended.set(true);
+    }
+
+    @Override
+    public void resume() {
+        suspended.set(false);
+    }
+
+    @Override
+    public boolean isSuspended() {
+        if (suspended==null) {
+            // only if accessed during construction in super, e.g. by a call to toString in configure
+            return true;
+        }
+        return suspended.get();
+    }
+
+    @Override
+    public void destroy(){
+        suspend();
+        super.destroy();
+    }
+
+    @Override
+    public boolean isRunning() {
+        return !isSuspended() && !isDestroyed();
+    }
+
+    @Override
+    protected void onChanged() {
+        // currently changes simply trigger re-persistence; there is no intermediate listener as we do for EntityChangeListener
+        if (getManagementContext() != null) {
+            getManagementContext().getRebindManager().getChangeListener().onChanged(this);
+        }
+    }
+    
+    @Override
+    public RebindSupport<PolicyMemento> getRebindSupport() {
+        return new BasicPolicyRebindSupport(this);
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(getClass())
+                .add("name", name)
+                .add("running", isRunning())
+                .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/org/apache/brooklyn/core/policy/basic/AdjunctType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/basic/AdjunctType.java b/core/src/main/java/org/apache/brooklyn/core/policy/basic/AdjunctType.java
new file mode 100644
index 0000000..f3d6a6c
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/AdjunctType.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.core.policy.basic;
+
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.brooklyn.api.policy.EntityAdjunct;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.config.ConfigKey.HasConfigKey;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+
+/**
+ * This is the actual type of a policy instance at runtime.
+ */
+public class AdjunctType implements Serializable {
+    private static final long serialVersionUID = -662979234559595903L;
+
+    private static final Logger LOG = LoggerFactory.getLogger(AdjunctType.class);
+
+    private final String name;
+    private final Map<String, ConfigKey<?>> configKeys;
+    private final Set<ConfigKey<?>> configKeysSet;
+
+    public AdjunctType(AbstractEntityAdjunct adjunct) {
+        this(adjunct.getClass(), adjunct);
+    }
+    
+    protected AdjunctType(Class<? extends EntityAdjunct> clazz) {
+        this(clazz, null);
+    }
+    
+    private AdjunctType(Class<? extends EntityAdjunct> clazz, AbstractEntityAdjunct adjunct) {
+        name = clazz.getCanonicalName();
+        configKeys = Collections.unmodifiableMap(findConfigKeys(clazz, null));
+        configKeysSet = ImmutableSet.copyOf(this.configKeys.values());
+        if (LOG.isTraceEnabled())
+            LOG.trace("Policy {} config keys: {}", name, Joiner.on(", ").join(configKeys.keySet()));
+    }
+    
+    AdjunctType(String name, Map<String, ConfigKey<?>> configKeys) {
+        this.name = name;
+        this.configKeys = ImmutableMap.copyOf(configKeys);
+        this.configKeysSet = ImmutableSet.copyOf(this.configKeys.values());
+    }
+
+    public String getName() {
+        return name;
+    }
+    
+    public Set<ConfigKey<?>> getConfigKeys() {
+        return configKeysSet;
+    }
+    
+    public ConfigKey<?> getConfigKey(String name) {
+        return configKeys.get(name);
+    }
+    
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(name, configKeys);
+    }
+    
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (getClass() != obj.getClass()) return false;
+        AdjunctType o = (AdjunctType) obj;
+        if (!Objects.equal(name, o.getName())) return false;
+        if (!Objects.equal(getConfigKeys(), o.getConfigKeys())) return false;
+        return true;
+    }
+    
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(name)
+                .add("configKeys", configKeys)
+                .toString();
+    }
+    
+    /**
+     * Finds the config keys defined on the entity's class, statics and optionally any non-static (discouraged).
+     */
+    // TODO Remove duplication from EntityDynamicType
+    protected static Map<String,ConfigKey<?>> findConfigKeys(Class<? extends EntityAdjunct> clazz, EntityAdjunct optionalInstance) {
+        try {
+            Map<String,ConfigKey<?>> result = Maps.newLinkedHashMap();
+            Map<String,Field> configFields = Maps.newLinkedHashMap();
+            for (Field f : clazz.getFields()) {
+                boolean isConfigKey = ConfigKey.class.isAssignableFrom(f.getType());
+                if (!isConfigKey) {
+                    if (!HasConfigKey.class.isAssignableFrom(f.getType())) {
+                        // neither ConfigKey nor HasConfigKey
+                        continue;
+                    }
+                }
+                if (!Modifier.isStatic(f.getModifiers())) {
+                    // require it to be static or we have an instance
+                    LOG.warn("Discouraged use of non-static config key "+f+" defined in " + (optionalInstance!=null ? optionalInstance : clazz));
+                    if (optionalInstance==null) continue;
+                }
+                ConfigKey<?> k = isConfigKey ? (ConfigKey<?>) f.get(optionalInstance) : 
+                    ((HasConfigKey<?>)f.get(optionalInstance)).getConfigKey();
+
+                Field alternativeField = configFields.get(k.getName());
+                // Allow overriding config keys (e.g. to set default values) when there is an assignable-from relationship between classes
+                Field definitiveField = alternativeField != null ? inferSubbestField(alternativeField, f) : f;
+                boolean skip = false;
+                if (definitiveField != f) {
+                    // If they refer to the _same_ instance, just keep the one we already have
+                    if (alternativeField.get(optionalInstance) == f.get(optionalInstance)) skip = true;
+                }
+                if (skip) {
+                    //nothing
+                } else if (definitiveField == f) {
+                    result.put(k.getName(), k);
+                    configFields.put(k.getName(), f);
+                } else if (definitiveField != null) {
+                    if (LOG.isDebugEnabled()) LOG.debug("multiple definitions for config key {} on {}; preferring that in sub-class: {} to {}", new Object[] {
+                            k.getName(), optionalInstance!=null ? optionalInstance : clazz, alternativeField, f});
+                } else if (definitiveField == null) {
+                    LOG.warn("multiple definitions for config key {} on {}; preferring {} to {}", new Object[] {
+                            k.getName(), optionalInstance!=null ? optionalInstance : clazz, alternativeField, f});
+                }
+            }
+            
+            return result;
+        } catch (IllegalAccessException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+    
+    /**
+     * Gets the field that is in the sub-class; or null if one field does not come from a sub-class of the other field's class
+     */
+    // TODO Remove duplication from EntityDynamicType
+    private static Field inferSubbestField(Field f1, Field f2) {
+        Class<?> c1 = f1.getDeclaringClass();
+        Class<?> c2 = f2.getDeclaringClass();
+        boolean isSuper1 = c1.isAssignableFrom(c2);
+        boolean isSuper2 = c2.isAssignableFrom(c1);
+        return (isSuper1) ? (isSuper2 ? null : f2) : (isSuper2 ? f1 : null);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/org/apache/brooklyn/core/policy/basic/ConfigMapImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/basic/ConfigMapImpl.java b/core/src/main/java/org/apache/brooklyn/core/policy/basic/ConfigMapImpl.java
new file mode 100644
index 0000000..5cdc279
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/ConfigMapImpl.java
@@ -0,0 +1,140 @@
+/*
+ * 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.policy.basic;
+
+import static brooklyn.util.GroovyJavaMethods.elvis;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.internal.ConfigKeySelfExtracting;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Maps;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.config.internal.AbstractConfigMapImpl;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.basic.Sanitizer;
+import brooklyn.event.basic.StructuredConfigKey;
+import brooklyn.util.guava.Maybe;
+
+public class ConfigMapImpl extends AbstractConfigMapImpl {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ConfigMapImpl.class);
+
+    /** policy against which config resolution / task execution will occur */
+    private final AbstractEntityAdjunct adjunct;
+
+    /*
+     * TODO An alternative implementation approach would be to have:
+     *   setParent(Entity o, Map<ConfigKey,Object> inheritedConfig=[:])
+     * The idea is that the parent could in theory decide explicitly what in its config
+     * would be shared.
+     * I (Aled) am undecided as to whether that would be better...
+     * 
+     * (Alex) i lean toward the config key getting to make the decision
+     */
+
+    public ConfigMapImpl(AbstractEntityAdjunct adjunct) {
+        this.adjunct = Preconditions.checkNotNull(adjunct, "AbstractEntityAdjunct must be specified");
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T getConfig(ConfigKey<T> key, T defaultValue) {
+        // FIXME What about inherited task in config?!
+        //              alex says: think that should work, no?
+        // FIXME What if someone calls getConfig on a task, before setting parent app?
+        //              alex says: not supported (throw exception, or return the task)
+        
+        // In case this entity class has overridden the given key (e.g. to set default), then retrieve this entity's key
+        // TODO If ask for a config value that's not in our configKeys, should we really continue with rest of method and return key.getDefaultValue?
+        //      e.g. SshBasedJavaAppSetup calls setAttribute(JMX_USER), which calls getConfig(JMX_USER)
+        //           but that example doesn't have a default...
+        ConfigKey<T> ownKey = adjunct!=null ? (ConfigKey<T>)elvis(adjunct.getAdjunctType().getConfigKey(key.getName()), key) : key;
+        
+        // Don't use groovy truth: if the set value is e.g. 0, then would ignore set value and return default!
+        if (ownKey instanceof ConfigKeySelfExtracting) {
+            if (((ConfigKeySelfExtracting<T>)ownKey).isSet(ownConfig)) {
+                // FIXME Should we support config from futures? How to get execution context before setEntity?
+                EntityLocal entity = adjunct.entity;
+                ExecutionContext exec = (entity != null) ? ((EntityInternal)entity).getExecutionContext() : null;
+                return ((ConfigKeySelfExtracting<T>)ownKey).extractValue(ownConfig, exec);
+            }
+        } else {
+            LOG.warn("Config key {} of {} is not a ConfigKeySelfExtracting; cannot retrieve value; returning default", ownKey, this);
+        }
+        return TypeCoercions.coerce((defaultValue != null) ? defaultValue : ownKey.getDefaultValue(), key.getTypeToken());
+    }
+    
+    @Override
+    public Maybe<Object> getConfigRaw(ConfigKey<?> key, boolean includeInherited) {
+        if (ownConfig.containsKey(key)) return Maybe.of(ownConfig.get(key));
+        return Maybe.absent();
+    }
+    
+    /** returns the config of this policy */
+    @Override
+    public Map<ConfigKey<?>,Object> getAllConfig() {
+        // Don't use ImmutableMap because valide for values to be null
+        return Collections.unmodifiableMap(Maps.newLinkedHashMap(ownConfig));
+    }
+
+    public Object setConfig(ConfigKey<?> key, Object v) {
+        Object val = coerceConfigVal(key, v);
+        if (key instanceof StructuredConfigKey) {
+            return ((StructuredConfigKey)key).applyValueToMap(val, ownConfig);
+        } else {
+            return ownConfig.put(key, val);
+        }
+    }
+    
+    public void addToLocalBag(Map<String, ?> vals) {
+        for (Map.Entry<String, ?> entry : vals.entrySet()) {
+            setConfig(ConfigKeys.newConfigKey(Object.class, entry.getKey()), entry.getValue());
+        }
+    }
+
+    public void removeFromLocalBag(String key) {
+        ownConfig.remove(key);
+    }
+
+    @Override
+    public ConfigMapImpl submap(Predicate<ConfigKey<?>> filter) {
+        ConfigMapImpl m = new ConfigMapImpl(adjunct);
+        for (Map.Entry<ConfigKey<?>,Object> entry: ownConfig.entrySet())
+            if (filter.apply(entry.getKey()))
+                m.ownConfig.put(entry.getKey(), entry.getValue());
+        return m;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString()+"[own="+Sanitizer.sanitize(ownConfig)+"]";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/org/apache/brooklyn/core/policy/basic/GeneralPurposePolicy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/basic/GeneralPurposePolicy.java b/core/src/main/java/org/apache/brooklyn/core/policy/basic/GeneralPurposePolicy.java
new file mode 100644
index 0000000..9d140cd
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/GeneralPurposePolicy.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.policy.basic;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * @deprecated since 0.7.0; will be either deleted or moved to tests
+ */
+@Deprecated
+public class GeneralPurposePolicy extends AbstractPolicy {
+    public GeneralPurposePolicy() {
+        this(Collections.emptyMap());
+    }
+    public GeneralPurposePolicy(Map properties) {
+        super(properties);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/org/apache/brooklyn/core/policy/basic/Policies.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/basic/Policies.java b/core/src/main/java/org/apache/brooklyn/core/policy/basic/Policies.java
new file mode 100644
index 0000000..7ac8823
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/Policies.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.core.policy.basic;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.api.event.Sensor;
+import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
+
+import groovy.lang.Closure;
+import brooklyn.entity.basic.Lifecycle;
+
+@SuppressWarnings({"rawtypes","unchecked"})
+public class Policies {
+
+    public static SensorEventListener listenerFromValueClosure(final Closure code) {
+        return new SensorEventListener() {
+            @Override
+            public void onEvent(SensorEvent event) {
+                code.call(event.getValue());
+            }
+        };
+    }
+    
+    public static <T> Policy newSingleSensorValuePolicy(final Sensor<T> sensor, final Closure code) {
+        return new AbstractPolicy() {
+            @Override
+            public void setEntity(EntityLocal entity) {
+                super.setEntity(entity);
+                entity.subscribe(entity, sensor, listenerFromValueClosure(code));
+            }
+        };
+    }
+    
+    public static <S,T> Policy newSingleSensorValuePolicy(final Entity remoteEntity, final Sensor<T> remoteSensor, 
+            final Closure code) {
+        return new AbstractPolicy() {
+            @Override
+            public void setEntity(EntityLocal entity) {
+                super.setEntity(entity);
+                entity.subscribe(remoteEntity, remoteSensor, listenerFromValueClosure(code));
+            }
+        };
+    }
+
+    public static Lifecycle getPolicyStatus(Policy p) {
+        if (p.isRunning()) return Lifecycle.RUNNING;
+        if (p.isDestroyed()) return Lifecycle.DESTROYED;
+        if (p.isSuspended()) return Lifecycle.STOPPED;
+        // TODO could policy be in an error state?
+        return Lifecycle.CREATED;        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyDynamicType.java b/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyDynamicType.java
new file mode 100644
index 0000000..315d03d
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyDynamicType.java
@@ -0,0 +1,44 @@
+/*
+ * 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.policy.basic;
+
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.policy.PolicyType;
+
+import brooklyn.basic.BrooklynDynamicType;
+
+public class PolicyDynamicType extends BrooklynDynamicType<Policy, AbstractPolicy> {
+
+    public PolicyDynamicType(Class<? extends Policy> type) {
+        super(type);
+    }
+    
+    public PolicyDynamicType(AbstractPolicy policy) {
+        super(policy);
+    }
+    
+    public PolicyType getSnapshot() {
+        return (PolicyType) super.getSnapshot();
+    }
+
+    @Override
+    protected PolicyTypeSnapshot newSnapshot() {
+        return new PolicyTypeSnapshot(name, value(configKeys));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyTypeSnapshot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyTypeSnapshot.java b/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyTypeSnapshot.java
new file mode 100644
index 0000000..0e655b6
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/policy/basic/PolicyTypeSnapshot.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.core.policy.basic;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.policy.PolicyType;
+
+import brooklyn.basic.BrooklynTypeSnapshot;
+import brooklyn.config.ConfigKey;
+
+public class PolicyTypeSnapshot extends BrooklynTypeSnapshot implements PolicyType {
+    private static final long serialVersionUID = 4670930188951106009L;
+    
+    PolicyTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) {
+        super(name, configKeys);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        return (obj instanceof PolicyTypeSnapshot) && super.equals(obj);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/entity/EntityPreManagementTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/EntityPreManagementTest.java b/core/src/test/java/brooklyn/entity/EntityPreManagementTest.java
index c29682e..3fc07ed 100644
--- a/core/src/test/java/brooklyn/entity/EntityPreManagementTest.java
+++ b/core/src/test/java/brooklyn/entity/EntityPreManagementTest.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.management.EntityManager;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.test.TestUtils;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
@@ -41,7 +42,6 @@ import org.testng.annotations.Test;
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.Entities;
-import brooklyn.policy.basic.AbstractPolicy;
 
 
 @SuppressWarnings({"rawtypes","unchecked"})

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java b/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
index 80ebfb7..35a2c74 100644
--- a/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/EntitySpecTest.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.apache.brooklyn.test.entity.TestEntityImpl;
@@ -41,7 +42,6 @@ import brooklyn.event.basic.BasicConfigKey;
 
 import org.apache.brooklyn.location.basic.SimulatedLocation;
 
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.test.Asserts;
 
 import com.google.common.collect.ImmutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/entity/basic/PolicyRegistrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/basic/PolicyRegistrationTest.java b/core/src/test/java/brooklyn/entity/basic/PolicyRegistrationTest.java
index 63c6a71..2f21dd8 100644
--- a/core/src/test/java/brooklyn/entity/basic/PolicyRegistrationTest.java
+++ b/core/src/test/java/brooklyn/entity/basic/PolicyRegistrationTest.java
@@ -31,6 +31,7 @@ import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.test.TestUtils;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.apache.brooklyn.test.entity.TestEntityNoEnrichersImpl;
@@ -38,7 +39,6 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.BrooklynAppUnitTestSupport;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.collections.MutableMap;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/entity/group/GroupPickUpEntitiesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/group/GroupPickUpEntitiesTest.java b/core/src/test/java/brooklyn/entity/group/GroupPickUpEntitiesTest.java
index 0ac1ef9..8b9fa5a 100644
--- a/core/src/test/java/brooklyn/entity/group/GroupPickUpEntitiesTest.java
+++ b/core/src/test/java/brooklyn/entity/group/GroupPickUpEntitiesTest.java
@@ -25,6 +25,7 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.testng.Assert;
@@ -36,7 +37,6 @@ import brooklyn.entity.basic.BasicGroup;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.trait.Startable;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.test.Asserts;
 import brooklyn.util.javalang.Boxing;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
index 92383fc..996c656 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindCatalogItemTest.java
@@ -44,6 +44,7 @@ import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
 import org.apache.brooklyn.core.catalog.internal.CatalogDto;
 import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.test.entity.TestEntity;
 
 import brooklyn.config.BrooklynProperties;
@@ -51,8 +52,6 @@ import brooklyn.config.BrooklynServerConfig;
 
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 
-import brooklyn.policy.basic.AbstractPolicy;
-
 import com.google.common.base.Joiner;
 import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/entity/rebind/RebindFailuresTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindFailuresTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindFailuresTest.java
index 674d77e..ac2d4c7 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindFailuresTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindFailuresTest.java
@@ -40,6 +40,7 @@ import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.testng.Assert;
@@ -53,7 +54,6 @@ import brooklyn.entity.basic.EntityFunctions;
 import brooklyn.entity.basic.EntityPredicates;
 import brooklyn.entity.rebind.RebindEntityTest.MyEntity;
 import brooklyn.entity.rebind.RebindEntityTest.MyEntityImpl;
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.os.Os;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
index d74a6fc..84413c2 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindPolicyTest.java
@@ -33,6 +33,7 @@ import org.apache.brooklyn.api.mementos.BrooklynMementoManifest;
 import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -47,7 +48,6 @@ import brooklyn.entity.rebind.RebindEnricherTest.MyEnricher;
 
 import org.apache.brooklyn.location.basic.Locations;
 
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java b/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
deleted file mode 100644
index 5ac58c9..0000000
--- a/core/src/test/java/brooklyn/policy/basic/BasicPolicyTest.java
+++ /dev/null
@@ -1,89 +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 brooklyn.policy.basic;
-
-import static org.testng.Assert.assertEquals;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.policy.PolicySpec;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-import org.testng.annotations.Test;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.BrooklynAppUnitTestSupport;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.collections.MutableSet;
-
-/**
- * Test that policy can be created and accessed, by construction and by spec
- */
-public class BasicPolicyTest extends BrooklynAppUnitTestSupport {
-    
-    public static class MyPolicy extends AbstractPolicy {
-        @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");
-        
-        MyPolicy(Map<?,?> flags) {
-            super(flags);
-        }
-        
-        public MyPolicy() {
-            super();
-        }
-    }
-    
-    @Test
-    public void testAddInstance() throws Exception {
-        MyPolicy policy = new MyPolicy();
-        policy.setDisplayName("Bob");
-        policy.config().set(MyPolicy.STR_KEY, "aval");
-        policy.config().set(MyPolicy.INT_KEY, 2);
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getDisplayName(), "Bob");
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
-        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
-    }
-    
-    @Test
-    public void testAddSpec() throws Exception {
-        MyPolicy policy = app.addPolicy(PolicySpec.create(MyPolicy.class)
-            .displayName("Bob")
-            .configure(MyPolicy.STR_KEY, "aval").configure(MyPolicy.INT_KEY, 2));
-        
-        assertEquals(policy.getDisplayName(), "Bob");
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
-        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
-    }
-        
-    @Test
-    public void testTagsFromSpec() throws Exception {
-        MyPolicy policy = app.addPolicy(PolicySpec.create(MyPolicy.class).tag(99).uniqueTag("x"));
-
-        assertEquals(policy.tags().getTags(), MutableSet.of("x", 99));
-        assertEquals(policy.getUniqueTag(), "x");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/policy/basic/EnricherTypeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/EnricherTypeTest.java b/core/src/test/java/brooklyn/policy/basic/EnricherTypeTest.java
deleted file mode 100644
index 14773f5..0000000
--- a/core/src/test/java/brooklyn/policy/basic/EnricherTypeTest.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 brooklyn.policy.basic;
-
-import static org.testng.Assert.assertEquals;
-
-import org.apache.brooklyn.api.policy.EnricherType;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.enricher.basic.AbstractEnricher;
-import brooklyn.event.basic.BasicConfigKey;
-
-import com.google.common.collect.ImmutableSet;
-
-public class EnricherTypeTest {
-    private MyEnricher enricher;
-    
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception{
-        enricher = new MyEnricher();
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        // nothing to tear down; no management context not started
-    }
-    
-    @Test
-    public void testGetConfig() throws Exception {
-        EnricherType enricherType = enricher.getEnricherType();
-        assertEquals(enricherType.getConfigKeys(), ImmutableSet.of(MyEnricher.CONF1, MyEnricher.CONF2, AbstractEnricher.SUPPRESS_DUPLICATES));
-        assertEquals(enricherType.getName(), MyEnricher.class.getCanonicalName());
-        assertEquals(enricherType.getConfigKey("test.conf1"), MyEnricher.CONF1);
-        assertEquals(enricherType.getConfigKey("test.conf2"), MyEnricher.CONF2);
-    }
-    
-    public static class MyEnricher extends AbstractEnricher {
-        public static final BasicConfigKey<String> CONF1 = new BasicConfigKey<String>(String.class, "test.conf1", "my descr, conf1", "defaultval1");
-        public static final BasicConfigKey<Integer> CONF2 = new BasicConfigKey<Integer>(Integer.class, "test.conf2", "my descr, conf2", 2);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/policy/basic/PolicyConfigTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/PolicyConfigTest.java b/core/src/test/java/brooklyn/policy/basic/PolicyConfigTest.java
deleted file mode 100644
index b68781d..0000000
--- a/core/src/test/java/brooklyn/policy/basic/PolicyConfigTest.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 brooklyn.policy.basic;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-
-import org.apache.brooklyn.test.entity.TestEntity;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.BrooklynAppUnitTestSupport;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.event.basic.DependentConfiguration;
-import brooklyn.policy.basic.BasicPolicyTest.MyPolicy;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-
-import com.google.common.util.concurrent.Callables;
-
-/**
- * Test that configuration properties are usable and inherited correctly.
- */
-public class PolicyConfigTest extends BrooklynAppUnitTestSupport {
-    private static final int EARLY_RETURN_GRACE = 10;
-
-    private BasicConfigKey<String> differentKey = new BasicConfigKey<String>(String.class, "differentkey", "diffval");
-
-    @Test
-    public void testConfigFlagsPassedInAtConstructionIsAvailable() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put("strKey", "aval")
-                .put("intKey", 2)
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
-        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
-        // this is set, because key name matches annotation on STR_KEY
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), "aval");
-    }
-    
-    @Test
-    public void testUnknownConfigPassedInAtConstructionIsWarnedAndIgnored() throws Exception {
-        // TODO Also assert it's warned
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(differentKey, "aval")
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(differentKey), null);
-        assertEquals(policy.getPolicyType().getConfigKey(differentKey.getName()), null);
-    }
-    
-    @Test
-    public void testConfigPassedInAtConstructionIsAvailable() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(MyPolicy.STR_KEY, "aval")
-                .put(MyPolicy.INT_KEY, 2)
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
-        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
-        // this is not set (contrast with above)
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), MyPolicy.STR_KEY_WITH_DEFAULT.getDefaultValue());
-    }
-    
-    @Test
-    public void testConfigSetToGroovyTruthFalseIsAvailable() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(MyPolicy.INT_KEY_WITH_DEFAULT, 0)
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.INT_KEY_WITH_DEFAULT), (Integer)0);
-    }
-    
-    @Test
-    public void testConfigSetToNullIsAvailable() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(MyPolicy.STR_KEY_WITH_DEFAULT, null)
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), null);
-    }
-    
-    @Test
-    public void testConfigCanBeSetOnPolicy() throws Exception {
-        MyPolicy policy = new MyPolicy();
-        policy.config().set(MyPolicy.STR_KEY, "aval");
-        policy.config().set(MyPolicy.INT_KEY, 2);
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
-        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
-    }
-    
-    @Test
-    public void testConfigSetterOverridesConstructorValue() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(MyPolicy.STR_KEY, "aval")
-                .build());
-        policy.config().set(MyPolicy.STR_KEY, "diffval");
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "diffval");
-    }
-
-    @Test
-    public void testConfigCannotBeSetAfterApplicationIsStarted() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(MyPolicy.STR_KEY, "origval")
-                .build());
-        app.addPolicy(policy);
-        
-        try {
-            policy.config().set(MyPolicy.STR_KEY,"newval");
-            fail();
-        } catch (UnsupportedOperationException e) {
-            // success
-        }
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "origval");
-    }
-    
-    @Test
-    public void testConfigReturnsDefaultValueIfNotSet() throws Exception {
-        MyPolicy policy = new MyPolicy();
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), "str key default");
-    }
-    
-    // FIXME Should we support this now?
-    @Test(enabled=false)
-    public void testGetFutureConfigWhenReady() throws Exception {
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(TestEntity.CONF_NAME, DependentConfiguration.whenDone(Callables.returning("aval")))
-                .build());
-        app.addPolicy(policy);
-        
-        assertEquals(policy.getConfig(TestEntity.CONF_NAME), "aval");
-    }
-    
-    // FIXME Should we support this now?
-    @Test(enabled=false)
-    public void testGetFutureConfigBlocksUntilReady() throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
-        MyPolicy policy = new MyPolicy(MutableMap.builder()
-                .put(TestEntity.CONF_NAME, DependentConfiguration.whenDone(new Callable<String>() {
-                        public String call() {
-                            try {
-                                latch.await(); return "aval";
-                            } catch (InterruptedException e) {
-                                throw Exceptions.propagate(e);
-                            }
-                        }}))
-                .build());
-        app.addPolicy(policy);
-        
-        Thread t = new Thread(new Runnable() {
-                public void run() {
-                    try {
-                        Thread.sleep(10+EARLY_RETURN_GRACE); latch.countDown();
-                    } catch (InterruptedException e) {
-                        throw Exceptions.propagate(e);
-                    }
-                }});
-        try {
-            long starttime = System.currentTimeMillis();
-            t.start();
-            assertEquals(policy.getConfig(TestEntity.CONF_NAME), "aval");
-            long endtime = System.currentTimeMillis();
-            
-            assertTrue((endtime - starttime) >= 10, "starttime="+starttime+"; endtime="+endtime);
-            
-        } finally {
-            t.interrupt();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/policy/basic/PolicySubscriptionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/PolicySubscriptionTest.java b/core/src/test/java/brooklyn/policy/basic/PolicySubscriptionTest.java
deleted file mode 100644
index e3b2dc8..0000000
--- a/core/src/test/java/brooklyn/policy/basic/PolicySubscriptionTest.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 brooklyn.policy.basic;
-
-import static org.testng.Assert.assertEquals;
-
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.BrooklynAppUnitTestSupport;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.management.SubscriptionHandle;
-import org.apache.brooklyn.entity.basic.RecordingSensorEventListener;
-import org.apache.brooklyn.test.entity.TestEntity;
-
-import brooklyn.event.basic.BasicSensorEvent;
-import org.apache.brooklyn.location.basic.SimulatedLocation;
-import brooklyn.test.Asserts;
-
-import com.google.common.collect.ImmutableList;
-
-public class PolicySubscriptionTest extends BrooklynAppUnitTestSupport {
-
-    // TODO Duplication between this and EntitySubscriptionTest
-    
-    private static final long SHORT_WAIT_MS = 100;
-    
-    private SimulatedLocation loc;
-    private TestEntity entity;
-    private TestEntity otherEntity;
-    private AbstractPolicy policy;
-    private RecordingSensorEventListener<Object> listener;
-    
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        loc = app.newSimulatedLocation();
-        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        otherEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
-        listener = new RecordingSensorEventListener<>();
-        policy = new AbstractPolicy() {};
-        entity.addPolicy(policy);
-        app.start(ImmutableList.of(loc));
-    }
-
-    @Test
-    public void testSubscriptionReceivesEvents() throws Exception {
-        policy.subscribe(entity, TestEntity.SEQUENCE, listener);
-        policy.subscribe(entity, TestEntity.NAME, listener);
-        policy.subscribe(entity, TestEntity.MY_NOTIF, listener);
-        
-        otherEntity.setAttribute(TestEntity.SEQUENCE, 456);
-        entity.setAttribute(TestEntity.SEQUENCE, 123);
-        entity.setAttribute(TestEntity.NAME, "myname");
-        entity.emit(TestEntity.MY_NOTIF, 789);
-        
-        Asserts.succeedsEventually(new Runnable() {
-            @Override public void run() {
-                assertEquals(listener.getEvents(), ImmutableList.of(
-                        new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, entity, 123),
-                        new BasicSensorEvent<String>(TestEntity.NAME, entity, "myname"),
-                        new BasicSensorEvent<Integer>(TestEntity.MY_NOTIF, entity, 789)));
-            }});
-    }
-    
-    @Test
-    public void testUnsubscribeRemovesAllSubscriptionsForThatEntity() throws Exception {
-        policy.subscribe(entity, TestEntity.SEQUENCE, listener);
-        policy.subscribe(entity, TestEntity.NAME, listener);
-        policy.subscribe(entity, TestEntity.MY_NOTIF, listener);
-        policy.subscribe(otherEntity, TestEntity.SEQUENCE, listener);
-        policy.unsubscribe(entity);
-        
-        entity.setAttribute(TestEntity.SEQUENCE, 123);
-        entity.setAttribute(TestEntity.NAME, "myname");
-        entity.emit(TestEntity.MY_NOTIF, 456);
-        otherEntity.setAttribute(TestEntity.SEQUENCE, 789);
-        
-        Thread.sleep(SHORT_WAIT_MS);
-        Asserts.succeedsEventually(new Runnable() {
-            @Override public void run() {
-                assertEquals(listener.getEvents(), ImmutableList.of(
-                        new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, otherEntity, 789)));
-            }});
-    }
-    
-    @Test
-    public void testUnsubscribeUsingHandleStopsEvents() throws Exception {
-        SubscriptionHandle handle1 = policy.subscribe(entity, TestEntity.SEQUENCE, listener);
-        SubscriptionHandle handle2 = policy.subscribe(entity, TestEntity.NAME, listener);
-        SubscriptionHandle handle3 = policy.subscribe(otherEntity, TestEntity.SEQUENCE, listener);
-        
-        policy.unsubscribe(entity, handle2);
-        
-        entity.setAttribute(TestEntity.SEQUENCE, 123);
-        entity.setAttribute(TestEntity.NAME, "myname");
-        otherEntity.setAttribute(TestEntity.SEQUENCE, 456);
-        
-        Asserts.succeedsEventually(new Runnable() {
-            @Override public void run() {
-                assertEquals(listener.getEvents(), ImmutableList.of(
-                        new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, entity, 123),
-                        new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, otherEntity, 456)));
-            }});
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/policy/basic/PolicyTypeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/policy/basic/PolicyTypeTest.java b/core/src/test/java/brooklyn/policy/basic/PolicyTypeTest.java
deleted file mode 100644
index cd9b6a7..0000000
--- a/core/src/test/java/brooklyn/policy/basic/PolicyTypeTest.java
+++ /dev/null
@@ -1,58 +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 brooklyn.policy.basic;
-
-import static org.testng.Assert.assertEquals;
-
-import org.apache.brooklyn.api.policy.PolicyType;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.event.basic.BasicConfigKey;
-
-import com.google.common.collect.ImmutableSet;
-
-public class PolicyTypeTest {
-    private MyPolicy policy;
-    
-    @BeforeMethod(alwaysRun=true)
-    public void setUpTestEntity() throws Exception{
-        policy = new MyPolicy();
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        // nothing to tear down; no management context not started
-    }
-    
-    @Test
-    public void testGetConfig() throws Exception {
-        PolicyType policyType = policy.getPolicyType();
-        assertEquals(policyType.getConfigKeys(), ImmutableSet.of(MyPolicy.CONF1, MyPolicy.CONF2));
-        assertEquals(policyType.getName(), MyPolicy.class.getCanonicalName());
-        assertEquals(policyType.getConfigKey("test.conf1"), MyPolicy.CONF1);
-        assertEquals(policyType.getConfigKey("test.conf2"), MyPolicy.CONF2);
-    }
-    
-    public static class MyPolicy extends AbstractPolicy {
-        public static final BasicConfigKey<String> CONF1 = new BasicConfigKey<String>(String.class, "test.conf1", "my descr, conf1", "defaultval1");
-        public static final BasicConfigKey<Integer> CONF2 = new BasicConfigKey<Integer>(Integer.class, "test.conf2", "my descr, conf2", 2);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/brooklyn/test/policy/TestPolicy.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/test/policy/TestPolicy.java b/core/src/test/java/brooklyn/test/policy/TestPolicy.java
index 184eb4e..e30fd2c 100644
--- a/core/src/test/java/brooklyn/test/policy/TestPolicy.java
+++ b/core/src/test/java/brooklyn/test/policy/TestPolicy.java
@@ -22,12 +22,12 @@ import java.util.Collections;
 import java.util.Map;
 
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.policy.basic.AbstractPolicy;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/org/apache/brooklyn/core/policy/basic/BasicPolicyTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/policy/basic/BasicPolicyTest.java b/core/src/test/java/org/apache/brooklyn/core/policy/basic/BasicPolicyTest.java
new file mode 100644
index 0000000..852e658
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/policy/basic/BasicPolicyTest.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.policy.basic;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.testng.annotations.Test;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.util.collections.MutableSet;
+
+/**
+ * Test that policy can be created and accessed, by construction and by spec
+ */
+public class BasicPolicyTest extends BrooklynAppUnitTestSupport {
+    
+    public static class MyPolicy extends AbstractPolicy {
+        @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");
+        
+        MyPolicy(Map<?,?> flags) {
+            super(flags);
+        }
+        
+        public MyPolicy() {
+            super();
+        }
+    }
+    
+    @Test
+    public void testAddInstance() throws Exception {
+        MyPolicy policy = new MyPolicy();
+        policy.setDisplayName("Bob");
+        policy.config().set(MyPolicy.STR_KEY, "aval");
+        policy.config().set(MyPolicy.INT_KEY, 2);
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getDisplayName(), "Bob");
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
+    }
+    
+    @Test
+    public void testAddSpec() throws Exception {
+        MyPolicy policy = app.addPolicy(PolicySpec.create(MyPolicy.class)
+            .displayName("Bob")
+            .configure(MyPolicy.STR_KEY, "aval").configure(MyPolicy.INT_KEY, 2));
+        
+        assertEquals(policy.getDisplayName(), "Bob");
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
+    }
+        
+    @Test
+    public void testTagsFromSpec() throws Exception {
+        MyPolicy policy = app.addPolicy(PolicySpec.create(MyPolicy.class).tag(99).uniqueTag("x"));
+
+        assertEquals(policy.tags().getTags(), MutableSet.of("x", 99));
+        assertEquals(policy.getUniqueTag(), "x");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/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
new file mode 100644
index 0000000..380192d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.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.policy.basic;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.policy.EnricherType;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.enricher.basic.AbstractEnricher;
+import brooklyn.event.basic.BasicConfigKey;
+
+import com.google.common.collect.ImmutableSet;
+
+public class EnricherTypeTest {
+    private MyEnricher enricher;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception{
+        enricher = new MyEnricher();
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        // nothing to tear down; no management context not started
+    }
+    
+    @Test
+    public void testGetConfig() throws Exception {
+        EnricherType enricherType = enricher.getEnricherType();
+        assertEquals(enricherType.getConfigKeys(), ImmutableSet.of(MyEnricher.CONF1, MyEnricher.CONF2, AbstractEnricher.SUPPRESS_DUPLICATES));
+        assertEquals(enricherType.getName(), MyEnricher.class.getCanonicalName());
+        assertEquals(enricherType.getConfigKey("test.conf1"), MyEnricher.CONF1);
+        assertEquals(enricherType.getConfigKey("test.conf2"), MyEnricher.CONF2);
+    }
+    
+    public static class MyEnricher extends AbstractEnricher {
+        public static final BasicConfigKey<String> CONF1 = new BasicConfigKey<String>(String.class, "test.conf1", "my descr, conf1", "defaultval1");
+        public static final BasicConfigKey<Integer> CONF2 = new BasicConfigKey<Integer>(Integer.class, "test.conf2", "my descr, conf2", 2);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/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
new file mode 100644
index 0000000..295d621
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicyConfigTest.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.policy.basic;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.brooklyn.core.policy.basic.BasicPolicyTest.MyPolicy;
+import org.apache.brooklyn.test.entity.TestEntity;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.event.basic.DependentConfiguration;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.util.concurrent.Callables;
+
+/**
+ * Test that configuration properties are usable and inherited correctly.
+ */
+public class PolicyConfigTest extends BrooklynAppUnitTestSupport {
+    private static final int EARLY_RETURN_GRACE = 10;
+
+    private BasicConfigKey<String> differentKey = new BasicConfigKey<String>(String.class, "differentkey", "diffval");
+
+    @Test
+    public void testConfigFlagsPassedInAtConstructionIsAvailable() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put("strKey", "aval")
+                .put("intKey", 2)
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
+        // this is set, because key name matches annotation on STR_KEY
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), "aval");
+    }
+    
+    @Test
+    public void testUnknownConfigPassedInAtConstructionIsWarnedAndIgnored() throws Exception {
+        // TODO Also assert it's warned
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(differentKey, "aval")
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(differentKey), null);
+        assertEquals(policy.getPolicyType().getConfigKey(differentKey.getName()), null);
+    }
+    
+    @Test
+    public void testConfigPassedInAtConstructionIsAvailable() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(MyPolicy.STR_KEY, "aval")
+                .put(MyPolicy.INT_KEY, 2)
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
+        // this is not set (contrast with above)
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), MyPolicy.STR_KEY_WITH_DEFAULT.getDefaultValue());
+    }
+    
+    @Test
+    public void testConfigSetToGroovyTruthFalseIsAvailable() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(MyPolicy.INT_KEY_WITH_DEFAULT, 0)
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY_WITH_DEFAULT), (Integer)0);
+    }
+    
+    @Test
+    public void testConfigSetToNullIsAvailable() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(MyPolicy.STR_KEY_WITH_DEFAULT, null)
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), null);
+    }
+    
+    @Test
+    public void testConfigCanBeSetOnPolicy() throws Exception {
+        MyPolicy policy = new MyPolicy();
+        policy.config().set(MyPolicy.STR_KEY, "aval");
+        policy.config().set(MyPolicy.INT_KEY, 2);
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "aval");
+        assertEquals(policy.getConfig(MyPolicy.INT_KEY), (Integer)2);
+    }
+    
+    @Test
+    public void testConfigSetterOverridesConstructorValue() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(MyPolicy.STR_KEY, "aval")
+                .build());
+        policy.config().set(MyPolicy.STR_KEY, "diffval");
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "diffval");
+    }
+
+    @Test
+    public void testConfigCannotBeSetAfterApplicationIsStarted() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(MyPolicy.STR_KEY, "origval")
+                .build());
+        app.addPolicy(policy);
+        
+        try {
+            policy.config().set(MyPolicy.STR_KEY,"newval");
+            fail();
+        } catch (UnsupportedOperationException e) {
+            // success
+        }
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY), "origval");
+    }
+    
+    @Test
+    public void testConfigReturnsDefaultValueIfNotSet() throws Exception {
+        MyPolicy policy = new MyPolicy();
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(MyPolicy.STR_KEY_WITH_DEFAULT), "str key default");
+    }
+    
+    // FIXME Should we support this now?
+    @Test(enabled=false)
+    public void testGetFutureConfigWhenReady() throws Exception {
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(TestEntity.CONF_NAME, DependentConfiguration.whenDone(Callables.returning("aval")))
+                .build());
+        app.addPolicy(policy);
+        
+        assertEquals(policy.getConfig(TestEntity.CONF_NAME), "aval");
+    }
+    
+    // FIXME Should we support this now?
+    @Test(enabled=false)
+    public void testGetFutureConfigBlocksUntilReady() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        MyPolicy policy = new MyPolicy(MutableMap.builder()
+                .put(TestEntity.CONF_NAME, DependentConfiguration.whenDone(new Callable<String>() {
+                        public String call() {
+                            try {
+                                latch.await(); return "aval";
+                            } catch (InterruptedException e) {
+                                throw Exceptions.propagate(e);
+                            }
+                        }}))
+                .build());
+        app.addPolicy(policy);
+        
+        Thread t = new Thread(new Runnable() {
+                public void run() {
+                    try {
+                        Thread.sleep(10+EARLY_RETURN_GRACE); latch.countDown();
+                    } catch (InterruptedException e) {
+                        throw Exceptions.propagate(e);
+                    }
+                }});
+        try {
+            long starttime = System.currentTimeMillis();
+            t.start();
+            assertEquals(policy.getConfig(TestEntity.CONF_NAME), "aval");
+            long endtime = System.currentTimeMillis();
+            
+            assertTrue((endtime - starttime) >= 10, "starttime="+starttime+"; endtime="+endtime);
+            
+        } finally {
+            t.interrupt();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/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
new file mode 100644
index 0000000..b775598
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicySubscriptionTest.java
@@ -0,0 +1,128 @@
+/*
+ * 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.policy.basic;
+
+import static org.testng.Assert.assertEquals;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.BrooklynAppUnitTestSupport;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.management.SubscriptionHandle;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
+import org.apache.brooklyn.entity.basic.RecordingSensorEventListener;
+import org.apache.brooklyn.test.entity.TestEntity;
+
+import brooklyn.event.basic.BasicSensorEvent;
+
+import org.apache.brooklyn.location.basic.SimulatedLocation;
+
+import brooklyn.test.Asserts;
+
+import com.google.common.collect.ImmutableList;
+
+public class PolicySubscriptionTest extends BrooklynAppUnitTestSupport {
+
+    // TODO Duplication between this and EntitySubscriptionTest
+    
+    private static final long SHORT_WAIT_MS = 100;
+    
+    private SimulatedLocation loc;
+    private TestEntity entity;
+    private TestEntity otherEntity;
+    private AbstractPolicy policy;
+    private RecordingSensorEventListener<Object> listener;
+    
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        loc = app.newSimulatedLocation();
+        entity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        otherEntity = app.createAndManageChild(EntitySpec.create(TestEntity.class));
+        listener = new RecordingSensorEventListener<>();
+        policy = new AbstractPolicy() {};
+        entity.addPolicy(policy);
+        app.start(ImmutableList.of(loc));
+    }
+
+    @Test
+    public void testSubscriptionReceivesEvents() throws Exception {
+        policy.subscribe(entity, TestEntity.SEQUENCE, listener);
+        policy.subscribe(entity, TestEntity.NAME, listener);
+        policy.subscribe(entity, TestEntity.MY_NOTIF, listener);
+        
+        otherEntity.setAttribute(TestEntity.SEQUENCE, 456);
+        entity.setAttribute(TestEntity.SEQUENCE, 123);
+        entity.setAttribute(TestEntity.NAME, "myname");
+        entity.emit(TestEntity.MY_NOTIF, 789);
+        
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                assertEquals(listener.getEvents(), ImmutableList.of(
+                        new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, entity, 123),
+                        new BasicSensorEvent<String>(TestEntity.NAME, entity, "myname"),
+                        new BasicSensorEvent<Integer>(TestEntity.MY_NOTIF, entity, 789)));
+            }});
+    }
+    
+    @Test
+    public void testUnsubscribeRemovesAllSubscriptionsForThatEntity() throws Exception {
+        policy.subscribe(entity, TestEntity.SEQUENCE, listener);
+        policy.subscribe(entity, TestEntity.NAME, listener);
+        policy.subscribe(entity, TestEntity.MY_NOTIF, listener);
+        policy.subscribe(otherEntity, TestEntity.SEQUENCE, listener);
+        policy.unsubscribe(entity);
+        
+        entity.setAttribute(TestEntity.SEQUENCE, 123);
+        entity.setAttribute(TestEntity.NAME, "myname");
+        entity.emit(TestEntity.MY_NOTIF, 456);
+        otherEntity.setAttribute(TestEntity.SEQUENCE, 789);
+        
+        Thread.sleep(SHORT_WAIT_MS);
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                assertEquals(listener.getEvents(), ImmutableList.of(
+                        new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, otherEntity, 789)));
+            }});
+    }
+    
+    @Test
+    public void testUnsubscribeUsingHandleStopsEvents() throws Exception {
+        SubscriptionHandle handle1 = policy.subscribe(entity, TestEntity.SEQUENCE, listener);
+        SubscriptionHandle handle2 = policy.subscribe(entity, TestEntity.NAME, listener);
+        SubscriptionHandle handle3 = policy.subscribe(otherEntity, TestEntity.SEQUENCE, listener);
+        
+        policy.unsubscribe(entity, handle2);
+        
+        entity.setAttribute(TestEntity.SEQUENCE, 123);
+        entity.setAttribute(TestEntity.NAME, "myname");
+        otherEntity.setAttribute(TestEntity.SEQUENCE, 456);
+        
+        Asserts.succeedsEventually(new Runnable() {
+            @Override public void run() {
+                assertEquals(listener.getEvents(), ImmutableList.of(
+                        new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, entity, 123),
+                        new BasicSensorEvent<Integer>(TestEntity.SEQUENCE, otherEntity, 456)));
+            }});
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicyTypeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicyTypeTest.java b/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicyTypeTest.java
new file mode 100644
index 0000000..40c4df3
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/policy/basic/PolicyTypeTest.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.policy.basic;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.policy.PolicyType;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.event.basic.BasicConfigKey;
+
+import com.google.common.collect.ImmutableSet;
+
+public class PolicyTypeTest {
+    private MyPolicy policy;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUpTestEntity() throws Exception{
+        policy = new MyPolicy();
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        // nothing to tear down; no management context not started
+    }
+    
+    @Test
+    public void testGetConfig() throws Exception {
+        PolicyType policyType = policy.getPolicyType();
+        assertEquals(policyType.getConfigKeys(), ImmutableSet.of(MyPolicy.CONF1, MyPolicy.CONF2));
+        assertEquals(policyType.getName(), MyPolicy.class.getCanonicalName());
+        assertEquals(policyType.getConfigKey("test.conf1"), MyPolicy.CONF1);
+        assertEquals(policyType.getConfigKey("test.conf2"), MyPolicy.CONF2);
+    }
+    
+    public static class MyPolicy extends AbstractPolicy {
+        public static final BasicConfigKey<String> CONF1 = new BasicConfigKey<String>(String.class, "test.conf1", "my descr, conf1", "defaultval1");
+        public static final BasicConfigKey<Integer> CONF2 = new BasicConfigKey<Integer>(Integer.class, "test.conf2", "my descr, conf2", 2);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/locations/jclouds/src/main/java/brooklyn/policy/os/AdvertiseWinrmLoginPolicy.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/policy/os/AdvertiseWinrmLoginPolicy.java b/locations/jclouds/src/main/java/brooklyn/policy/os/AdvertiseWinrmLoginPolicy.java
index 266f738..f5257e5 100644
--- a/locations/jclouds/src/main/java/brooklyn/policy/os/AdvertiseWinrmLoginPolicy.java
+++ b/locations/jclouds/src/main/java/brooklyn/policy/os/AdvertiseWinrmLoginPolicy.java
@@ -24,6 +24,7 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,8 +33,6 @@ import brooklyn.event.basic.Sensors;
 
 import org.apache.brooklyn.location.basic.WinRmMachineLocation;
 
-import brooklyn.policy.basic.AbstractPolicy;
-
 import com.google.common.annotations.Beta;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/54f5c363/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
----------------------------------------------------------------------
diff --git a/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java b/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
index 8327cf1..dd33058 100644
--- a/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
+++ b/locations/jclouds/src/main/java/brooklyn/policy/os/CreateUserPolicy.java
@@ -26,6 +26,7 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.policy.basic.AbstractPolicy;
 import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 import org.jclouds.compute.config.AdminAccessConfiguration;
@@ -43,7 +44,6 @@ import brooklyn.event.basic.Sensors;
 
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
-import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.text.Identifiers;
 
 import com.google.common.annotations.Beta;



[09/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/ShellToolAbstractTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/ShellToolAbstractTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/ShellToolAbstractTest.java
new file mode 100644
index 0000000..794a512
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/ShellToolAbstractTest.java
@@ -0,0 +1,441 @@
+/*
+ * 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.util.internal.ssh;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+
+public abstract class ShellToolAbstractTest {
+
+    protected List<ShellTool> tools = Lists.newArrayList();
+    protected List<String> filesCreated;
+    protected String localFilePath;
+    
+    protected ShellTool tool;
+    
+    protected ShellTool newTool() {
+        return newTool(MutableMap.<String,Object>of());
+    }
+    
+    protected ShellTool newTool(Map<String,?> flags) {
+        ShellTool t = newUnregisteredTool(flags);
+        tools.add(t);
+        return t;
+    }
+
+    protected abstract ShellTool newUnregisteredTool(Map<String,?> flags);
+    
+    protected ShellTool tool() { return tool; }
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        localFilePath = "/tmp/ssh-test-local-"+Identifiers.makeRandomId(8);
+        filesCreated = new ArrayList<String>();
+        filesCreated.add(localFilePath);
+
+        tool = newTool();
+        connect(tool);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void afterMethod() throws Exception {
+        for (ShellTool t : tools) {
+            if (t instanceof SshTool) ((SshTool)t).disconnect();
+        }
+        for (String fileCreated : filesCreated) {
+            new File(fileCreated).delete();
+        }
+    }
+
+    protected static void connect(ShellTool tool) {
+        if (tool instanceof SshTool)
+            ((SshTool)tool).connect();
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecConsecutiveCommands() throws Exception {
+        String out = execScript("echo run1");
+        String out2 = execScript("echo run2");
+        
+        assertTrue(out.contains("run1"), "out="+out);
+        assertTrue(out2.contains("run2"), "out="+out);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecScriptChainOfCommands() throws Exception {
+        String out = execScript("export MYPROP=abc", "echo val is $MYPROP");
+
+        assertTrue(out.contains("val is abc"), "out="+out);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecScriptReturningNonZeroExitCode() throws Exception {
+        int exitcode = tool.execScript(MutableMap.<String,Object>of(), ImmutableList.of("exit 123"));
+        assertEquals(exitcode, 123);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecScriptReturningZeroExitCode() throws Exception {
+        int exitcode = tool.execScript(MutableMap.<String,Object>of(), ImmutableList.of("date"));
+        assertEquals(exitcode, 0);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecScriptCommandWithEnvVariables() throws Exception {
+        String out = execScript(ImmutableList.of("echo val is $MYPROP2"), ImmutableMap.of("MYPROP2", "myval"));
+
+        assertTrue(out.contains("val is myval"), "out="+out);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testScriptDataNotLost() throws Exception {
+        String out = execScript("echo `echo foo``echo bar`");
+
+        assertTrue(out.contains("foobar"), "out="+out);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecScriptWithSleepThenExit() throws Exception {
+        Stopwatch watch = Stopwatch.createStarted();
+        execScript("sleep 1", "exit 0");
+        assertTrue(watch.elapsed(TimeUnit.MILLISECONDS) > 900, "only slept "+Time.makeTimeStringRounded(watch));
+    }
+
+    // Really just tests that it returns; the command will be echo'ed automatically so this doesn't assert the command will have been executed
+    @Test(groups = {"Integration"})
+    public void testExecScriptBigCommand() throws Exception {
+        String bigstring = Strings.repeat("a", 10000);
+        String out = execScript("echo "+bigstring);
+        
+        assertTrue(out.contains(bigstring), "out="+out);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecScriptBigChainOfCommand() throws Exception {
+        String bigstring = Strings.repeat("abcdefghij", 100); // 1KB
+        List<String> cmds = Lists.newArrayList();
+        for (int i = 0; i < 10; i++) {
+            cmds.add("export MYPROP"+i+"="+bigstring);
+            cmds.add("echo val"+i+" is $MYPROP"+i);
+        }
+        String out = execScript(cmds);
+        
+        for (int i = 0; i < 10; i++) {
+            assertTrue(out.contains("val"+i+" is "+bigstring), "out="+out);
+        }
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecScriptAbortsOnCommandFailure() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int exitcode = tool.execScript(ImmutableMap.of("out", out), ImmutableList.of("export MYPROP=myval", "acmdthatdoesnotexist", "echo val is $MYPROP"));
+        String outstr = new String(out.toByteArray());
+
+        assertFalse(outstr.contains("val is myval"), "out="+out);
+        assertNotEquals(exitcode,  0);
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testExecScriptWithSleepThenBigCommand() throws Exception {
+        String bigstring = Strings.repeat("abcdefghij", 1000); // 10KB
+        String out = execScript("sleep 2", "export MYPROP="+bigstring, "echo val is $MYPROP");
+        assertTrue(out.contains("val is "+bigstring), "out="+out);
+    }
+    
+    @Test(groups = {"WIP", "Integration"})
+    public void testExecScriptBigConcurrentCommand() throws Exception {
+        ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
+        List<ListenableFuture<?>> futures = new ArrayList<ListenableFuture<?>>();
+        try {
+            for (int i = 0; i < 10; i++) {
+                final ShellTool localtool = newTool();
+                connect(localtool);
+                
+                futures.add(executor.submit(new Runnable() {
+                        public void run() {
+                            String bigstring = Strings.repeat("abcdefghij", 1000); // 10KB
+                            String out = execScript(localtool, ImmutableList.of("export MYPROP="+bigstring, "echo val is $MYPROP"));
+                            assertTrue(out.contains("val is "+bigstring), "outSize="+out.length()+"; out="+out);
+                        }}));
+            }
+            Futures.allAsList(futures).get();
+        } finally {
+            executor.shutdownNow();
+        }
+    }
+
+    @Test(groups = {"WIP", "Integration"})
+    public void testExecScriptBigConcurrentSleepyCommand() throws Exception {
+        ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
+        List<ListenableFuture<?>> futures = new ArrayList<ListenableFuture<?>>();
+        try {
+            long starttime = System.currentTimeMillis();
+            for (int i = 0; i < 10; i++) {
+                final ShellTool localtool = newTool();
+                connect(localtool);
+                
+                futures.add(executor.submit(new Runnable() {
+                        public void run() {
+                            String bigstring = Strings.repeat("abcdefghij", 1000); // 10KB
+                            String out = execScript(localtool, ImmutableList.of("sleep 2", "export MYPROP="+bigstring, "echo val is $MYPROP"));
+                            assertTrue(out.contains("val is "+bigstring), "out="+out);
+                        }}));
+            }
+            Futures.allAsList(futures).get();
+            long runtime = System.currentTimeMillis() - starttime;
+            
+            long OVERHEAD = 20*1000;
+            assertTrue(runtime < 2000+OVERHEAD, "runtime="+runtime);
+            
+        } finally {
+            executor.shutdownNow();
+        }
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecChainOfCommands() throws Exception {
+        String out = execCommands("MYPROP=abc", "echo val is $MYPROP");
+
+        assertEquals(out, "val is abc\n");
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecReturningNonZeroExitCode() throws Exception {
+        int exitcode = tool.execCommands(MutableMap.<String,Object>of(), ImmutableList.of("exit 123"));
+        assertEquals(exitcode, 123);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecReturningZeroExitCode() throws Exception {
+        int exitcode = tool.execCommands(MutableMap.<String,Object>of(), ImmutableList.of("date"));
+        assertEquals(exitcode, 0);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecCommandWithEnvVariables() throws Exception {
+        String out = execCommands(ImmutableList.of("echo val is $MYPROP2"), ImmutableMap.of("MYPROP2", "myval"));
+
+        assertEquals(out, "val is myval\n");
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecBigCommand() throws Exception {
+        String bigstring = Strings.repeat("abcdefghij", 1000); // 10KB
+        String out = execCommands("echo "+bigstring);
+
+        assertEquals(out, bigstring+"\n", "actualSize="+out.length()+"; expectedSize="+bigstring.length());
+    }
+
+    @Test(groups = {"Integration"})
+    public void testExecBigConcurrentCommand() throws Exception {
+        runExecBigConcurrentCommand(10, 0L);
+    }
+    
+    // TODO Fails I believe due to synchronization model in SshjTool of calling connect/disconnect.
+    // Even with a retry-count of 4, it still fails because some commands are calling disconnect
+    // while another concurrently executing command expects to be still connected.
+    @Test(groups = {"Integration", "WIP"})
+    public void testExecBigConcurrentCommandWithStaggeredStart() throws Exception {
+        // This test is to vary the concurrency of concurrent actions
+        runExecBigConcurrentCommand(50, 100L);
+    }
+    
+    protected void runExecBigConcurrentCommand(int numCommands, long staggeredDelayBeforeStart) throws Exception {
+        ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
+        List<ListenableFuture<?>> futures = new ArrayList<ListenableFuture<?>>();
+        try {
+            for (int i = 0; i < numCommands; i++) {
+                long delay = (long) (Math.random() * staggeredDelayBeforeStart);
+                if (i > 0) Time.sleep(delay);
+                
+                futures.add(executor.submit(new Runnable() {
+                        public void run() {
+                            String bigstring = Strings.repeat("abcdefghij", 1000); // 10KB
+                            String out = execCommands("echo "+bigstring);
+                            assertEquals(out, bigstring+"\n", "actualSize="+out.length()+"; expectedSize="+bigstring.length());
+                        }}));
+            }
+            Futures.allAsList(futures).get();
+        } finally {
+            executor.shutdownNow();
+        }
+    }
+
+    // fails if terminal enabled
+    @Test(groups = {"Integration"})
+    @Deprecated // tests deprecated code
+    public void testExecScriptCapturesStderr() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream err = new ByteArrayOutputStream();
+        String nonExistantCmd = "acmdthatdoesnotexist";
+        tool.execScript(ImmutableMap.of("out", out, "err", err), ImmutableList.of(nonExistantCmd));
+        assertTrue(new String(err.toByteArray()).contains(nonExistantCmd+": command not found"), "out="+out+"; err="+err);
+    }
+
+    // fails if terminal enabled
+    @Test(groups = {"Integration"})
+    @Deprecated // tests deprecated code
+    public void testExecCapturesStderr() throws Exception {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream err = new ByteArrayOutputStream();
+        String nonExistantCmd = "acmdthatdoesnotexist";
+        tool.execCommands(ImmutableMap.of("out", out, "err", err), ImmutableList.of(nonExistantCmd));
+        String errMsg = new String(err.toByteArray());
+        assertTrue(errMsg.contains(nonExistantCmd+": command not found\n"), "errMsg="+errMsg+"; out="+out+"; err="+err);
+        
+    }
+
+    @Test(groups = {"Integration"})
+    public void testScriptHeader() {
+        final ShellTool localtool = newTool();
+        String out = execScript(MutableMap.of("scriptHeader", "#!/bin/bash -e\necho hello world\n"), 
+                localtool, Arrays.asList("echo goodbye world"), null);
+        assertTrue(out.contains("goodbye world"), "no goodbye in output: "+out);
+        assertTrue(out.contains("hello world"), "no hello in output: "+out);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testStdErr() {
+        final ShellTool localtool = newTool();
+        Map<String,Object> props = new LinkedHashMap<String, Object>();
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream err = new ByteArrayOutputStream();
+        props.put("out", out);
+        props.put("err", err);
+        int exitcode = localtool.execScript(props, Arrays.asList("echo hello err > /dev/stderr"), null);
+        assertFalse(out.toString().contains("hello err"), "hello found where it shouldn't have been, in stdout: "+out);
+        assertTrue(err.toString().contains("hello err"), "no hello in stderr: "+err);
+        assertEquals(0, exitcode);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testRunAsRoot() {
+        final ShellTool localtool = newTool();
+        Map<String,Object> props = new LinkedHashMap<String, Object>();
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream err = new ByteArrayOutputStream();
+        props.put("out", out);
+        props.put("err", err);
+        props.put(SshTool.PROP_RUN_AS_ROOT.getName(), true);
+        int exitcode = localtool.execScript(props, Arrays.asList("whoami"), null);
+        assertTrue(out.toString().contains("root"), "not running as root; whoami is: "+out+" (err is '"+err+"')");
+        assertEquals(0, exitcode);
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testExecScriptEchosExecute() throws Exception {
+        String out = execScript("date");
+        assertTrue(out.toString().contains("Executed"), "Executed did not display: "+out);
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testExecScriptEchosDontExecuteWhenToldNoExtraOutput() throws Exception {
+        final ShellTool localtool = newTool();
+        Map<String,Object> props = new LinkedHashMap<String, Object>();
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream err = new ByteArrayOutputStream();
+        props.put("out", out);
+        props.put("err", err);
+        props.put(SshTool.PROP_NO_EXTRA_OUTPUT.getName(), true);
+        int exitcode = localtool.execScript(props, Arrays.asList("echo hello world"), null);
+        assertFalse(out.toString().contains("Executed"), "Executed should not have displayed: "+out);
+        assertEquals(out.toString().trim(), "hello world");
+        assertEquals(0, exitcode);
+    }
+    
+    protected String execCommands(String... cmds) {
+        return execCommands(Arrays.asList(cmds));
+    }
+    
+    protected String execCommands(List<String> cmds) {
+        return execCommands(cmds, ImmutableMap.<String,Object>of());
+    }
+
+    protected String execCommands(List<String> cmds, Map<String,?> env) {
+        return execCommands(null, cmds, env);
+    }
+
+    protected String execCommands(ConfigBag config, List<String> cmds, Map<String,?> env) {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        MutableMap<String,Object> flags = MutableMap.<String,Object>of("out", out);
+        if (config!=null) flags.add(config.getAllConfig());
+        tool.execCommands(flags, cmds, env);
+        return new String(out.toByteArray());
+    }
+
+    protected String execScript(String... cmds) {
+        return execScript(tool, Arrays.asList(cmds));
+    }
+
+    protected String execScript(ShellTool t, List<String> cmds) {
+        return execScript(ImmutableMap.<String,Object>of(), t, cmds, ImmutableMap.<String,Object>of());
+    }
+
+    protected String execScript(List<String> cmds) {
+        return execScript(cmds, ImmutableMap.<String,Object>of());
+    }
+    
+    protected String execScript(List<String> cmds, Map<String,?> env) {
+        return execScript(MutableMap.<String,Object>of(), tool, cmds, env);
+    }
+    
+    protected String execScript(Map<String, ?> props, ShellTool tool, List<String> cmds, Map<String,?> env) {
+        Map<String, Object> props2 = new LinkedHashMap<String, Object>(props);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        props2.put("out", out);
+        int exitcode = tool.execScript(props2, cmds, env);
+        String outstr = new String(out.toByteArray());
+        assertEquals(exitcode, 0, outstr);
+        return outstr;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/SshToolAbstractIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/SshToolAbstractIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/SshToolAbstractIntegrationTest.java
new file mode 100644
index 0000000..309d4fb
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/SshToolAbstractIntegrationTest.java
@@ -0,0 +1,304 @@
+/*
+ * 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.util.internal.ssh;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshException;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.os.Os;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.Files;
+
+/**
+ * Test the operation of the {@link SshTool} utility class; to be extended to test concrete implementations.
+ * 
+ * Requires keys set up, e.g. running:
+ * 
+ * <pre>
+ * cd ~/.ssh
+ * ssh-keygen
+ * id_rsa_with_passphrase
+ * mypassphrase
+ * mypassphrase
+ * </pre>
+ * 
+ */
+public abstract class SshToolAbstractIntegrationTest extends ShellToolAbstractTest {
+
+    private static final Logger log = LoggerFactory.getLogger(SshToolAbstractIntegrationTest.class);
+    
+    // FIXME need tests which take properties set in entities and brooklyn.properties;
+    // but not in this class because it is lower level than entities, Aled would argue.
+
+    // TODO No tests for retry logic and exception handing yet
+
+    public static final String SSH_KEY_WITH_PASSPHRASE = System.getProperty("sshPrivateKeyWithPassphrase", "~/.ssh/id_rsa_with_passphrase");
+    public static final String SSH_PASSPHRASE = System.getProperty("sshPrivateKeyPassphrase", "mypassphrase");
+
+    protected String remoteFilePath;
+
+    protected SshTool tool() { return (SshTool)tool; }
+    
+    protected abstract SshTool newUnregisteredTool(Map<String,?> flags);
+
+    @Override
+    protected SshTool newTool() {
+        return newTool(ImmutableMap.of("host", "localhost", "privateKeyFile", "~/.ssh/id_rsa"));
+    }
+    
+    @Override
+    protected SshTool newTool(Map<String,?> flags) {
+        return (SshTool) super.newTool(flags);
+    }
+    
+
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        super.setUp();
+        remoteFilePath = "/tmp/ssh-test-remote-"+Identifiers.makeRandomId(8);
+        filesCreated.add(remoteFilePath);
+    }
+    
+    protected void assertRemoteFileContents(String remotePath, String expectedContents) {
+        String catout = execCommands("cat "+remotePath);
+        assertEquals(catout, expectedContents);
+    }
+    
+    /**
+     * @param remotePath
+     * @param expectedPermissions Of the form, for example, "-rw-r--r--"
+     */
+    protected void assertRemoteFilePermissions(String remotePath, String expectedPermissions) {
+        String lsout = execCommands("ls -l "+remotePath);
+        assertTrue(lsout.contains(expectedPermissions), lsout);
+    }
+    
+    protected void assertRemoteFileLastModifiedIsNow(String remotePath) {
+        // Check default last-modified time is `now`.
+        // Be lenient in assertion, in case unlucky that clock ticked over to next hour/minute as test was running.
+        // TODO Code could be greatly improved, but low priority!
+        // Output format:
+        //   -rw-r--r--  1   aled  wheel  18  Apr 24  15:03 /tmp/ssh-test-remote-CvFN9zQA
+        //   [0]         [1] [2]   [3]    [4] [5] [6] [7]   [8]
+        
+        String lsout = execCommands("ls -l "+remotePath);
+        
+        String[] lsparts = lsout.split("\\s+");
+        int day = Integer.parseInt(lsparts[6]);
+        int hour = Integer.parseInt(lsparts[7].split(":")[0]);
+        int minute = Integer.parseInt(lsparts[7].split(":")[1]);
+        
+        Calendar expected = Calendar.getInstance();
+        int expectedDay = expected.get(Calendar.DAY_OF_MONTH);
+        int expectedHour = expected.get(Calendar.HOUR_OF_DAY);
+        int expectedMinute = expected.get(Calendar.MINUTE);
+        
+        assertEquals(day, expectedDay, "ls="+lsout+"; lsparts="+Arrays.toString(lsparts)+"; expected="+expected+"; expectedDay="+expectedDay+"; day="+day+"; zone="+expected.getTimeZone());
+        assertTrue(Math.abs(hour - expectedHour) <= 1, "ls="+lsout+"; lsparts="+Arrays.toString(lsparts)+"; expected="+expected+"; expectedHour="+expectedHour+"; hour="+hour+"; zone="+expected.getTimeZone());
+        assertTrue(Math.abs(minute - expectedMinute) <= 1, "ls="+lsout+"; lsparts="+Arrays.toString(lsparts)+"; expected="+expected+"; expectedMinute="+expectedMinute+"; minute="+minute+"; zone="+expected.getTimeZone());
+    }
+
+    @Test(groups = {"Integration"})
+    public void testCopyToServerFromBytes() throws Exception {
+        String contents = "echo hello world!\n";
+        byte[] contentBytes = contents.getBytes();
+        tool().copyToServer(MutableMap.<String,Object>of(), contentBytes, remoteFilePath);
+
+        assertRemoteFileContents(remoteFilePath, contents);
+        assertRemoteFilePermissions(remoteFilePath, "-rw-r--r--");
+        
+        // TODO would like to also assert lastModified time, but on jenkins the jvm locale
+        // and the OS locale are different (i.e. different timezones) so the file time-stamp 
+        // is several hours out.
+        //assertRemoteFileLastModifiedIsNow(remoteFilePath);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testCopyToServerFromInputStream() throws Exception {
+        String contents = "echo hello world!\n";
+        ByteArrayInputStream contentsStream = new ByteArrayInputStream(contents.getBytes());
+        tool().copyToServer(MutableMap.<String,Object>of(), contentsStream, remoteFilePath);
+
+        assertRemoteFileContents(remoteFilePath, contents);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testCopyToServerWithPermissions() throws Exception {
+        tool().copyToServer(ImmutableMap.of("permissions","0754"), "echo hello world!\n".getBytes(), remoteFilePath);
+
+        assertRemoteFilePermissions(remoteFilePath, "-rwxr-xr--");
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testCopyToServerWithLastModifiedDate() throws Exception {
+        long lastModificationTime = 1234567;
+        tool().copyToServer(ImmutableMap.of("lastModificationDate", lastModificationTime), "echo hello world!\n".getBytes(), remoteFilePath);
+
+        String lsout = execCommands("ls -l "+remoteFilePath);//+" | awk '{print \$6 \" \" \$7 \" \" \$8}'"])
+        //execCommands([ "ls -l "+remoteFilePath+" | awk '{print \$6 \" \" \$7 \" \" \$8}'"])
+        //varies depending on timezone
+        assertTrue(lsout.contains("Jan 15  1970") || lsout.contains("Jan 14  1970") || lsout.contains("Jan 16  1970"), lsout);
+        //assertLastModified(lsout, lastModifiedDate)
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testCopyFileToServerWithPermissions() throws Exception {
+        String contents = "echo hello world!\n";
+        Files.write(contents, new File(localFilePath), Charsets.UTF_8);
+        tool().copyToServer(ImmutableMap.of("permissions", "0754"), new File(localFilePath), remoteFilePath);
+
+        assertRemoteFileContents(remoteFilePath, contents);
+
+        String lsout = execCommands("ls -l "+remoteFilePath);
+        assertTrue(lsout.contains("-rwxr-xr--"), lsout);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testCopyFromServer() throws Exception {
+        String contentsWithoutLineBreak = "echo hello world!";
+        String contents = contentsWithoutLineBreak+"\n";
+        tool().copyToServer(MutableMap.<String,Object>of(), contents.getBytes(), remoteFilePath);
+        
+        tool().copyFromServer(MutableMap.<String,Object>of(), remoteFilePath, new File(localFilePath));
+
+        List<String> actual = Files.readLines(new File(localFilePath), Charsets.UTF_8);
+        assertEquals(actual, ImmutableList.of(contentsWithoutLineBreak));
+    }
+    
+    // TODO No config options in sshj or scp for auto-creating the parent directories
+    @Test(enabled=false, groups = {"Integration"})
+    public void testCopyFileToNonExistantDir() throws Exception {
+        String contents = "echo hello world!\n";
+        String remoteFileDirPath = "/tmp/ssh-test-remote-dir-"+Identifiers.makeRandomId(8);
+        String remoteFileInDirPath = remoteFileDirPath + File.separator + "ssh-test-remote-"+Identifiers.makeRandomId(8);
+        filesCreated.add(remoteFileInDirPath);
+        filesCreated.add(remoteFileDirPath);
+        
+        tool().copyToServer(MutableMap.<String,Object>of(), contents.getBytes(), remoteFileInDirPath);
+
+        assertRemoteFileContents(remoteFileInDirPath, contents);
+    }
+    
+
+    @Test(groups = {"Integration"})
+    public void testAllocatePty() {
+        final ShellTool localtool = newTool(MutableMap.of("host", "localhost", SshTool.PROP_ALLOCATE_PTY.getName(), true));
+        Map<String,Object> props = new LinkedHashMap<String, Object>();
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream err = new ByteArrayOutputStream();
+        props.put("out", out);
+        props.put("err", err);
+        int exitcode = localtool.execScript(props, Arrays.asList("echo hello err > /dev/stderr"), null);
+        assertTrue(out.toString().contains("hello err"), "no hello in output: "+out+" (err is '"+err+"')");
+        assertFalse(err.toString().contains("hello err"), "hello found in stderr: "+err);
+        assertEquals(0, exitcode);
+    }
+
+    // Requires setting up an extra ssh key, with a passphrase, and adding it to ~/.ssh/authorized_keys
+    @Test(groups = {"Integration"})
+    public void testSshKeyWithPassphrase() throws Exception {
+        final SshTool localtool = newTool(ImmutableMap.<String,Object>builder()
+                .put(SshTool.PROP_HOST.getName(), "localhost")
+                .put(SshTool.PROP_PRIVATE_KEY_FILE.getName(), SSH_KEY_WITH_PASSPHRASE)
+                .put(SshTool.PROP_PRIVATE_KEY_PASSPHRASE.getName(), SSH_PASSPHRASE)
+                .build());
+        localtool.connect();
+        
+        assertEquals(tool.execScript(MutableMap.<String,Object>of(), ImmutableList.of("date")), 0);
+
+        // Also needs the negative test to prove that we're really using an ssh-key with a passphrase
+        try {
+            final SshTool localtool2 = newTool(ImmutableMap.<String,Object>builder()
+                    .put(SshTool.PROP_HOST.getName(), "localhost")
+                    .put(SshTool.PROP_PRIVATE_KEY_FILE.getName(), SSH_KEY_WITH_PASSPHRASE)
+                    .build());
+            localtool2.connect();
+            fail();
+        } catch (Exception e) {
+            SshException se = Exceptions.getFirstThrowableOfType(e, SshException.class);
+            if (se == null) throw e;
+        }
+    }
+
+    @Test(groups = {"Integration"})
+    public void testConnectWithInvalidUserThrowsException() throws Exception {
+        final ShellTool localtool = newTool(ImmutableMap.of("user", "wronguser", "host", "localhost", "privateKeyFile", "~/.ssh/id_rsa"));
+        tools.add(localtool);
+        try {
+            connect(localtool);
+            fail();
+        } catch (SshException e) {
+            if (!e.toString().contains("failed to connect")) throw e;
+        }
+    }
+
+    @Test(groups = {"Integration"})
+    public void testOutputAsExpected() throws Exception {
+        final String CONTENTS = "hello world\n"
+            + "bye bye\n";
+        execCommands("cat > "+Os.mergePaths(Os.tmp(), "test1")+" << X\n"
+            + CONTENTS
+            + "X\n");
+        String read = execCommands("echo START_FOO", "cat "+Os.mergePaths(Os.tmp(), "test1"), "echo END_FOO");
+        log.debug("read back data written, as:\n"+read);
+        String contents = Strings.getFragmentBetween(read, "START_FOO", "END_FOO");
+        Assert.assertEquals(CONTENTS.trim(), contents.trim());
+    }
+
+    @Test(groups = {"Integration"})
+    public void testScriptDirPropertiesIsRespected() {
+        // For explanation of (some of) the magic behind this command, see http://stackoverflow.com/a/229606/68898
+        final String command = "if [[ \"$0\" == \"/var/tmp/\"* ]]; then true; else false; fi";
+
+        SshTool sshTool = newTool(ImmutableMap.<String, Object>builder()
+                .put(SshTool.PROP_HOST.getName(), "localhost")
+                .build());
+        int rc = sshTool.execScript(ImmutableMap.<String, Object>builder()
+                .put(SshTool.PROP_SCRIPT_DIR.getName(), "/var/tmp")
+                .build(), ImmutableList.of(command));
+        assertEquals(rc, 0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/SshToolAbstractPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/SshToolAbstractPerformanceTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/SshToolAbstractPerformanceTest.java
new file mode 100644
index 0000000..1730816
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/SshToolAbstractPerformanceTest.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.core.util.internal.ssh;
+
+import java.io.ByteArrayOutputStream;
+import java.lang.management.ManagementFactory;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Test the performance of different variants of invoking the sshj tool.
+ * 
+ * Intended for human-invocation and inspection, to see which parts are most expensive.
+ */
+public abstract class SshToolAbstractPerformanceTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SshToolAbstractPerformanceTest.class);
+    
+    private SshTool tool;
+    
+    protected abstract SshTool newSshTool(Map<String,?> flags);
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        if (tool != null) tool.disconnect();
+    }
+
+    @Test(groups = {"Integration"})
+    public void testConsecutiveConnectAndDisconnect() throws Exception {
+        Runnable task = new Runnable() {
+            public void run() {
+                tool = newSshTool(MutableMap.of("host", "localhost"));
+                tool.connect();
+                tool.disconnect();
+            }
+        };
+        runMany(task, "connect-disconnect", 10);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testConsecutiveSmallCommands() throws Exception {
+        runExecManyCommands(ImmutableList.of("true"), false, "small-cmd", 10);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testConsecutiveSmallCommandsWithStdouterr() throws Exception {
+        runExecManyCommands(ImmutableList.of("true"), true, "small-cmd-with-stdout", 10);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testConsecutiveBigStdoutCommands() throws Exception {
+        runExecManyCommands(ImmutableList.of("head -c 100000 /dev/urandom"), true, "big-stdout", 10);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testConsecutiveBigStdinCommands() throws Exception {
+        String bigstr = Identifiers.makeRandomId(100000);
+        runExecManyCommands(ImmutableList.of("echo "+bigstr+" | wc -c"), true, "big-stdin", 10);
+    }
+
+    private void runExecManyCommands(final List<String> cmds, final boolean captureOutAndErr, String context, int iterations) throws Exception {
+        Runnable task = new Runnable() {
+                @Override public void run() {
+                    execScript(cmds, captureOutAndErr);
+                }};
+        runMany(task, context, iterations);
+    }
+
+    private void runMany(Runnable task, String context, int iterations) throws Exception {
+        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
+        ObjectName osMBeanName = ObjectName.getInstance(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
+        long preCpuTime = (Long) mbeanServer.getAttribute(osMBeanName, "ProcessCpuTime");
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        
+        for (int i = 0; i < iterations; i++) {
+            task.run();
+            
+            long postCpuTime = (Long) mbeanServer.getAttribute(osMBeanName, "ProcessCpuTime");
+            long elapsedTime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
+            double fractionCpu = (elapsedTime > 0) ? ((double)postCpuTime-preCpuTime) / TimeUnit.MILLISECONDS.toNanos(elapsedTime) : -1;
+            LOG.info("Executing {}; completed {}; took {}; fraction cpu {}", new Object[] {context, (i+1), Time.makeTimeStringRounded(elapsedTime), fractionCpu});
+        }
+    }
+
+    private int execScript(List<String> cmds, boolean captureOutandErr) {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream err = new ByteArrayOutputStream();
+        MutableMap<String,?> flags = (captureOutandErr) ? MutableMap.of("out", out, "err", err) : MutableMap.<String,Object>of();
+        
+        tool = newSshTool(MutableMap.of("host", "localhost"));
+        tool.connect();
+        int result = tool.execScript(flags, cmds);
+        tool.disconnect();
+        
+        int outlen = out.toByteArray().length;
+        int errlen = out.toByteArray().length;
+        if (LOG.isTraceEnabled()) LOG.trace("Executed: result={}; stdout={}; stderr={}", new Object[] {result, outlen, errlen});
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliToolIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliToolIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliToolIntegrationTest.java
new file mode 100644
index 0000000..f8efa87
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliToolIntegrationTest.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.util.internal.ssh.cli;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.internal.ssh.SshException;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshToolAbstractIntegrationTest;
+import org.apache.brooklyn.core.util.internal.ssh.cli.SshCliTool;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test the operation of the {@link SshJschTool} utility class.
+ */
+public class SshCliToolIntegrationTest extends SshToolAbstractIntegrationTest {
+
+    private static final Logger log = LoggerFactory.getLogger(SshCliToolIntegrationTest.class);
+    
+    protected SshTool newUnregisteredTool(Map<String,?> flags) {
+        return new SshCliTool(flags);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testFlags() throws Exception {
+        final SshTool localtool = newTool(ImmutableMap.of("sshFlags", "-vvv -tt", "host", "localhost"));
+        tools.add(localtool);
+        try {
+            localtool.connect();
+            Map<String,Object> props = new LinkedHashMap<String, Object>();
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            ByteArrayOutputStream err = new ByteArrayOutputStream();
+            props.put("out", out);
+            props.put("err", err);
+            int exitcode = localtool.execScript(props, Arrays.asList("echo hello err > /dev/stderr"), null);
+            Assert.assertEquals(0, exitcode, "exitCode="+exitcode+", but expected 0");
+            log.debug("OUT from ssh -vvv command is: "+out);
+            log.debug("ERR from ssh -vvv command is: "+err);
+            assertFalse(err.toString().contains("hello err"), "hello found where it shouldn't have been, in stderr (should have been tty merged to stdout): "+err);
+            assertTrue(out.toString().contains("hello err"), "no hello in stdout: "+err);
+            // look for word 'ssh' to confirm we got verbose output
+            assertTrue(err.toString().toLowerCase().contains("ssh"), "no mention of ssh in stderr: "+err);
+        } catch (SshException e) {
+            if (!e.toString().contains("failed to connect")) throw e;
+        }
+    }
+
+    // Need to have at least one test method here (rather than just inherited) for eclipse to recognize it
+    @Test(enabled = false)
+    public void testDummy() throws Exception {
+    }
+    
+    // TODO When running mvn on the command line (for Aled), this test hangs when prompting for a password (but works in the IDE!)
+    // Doing .connect() isn't enough; need to cause ssh or scp to be invoked
+    @Test(enabled=false, groups = {"Integration"})
+    public void testConnectWithInvalidUserThrowsException() throws Exception {
+        final SshTool localtool = newTool(ImmutableMap.of("user", "wronguser", "host", "localhost", "privateKeyFile", "~/.ssh/id_rsa"));
+        tools.add(localtool);
+        try {
+            localtool.connect();
+            int result = localtool.execScript(ImmutableMap.<String,Object>of(), ImmutableList.of("date"));
+            fail("exitCode="+result+", but expected exception");
+        } catch (SshException e) {
+            if (!e.toString().contains("failed to connect")) throw e;
+        }
+    }
+    
+    // TODO ssh-cli doesn't support pass-phrases yet
+    @Test(enabled=false, groups = {"Integration"})
+    public void testSshKeyWithPassphrase() throws Exception {
+        super.testSshKeyWithPassphrase();
+    }
+
+    // Setting last modified date not yet supported for cli-based ssh
+    @Override
+    @Test(enabled=false, groups = {"Integration"})
+    public void testCopyToServerWithLastModifiedDate() throws Exception {
+        super.testCopyToServerWithLastModifiedDate();
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testExecReturningNonZeroExitCode() throws Exception {
+        int exitcode = tool.execCommands(MutableMap.<String,Object>of(), ImmutableList.of("exit 123"));
+        assertEquals(exitcode, 123);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliToolPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliToolPerformanceTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliToolPerformanceTest.java
new file mode 100644
index 0000000..fd01180
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/cli/SshCliToolPerformanceTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util.internal.ssh.cli;
+
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshToolAbstractPerformanceTest;
+import org.apache.brooklyn.core.util.internal.ssh.cli.SshCliTool;
+import org.testng.annotations.Test;
+
+/**
+ * Test the performance of different variants of invoking the sshj tool.
+ * 
+ * Intended for human-invocation and inspection, to see which parts are most expensive.
+ */
+public class SshCliToolPerformanceTest extends SshToolAbstractPerformanceTest {
+
+    @Override
+    protected SshTool newSshTool(Map<String,?> flags) {
+        return new SshCliTool(flags);
+    }
+    
+    // Need to have at least one test method here (rather than just inherited) for eclipse to recognize it
+    @Test(enabled = false)
+    public void testDummy() throws Exception {
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessToolIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessToolIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessToolIntegrationTest.java
new file mode 100644
index 0000000..3dd558d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessToolIntegrationTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.util.internal.ssh.process;
+
+import static org.testng.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.internal.ssh.ShellToolAbstractTest;
+import org.apache.brooklyn.core.util.internal.ssh.process.ProcessTool;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Test the operation of the {@link ProcessTool} utility class.
+ */
+public class ProcessToolIntegrationTest extends ShellToolAbstractTest {
+
+    @Override
+    protected ProcessTool newUnregisteredTool(Map<String,?> flags) {
+        return new ProcessTool(flags);
+    }
+
+    // ones here included as *non*-integration tests. must run on windows and linux.
+    // (also includes integration tests from parent)
+
+    @Test(groups="UNIX")
+    public void testPortableCommand() throws Exception {
+        String out = execScript("echo hello world");
+        assertTrue(out.contains("hello world"), "out="+out);
+    }
+
+    @Test(groups="Integration")
+    public void testLoginShell() {
+        // this detection scheme only works for commands; can't test whether it works for scripts without 
+        // requiring stuff in bash_profile / profile / etc, which gets hard to make portable;
+        // it is nearly the same code path on the impl so this is probably enough 
+        
+        final String LOGIN_SHELL_CHECK = "shopt -q login_shell && echo 'yes, login shell' || echo 'no, not login shell'";
+        ConfigBag config = ConfigBag.newInstance().configure(ProcessTool.PROP_NO_EXTRA_OUTPUT, true);
+        String out;
+        
+        out = execCommands(config, Arrays.asList(LOGIN_SHELL_CHECK), null);
+        Assert.assertEquals(out.trim(), "no, not login shell", "out = "+out);
+        
+        config.configure(ProcessTool.PROP_LOGIN_SHELL, true);
+        out = execCommands(config, Arrays.asList(LOGIN_SHELL_CHECK), null);
+        Assert.assertEquals(out.trim(), "yes, login shell", "out = "+out);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessToolStaticsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessToolStaticsTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessToolStaticsTest.java
new file mode 100644
index 0000000..eacd761
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/process/ProcessToolStaticsTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.util.internal.ssh.process;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.brooklyn.core.util.internal.ssh.process.ProcessTool;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.os.Os;
+
+public class ProcessToolStaticsTest {
+
+    ByteArrayOutputStream out;
+    ByteArrayOutputStream err;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void clear() {
+        out = new ByteArrayOutputStream();
+        err = new ByteArrayOutputStream();
+    }
+    
+    private List<String> getTestCommand() {
+        if(Os.isMicrosoftWindows()) {
+            return Arrays.asList("cmd", "/c", "echo", "hello", "world");
+        } else {
+            return Arrays.asList("echo", "hello", "world");
+        }
+    }
+
+    @Test
+    public void testRunsWithStdout() throws Exception {
+        int code = ProcessTool.execSingleProcess(getTestCommand(), null, (File)null, out, err, this);
+        Assert.assertEquals(err.toString().trim(), "");
+        Assert.assertEquals(out.toString().trim(), "hello world");
+        Assert.assertEquals(code, 0);
+    }
+
+    @Test(groups="Integration") // *nix only
+    public void testRunsWithBashEnvVarAndStderr() throws Exception {
+        int code = ProcessTool.execSingleProcess(Arrays.asList("/bin/bash", "-c", "echo hello $NAME | tee /dev/stderr"), 
+                MutableMap.of("NAME", "BOB"), (File)null, out, err, this);
+        Assert.assertEquals(err.toString().trim(), "hello BOB", "err is: "+err);
+        Assert.assertEquals(out.toString().trim(), "hello BOB", "out is: "+out);
+        Assert.assertEquals(code, 0);
+    }
+
+    @Test(groups="Integration") // *nix only
+    public void testRunsManyCommandsWithBashEnvVarAndStderr() throws Exception {
+        int code = ProcessTool.execProcesses(Arrays.asList("echo hello $NAME", "export NAME=JOHN", "echo goodbye $NAME | tee /dev/stderr"), 
+                MutableMap.of("NAME", "BOB"), (File)null, out, err, " ; ", false, this);
+        Assert.assertEquals(err.toString().trim(), "goodbye JOHN", "err is: "+err);
+        Assert.assertEquals(out.toString().trim(), "hello BOB\ngoodbye JOHN", "out is: "+out);
+        Assert.assertEquals(code, 0);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java
new file mode 100644
index 0000000..e3b4b7d
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.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.core.util.internal.ssh.sshj;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
+import org.apache.brooklyn.core.util.internal.ssh.SshAbstractTool.SshAction;
+import org.apache.brooklyn.core.util.internal.ssh.sshj.SshjTool;
+import org.apache.brooklyn.core.util.internal.ssh.sshj.SshjTool.ShellAction;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+/**
+ * Tests for async-exec with {@link SshjTool}, where it stubs out the actual ssh commands
+ * to return a controlled sequence of responses.
+ */
+public class SshjToolAsyncStubIntegrationTest {
+
+    static class InjectedResult {
+        Predicate<SshjTool.ShellAction> expected;
+        Function<SshjTool.ShellAction, Integer> result;
+        
+        InjectedResult(Predicate<SshjTool.ShellAction> expected, Function<SshjTool.ShellAction, Integer> result) {
+            this.expected = expected;
+            this.result = result;
+        }
+    }
+    
+    private SshjTool tool;
+    private List<InjectedResult> sequence;
+    int counter = 0;
+    private boolean origFeatureEnablement;
+    
+    @BeforeMethod(alwaysRun=true)
+    public void setUp() throws Exception {
+        origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
+        sequence = Lists.newArrayList();
+        counter = 0;
+        
+        tool = new SshjTool(ImmutableMap.<String,Object>of("host", "localhost")) {
+            @SuppressWarnings("unchecked")
+            protected <T, C extends SshAction<T>> T acquire(C action, int sshTries, Duration sshTriesTimeout) {
+                if (action instanceof SshjTool.ShellAction) {
+                    SshjTool.ShellAction shellAction = (SshjTool.ShellAction) action;
+                    InjectedResult injectedResult = sequence.get(counter);
+                    assertTrue(injectedResult.expected.apply(shellAction), "counter="+counter+"; cmds="+shellAction.commands);
+                    counter++;
+                    return (T) injectedResult.result.apply(shellAction);
+                }
+                return super.acquire(action, sshTries, sshTriesTimeout);
+            }
+        };
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        try {
+            if (tool != null) tool.disconnect();
+        } finally {
+            BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
+        }
+    }
+    
+    private Predicate<SshjTool.ShellAction> containsCmd(final String cmd) {
+        return new Predicate<SshjTool.ShellAction>() {
+            @Override public boolean apply(ShellAction input) {
+                return input != null && input.commands.toString().contains(cmd);
+            }
+        };
+    }
+    
+    private Function<SshjTool.ShellAction, Integer> returning(final int result, final String stdout, final String stderr) {
+        return new Function<SshjTool.ShellAction, Integer>() {
+            @Override public Integer apply(ShellAction input) {
+                try {
+                    if (stdout != null && input.out != null) input.out.write(stdout.getBytes());
+                    if (stderr != null && input.err != null) input.err.write(stderr.getBytes());
+                } catch (IOException e) {
+                    throw Exceptions.propagate(e);
+                }
+                return result;
+            }
+        };
+    }
+    
+    @Test(groups="Integration")
+    public void testPolls() throws Exception {
+        sequence = ImmutableList.of(
+                new InjectedResult(containsCmd("nohup"), returning(0, "", "")),
+                new InjectedResult(containsCmd("# Long poll"), returning(0, "mystringToStdout", "mystringToStderr")));
+
+        runTest(0, "mystringToStdout", "mystringToStderr");
+        assertEquals(counter, sequence.size());
+    }
+    
+    @Test(groups="Integration")
+    public void testPollsAndReturnsNonZeroExitCode() throws Exception {
+        sequence = ImmutableList.of(
+                new InjectedResult(containsCmd("nohup"), returning(0, "", "")),
+                new InjectedResult(containsCmd("# Long poll"), returning(123, "mystringToStdout", "mystringToStderr")),
+                new InjectedResult(containsCmd("# Retrieve status"), returning(0, "123", "")));
+
+        runTest(123, "mystringToStdout", "mystringToStderr");
+        assertEquals(counter, sequence.size());
+    }
+    
+    @Test(groups="Integration")
+    public void testPollsRepeatedly() throws Exception {
+        sequence = ImmutableList.of(
+                new InjectedResult(containsCmd("nohup"), returning(0, "", "")),
+                new InjectedResult(containsCmd("# Long poll"), returning(125, "mystringToStdout", "mystringToStderr")),
+                new InjectedResult(containsCmd("# Retrieve status"), returning(0, "", "")),
+                new InjectedResult(containsCmd("# Long poll"), returning(125, "mystringToStdout2", "mystringToStderr2")),
+                new InjectedResult(containsCmd("# Retrieve status"), returning(0, "", "")),
+                new InjectedResult(containsCmd("# Long poll"), returning(-1, "mystringToStdout3", "mystringToStderr3")),
+                new InjectedResult(containsCmd("# Long poll"), returning(125, "mystringToStdout4", "mystringToStderr4")),
+                new InjectedResult(containsCmd("# Retrieve status"), returning(0, "", "")),
+                new InjectedResult(containsCmd("# Long poll"), returning(0, "mystringToStdout5", "mystringToStderr5")));
+
+        runTest(0,
+                "mystringToStdout"+"mystringToStdout2"+"mystringToStdout3"+"mystringToStdout4"+"mystringToStdout5",
+                "mystringToStderr"+"mystringToStderr2"+"mystringToStderr3"+"mystringToStderr4"+"mystringToStderr5");
+        assertEquals(counter, sequence.size());
+    }
+    
+    protected void runTest(int expectedExit, String expectedStdout, String expectedStderr) throws Exception {
+        List<String> cmds = ImmutableList.of("abc");
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        ByteArrayOutputStream err = new ByteArrayOutputStream();
+        int exitCode = tool.execScript(
+                ImmutableMap.of(
+                        "out", out, 
+                        "err", err, 
+                        SshjTool.PROP_EXEC_ASYNC.getName(), true, 
+                        SshjTool.PROP_NO_EXTRA_OUTPUT.getName(), true,
+                        SshjTool.PROP_EXEC_ASYNC_POLLING_TIMEOUT.getName(), Duration.ONE_MILLISECOND), 
+                cmds, 
+                ImmutableMap.<String,String>of());
+        String outStr = new String(out.toByteArray());
+        String errStr = new String(err.toByteArray());
+
+        assertEquals(exitCode, expectedExit);
+        assertEquals(outStr.trim(), expectedStdout);
+        assertEquals(errStr.trim(), expectedStderr);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolIntegrationTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolIntegrationTest.java
new file mode 100644
index 0000000..bf1aafb
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolIntegrationTest.java
@@ -0,0 +1,314 @@
+/*
+ * 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.util.internal.ssh.sshj;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+import net.schmizz.sshj.connection.channel.direct.Session;
+
+import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
+import org.apache.brooklyn.core.util.internal.ssh.SshException;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshToolAbstractIntegrationTest;
+import org.apache.brooklyn.core.util.internal.ssh.sshj.SshjTool;
+import org.testng.annotations.Test;
+
+import brooklyn.test.Asserts;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.RuntimeTimeoutException;
+import brooklyn.util.os.Os;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test the operation of the {@link SshJschTool} utility class.
+ */
+public class SshjToolIntegrationTest extends SshToolAbstractIntegrationTest {
+
+    @Override
+    protected SshTool newUnregisteredTool(Map<String,?> flags) {
+        return new SshjTool(flags);
+    }
+
+    // TODO requires vt100 terminal emulation to work?
+    @Test(enabled = false, groups = {"Integration"})
+    public void testExecShellWithCommandTakingStdin() throws Exception {
+        // Uses `tee` to redirect stdin to the given file; cntr-d (i.e. char 4) stops tee with exit code 0
+        String content = "blah blah";
+        String out = execShellDirectWithTerminalEmulation("tee "+remoteFilePath, content, ""+(char)4, "echo file contents: `cat "+remoteFilePath+"`");
+
+        assertTrue(out.contains("file contents: blah blah"), "out="+out);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testGivesUpAfterMaxRetries() throws Exception {
+        final AtomicInteger callCount = new AtomicInteger();
+        
+        final SshTool localtool = new SshjTool(ImmutableMap.of("sshTries", 3, "host", "localhost", "privateKeyFile", "~/.ssh/id_rsa")) {
+            protected SshAction<Session> newSessionAction() {
+                callCount.incrementAndGet();
+                throw new RuntimeException("Simulating ssh execution failure");
+            }
+        };
+        
+        tools.add(localtool);
+        try {
+            localtool.execScript(ImmutableMap.<String,Object>of(), ImmutableList.of("true"));
+            fail();
+        } catch (SshException e) {
+            if (!e.toString().contains("out of retries")) throw e;
+            assertEquals(callCount.get(), 3);
+        }
+    }
+
+    @Test(groups = {"Integration"})
+    public void testReturnsOnSuccessWhenRetrying() throws Exception {
+        final AtomicInteger callCount = new AtomicInteger();
+        final int successOnAttempt = 2;
+        final SshTool localtool = new SshjTool(ImmutableMap.of("sshTries", 3, "host", "localhost", "privateKeyFile", "~/.ssh/id_rsa")) {
+            protected SshAction<Session> newSessionAction() {
+                callCount.incrementAndGet();
+                if (callCount.incrementAndGet() >= successOnAttempt) {
+                    return super.newSessionAction();
+                } else {
+                    throw new RuntimeException("Simulating ssh execution failure");
+                }
+            }
+        };
+        
+        tools.add(localtool);
+        localtool.execScript(ImmutableMap.<String,Object>of(), ImmutableList.of("true"));
+        assertEquals(callCount.get(), successOnAttempt);
+    }
+
+    @Test(groups = {"Integration"})
+    public void testGivesUpAfterMaxTime() throws Exception {
+        final AtomicInteger callCount = new AtomicInteger();
+        final SshTool localtool = new SshjTool(ImmutableMap.of("sshTriesTimeout", 1000, "host", "localhost", "privateKeyFile", "~/.ssh/id_rsa")) {
+            protected SshAction<Session> newSessionAction() {
+                callCount.incrementAndGet();
+                try {
+                    Thread.sleep(600);
+                } catch (InterruptedException e) {
+                    throw Exceptions.propagate(e);
+                }
+                throw new RuntimeException("Simulating ssh execution failure");
+            }
+        };
+        
+        tools.add(localtool);
+        try {
+            localtool.execScript(ImmutableMap.<String,Object>of(), ImmutableList.of("true"));
+            fail();
+        } catch (RuntimeTimeoutException e) {
+            if (!e.toString().contains("out of time")) throw e;
+            assertEquals(callCount.get(), 2);
+        }
+    }
+    
+    @Test(groups = {"Integration"})
+    public void testUsesCustomLocalTempDir() throws Exception {
+        class SshjToolForTest extends SshjTool {
+            public SshjToolForTest(Map<String, ?> map) {
+                super(map);
+            }
+            public File getLocalTempDir() {
+                return localTempDir;
+            }
+        };
+        
+        final SshjToolForTest localtool = new SshjToolForTest(ImmutableMap.<String, Object>of("host", "localhost"));
+        assertNotNull(localtool.getLocalTempDir());
+        assertEquals(localtool.getLocalTempDir(), new File(Os.tidyPath(SshjTool.PROP_LOCAL_TEMP_DIR.getDefaultValue())));
+        
+        String customTempDir = Os.tmp();
+        final SshjToolForTest localtool2 = new SshjToolForTest(ImmutableMap.of(
+                "host", "localhost", 
+                SshjTool.PROP_LOCAL_TEMP_DIR.getName(), customTempDir));
+        assertEquals(localtool2.getLocalTempDir(), new File(customTempDir));
+        
+        String customRelativeTempDir = "~/tmp";
+        final SshjToolForTest localtool3 = new SshjToolForTest(ImmutableMap.of(
+                "host", "localhost", 
+                SshjTool.PROP_LOCAL_TEMP_DIR.getName(), customRelativeTempDir));
+        assertEquals(localtool3.getLocalTempDir(), new File(Os.tidyPath(customRelativeTempDir)));
+    }
+
+    @Test(groups = {"Integration"})
+    public void testAsyncExecStdoutAndStderr() throws Exception {
+        boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
+        try {
+            // Include a sleep, to ensure that the contents retrieved in first poll and subsequent polls are appended
+            List<String> cmds = ImmutableList.of(
+                    "echo mystringToStdout",
+                    "echo mystringToStderr 1>&2",
+                    "sleep 5",
+                    "echo mystringPostSleepToStdout",
+                    "echo mystringPostSleepToStderr 1>&2");
+            
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            ByteArrayOutputStream err = new ByteArrayOutputStream();
+            int exitCode = tool.execScript(
+                    ImmutableMap.of(
+                            "out", out, 
+                            "err", err, 
+                            SshjTool.PROP_EXEC_ASYNC.getName(), true, 
+                            SshjTool.PROP_NO_EXTRA_OUTPUT.getName(), true,
+                            SshjTool.PROP_EXEC_ASYNC_POLLING_TIMEOUT.getName(), Duration.ONE_SECOND), 
+                    cmds, 
+                    ImmutableMap.<String,String>of());
+            String outStr = new String(out.toByteArray());
+            String errStr = new String(err.toByteArray());
+    
+            assertEquals(exitCode, 0);
+            assertEquals(outStr.trim(), "mystringToStdout\nmystringPostSleepToStdout");
+            assertEquals(errStr.trim(), "mystringToStderr\nmystringPostSleepToStderr");
+        } finally {
+            BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
+        }
+    }
+
+    @Test(groups = {"Integration"})
+    public void testAsyncExecReturnsExitCode() throws Exception {
+        boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
+        try {
+            int exitCode = tool.execScript(
+                    ImmutableMap.of(SshjTool.PROP_EXEC_ASYNC.getName(), true), 
+                    ImmutableList.of("exit 123"), 
+                    ImmutableMap.<String,String>of());
+            assertEquals(exitCode, 123);
+        } finally {
+            BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
+        }
+    }
+
+    @Test(groups = {"Integration"})
+    public void testAsyncExecTimesOut() throws Exception {
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
+        try {
+            tool.execScript(
+                ImmutableMap.of(SshjTool.PROP_EXEC_ASYNC.getName(), true, SshjTool.PROP_EXEC_TIMEOUT.getName(), Duration.millis(1)), 
+                ImmutableList.of("sleep 60"), 
+                ImmutableMap.<String,String>of());
+            fail();
+        } catch (Exception e) {
+            TimeoutException te = Exceptions.getFirstThrowableOfType(e, TimeoutException.class);
+            if (te == null) throw e;
+        } finally {
+            BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
+        }
+        
+        long seconds = stopwatch.elapsed(TimeUnit.SECONDS);
+        assertTrue(seconds < 30, "exec took "+seconds+" seconds");
+    }
+
+    @Test(groups = {"Integration"})
+    public void testAsyncExecAbortsIfProcessFails() throws Exception {
+        final AtomicReference<Throwable> error = new AtomicReference<Throwable>();
+        Thread thread = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Stopwatch stopwatch = Stopwatch.createStarted();
+                    int exitStatus = tool.execScript(
+                        ImmutableMap.of(SshjTool.PROP_EXEC_ASYNC.getName(), true, SshjTool.PROP_EXEC_TIMEOUT.getName(), Duration.millis(1)), 
+                        ImmutableList.of("sleep 63"), 
+                        ImmutableMap.<String,String>of());
+                    
+                    assertEquals(exitStatus, 143 /* 128 + Signal number (SIGTERM) */);
+                    
+                    long seconds = stopwatch.elapsed(TimeUnit.SECONDS);
+                    assertTrue(seconds < 30, "exec took "+seconds+" seconds");
+                } catch (Throwable t) {
+                    error.set(t);
+                }
+            }});
+        
+        boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
+        try {
+            thread.start();
+            
+            Asserts.succeedsEventually(new Runnable() {
+                @Override
+                public void run() {
+                    int exitStatus = tool.execCommands(ImmutableMap.<String,Object>of(), ImmutableList.of("ps aux| grep \"sleep 63\" | grep -v grep"));
+                    assertEquals(exitStatus, 0);
+                }});
+            
+            tool.execCommands(ImmutableMap.<String,Object>of(), ImmutableList.of("ps aux| grep \"sleep 63\" | grep -v grep | awk '{print($2)}' | xargs kill"));
+            
+            thread.join(30*1000);
+            assertFalse(thread.isAlive());
+            if (error.get() != null) {
+                throw Exceptions.propagate(error.get());
+            }
+        } finally {
+            thread.interrupt();
+            BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
+        }
+    }
+
+    
+    protected String execShellDirect(List<String> cmds) {
+        return execShellDirect(cmds, ImmutableMap.<String,Object>of());
+    }
+    
+    protected String execShellDirect(List<String> cmds, Map<String,?> env) {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int exitcode = ((SshjTool)tool).execShellDirect(ImmutableMap.of("out", out), cmds, env);
+        String outstr = new String(out.toByteArray());
+        assertEquals(exitcode, 0, outstr);
+        return outstr;
+    }
+
+    private String execShellDirectWithTerminalEmulation(String... cmds) {
+        return execShellDirectWithTerminalEmulation(Arrays.asList(cmds));
+    }
+    
+    private String execShellDirectWithTerminalEmulation(List<String> cmds) {
+        return execShellDirectWithTerminalEmulation(cmds, ImmutableMap.<String,Object>of());
+    }
+    
+    private String execShellDirectWithTerminalEmulation(List<String> cmds, Map<String,?> env) {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int exitcode = ((SshjTool)tool).execShellDirect(ImmutableMap.of("allocatePTY", true, "out", out), cmds, env);
+        String outstr = new String(out.toByteArray());
+        assertEquals(exitcode, 0, outstr);
+        return outstr;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolPerformanceTest.java b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolPerformanceTest.java
new file mode 100644
index 0000000..71ea4e6
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/internal/ssh/sshj/SshjToolPerformanceTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util.internal.ssh.sshj;
+
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshToolAbstractPerformanceTest;
+import org.apache.brooklyn.core.util.internal.ssh.sshj.SshjTool;
+import org.testng.annotations.Test;
+
+/**
+ * Test the performance of different variants of invoking the sshj tool.
+ * 
+ * Intended for human-invocation and inspection, to see which parts are most expensive.
+ */
+public class SshjToolPerformanceTest extends SshToolAbstractPerformanceTest {
+
+    @Override
+    protected SshTool newSshTool(Map<String,?> flags) {
+        return new SshjTool(flags);
+    }
+    
+    // Need to have at least one test method here (rather than just inherited) for eclipse to recognize it
+    @Test(enabled = false)
+    public void testDummy() throws Exception {
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/org/apache/brooklyn/core/util/mutex/WithMutexesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/util/mutex/WithMutexesTest.java b/core/src/test/java/org/apache/brooklyn/core/util/mutex/WithMutexesTest.java
new file mode 100644
index 0000000..c37ab30
--- /dev/null
+++ b/core/src/test/java/org/apache/brooklyn/core/util/mutex/WithMutexesTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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.util.mutex;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.brooklyn.core.util.mutex.MutexSupport;
+import org.apache.brooklyn.core.util.mutex.SemaphoreWithOwners;
+import org.apache.brooklyn.core.util.mutex.WithMutexes;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class WithMutexesTest {
+
+    @Test
+    public void testOneAcquisitionAndRelease() throws InterruptedException {
+        MutexSupport m = new MutexSupport();
+        Map<String, SemaphoreWithOwners> sems;
+        SemaphoreWithOwners s;
+        try {
+            m.acquireMutex("foo", "something foo");
+            sems = m.getAllSemaphores();
+            Assert.assertEquals(sems.size(), 1);
+            s = sems.get("foo");
+            Assert.assertEquals(s.getDescription(), "something foo");
+            Assert.assertEquals(s.getOwningThreads(), Arrays.asList(Thread.currentThread()));
+            Assert.assertEquals(s.getRequestingThreads(), Collections.emptyList());
+            Assert.assertTrue(s.isInUse());
+            Assert.assertTrue(s.isCallingThreadAnOwner());
+        } finally {
+            m.releaseMutex("foo");
+        }
+        Assert.assertFalse(s.isInUse());
+        Assert.assertFalse(s.isCallingThreadAnOwner());
+        Assert.assertEquals(s.getDescription(), "something foo");
+        Assert.assertEquals(s.getOwningThreads(), Collections.emptyList());
+        Assert.assertEquals(s.getRequestingThreads(), Collections.emptyList());
+        
+        sems = m.getAllSemaphores();
+        Assert.assertEquals(sems, Collections.emptyMap());
+    }
+
+    @Test(groups = "Integration")  //just because it takes a wee while
+    public void testBlockingAcquisition() throws InterruptedException {
+        final MutexSupport m = new MutexSupport();
+        m.acquireMutex("foo", "something foo");
+        
+        Assert.assertFalse(m.tryAcquireMutex("foo", "something else"));
+
+        Thread t = new Thread() {
+            public void run() {
+                try {
+                    m.acquireMutex("foo", "thread 2 foo");
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                m.releaseMutex("foo");
+            }
+        };
+        t.start();
+        
+        t.join(500);
+        Assert.assertTrue(t.isAlive());
+        Assert.assertEquals(m.getSemaphore("foo").getRequestingThreads(), Arrays.asList(t));
+
+        m.releaseMutex("foo");
+        
+        t.join(1000);
+        Assert.assertFalse(t.isAlive());
+
+        Assert.assertEquals(m.getAllSemaphores(), Collections.emptyMap());
+    }
+
+    
+    public static class SampleWithMutexesDelegatingMixin implements WithMutexes {
+        
+        /* other behaviour would typically go here... */
+        
+        WithMutexes mutexSupport = new MutexSupport();
+        
+        @Override
+        public void acquireMutex(String mutexId, String description) throws InterruptedException {
+            mutexSupport.acquireMutex(mutexId, description);
+        }
+
+        @Override
+        public boolean tryAcquireMutex(String mutexId, String description) {
+            return mutexSupport.tryAcquireMutex(mutexId, description);
+        }
+
+        @Override
+        public void releaseMutex(String mutexId) {
+            mutexSupport.releaseMutex(mutexId);
+        }
+
+        @Override
+        public boolean hasMutex(String mutexId) {
+            return mutexSupport.hasMutex(mutexId);
+        }
+    }
+    
+    @Test
+    public void testDelegatingMixinPattern() throws InterruptedException {
+        WithMutexes m = new SampleWithMutexesDelegatingMixin();
+        m.acquireMutex("foo", "sample");
+        Assert.assertTrue(m.hasMutex("foo"));
+        Assert.assertFalse(m.hasMutex("bar"));
+        m.releaseMutex("foo");
+        Assert.assertFalse(m.hasMutex("foo"));
+    }
+}



[30/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ForwardingTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ForwardingTask.java b/core/src/main/java/brooklyn/util/task/ForwardingTask.java
deleted file mode 100644
index 3bc3427..0000000
--- a/core/src/main/java/brooklyn/util/task/ForwardingTask.java
+++ /dev/null
@@ -1,325 +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 brooklyn.util.task;
-
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.apache.brooklyn.api.management.Task;
-
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Function;
-import com.google.common.collect.ForwardingObject;
-import com.google.common.util.concurrent.ExecutionList;
-import com.google.common.util.concurrent.ListenableFuture;
-
-public abstract class ForwardingTask<T> extends ForwardingObject implements TaskInternal<T> {
-
-    /** Constructor for use by subclasses. */
-    protected ForwardingTask() {}
-
-    @Override
-    protected abstract TaskInternal<T> delegate();
-
-    @Override
-    public void addListener(Runnable listener, Executor executor) {
-        delegate().addListener(listener, executor);
-    }
-
-    @Override
-    public boolean cancel(boolean arg0) {
-        return delegate().cancel(arg0);
-    }
-
-    @Override
-    public T get() throws InterruptedException, ExecutionException {
-        return delegate().get();
-    }
-
-    @Override
-    public T get(long arg0, TimeUnit arg1) throws InterruptedException, ExecutionException, TimeoutException {
-        return delegate().get(arg0, arg1);
-    }
-
-    @Override
-    public boolean isCancelled() {
-        return delegate().isCancelled();
-    }
-
-    @Override
-    public boolean isDone() {
-        return delegate().isDone();
-    }
-
-    @Override
-    public Task<T> asTask() {
-        return delegate().asTask();
-    }
-
-    @Override
-    public String getId() {
-        return delegate().getId();
-    }
-
-    @Override
-    public Set<Object> getTags() {
-        return delegate().getTags();
-    }
-
-    @Override
-    public long getSubmitTimeUtc() {
-        return delegate().getSubmitTimeUtc();
-    }
-
-    @Override
-    public long getStartTimeUtc() {
-        return delegate().getStartTimeUtc();
-    }
-
-    @Override
-    public long getEndTimeUtc() {
-        return delegate().getEndTimeUtc();
-    }
-
-    @Override
-    public String getDisplayName() {
-        return delegate().getDisplayName();
-    }
-
-    @Override
-    public String getDescription() {
-        return delegate().getDescription();
-    }
-
-    @Override
-    public Task<?> getSubmittedByTask() {
-        return delegate().getSubmittedByTask();
-    }
-
-    @Override
-    public Thread getThread() {
-        return delegate().getThread();
-    }
-
-    @Override
-    public boolean isSubmitted() {
-        return delegate().isSubmitted();
-    }
-
-    @Override
-    public boolean isBegun() {
-        return delegate().isBegun();
-    }
-
-    @Override
-    public boolean isError() {
-        return delegate().isError();
-    }
-
-    @Override
-    public void blockUntilStarted() {
-        delegate().blockUntilStarted();
-    }
-
-    @Override
-    public void blockUntilEnded() {
-        delegate().blockUntilEnded();
-    }
-
-    @Override
-    public boolean blockUntilEnded(Duration timeout) {
-        return delegate().blockUntilEnded(timeout);
-    }
-
-    @Override
-    public String getStatusSummary() {
-        return delegate().getStatusSummary();
-    }
-
-    @Override
-    public String getStatusDetail(boolean multiline) {
-        return delegate().getStatusDetail(multiline);
-    }
-
-    @Override
-    public T get(Duration duration) throws InterruptedException, ExecutionException, TimeoutException {
-        return delegate().get(duration);
-    }
-
-    @Override
-    public T getUnchecked() {
-        return delegate().getUnchecked();
-    }
-
-    @Override
-    public T getUnchecked(Duration duration) {
-        return delegate().getUnchecked(duration);
-    }
-
-    @Override
-    public void initInternalFuture(ListenableFuture<T> result) {
-        delegate().initInternalFuture(result);
-    }
-
-    @Override
-    public long getQueuedTimeUtc() {
-        return delegate().getQueuedTimeUtc();
-    }
-
-    @Override
-    public Future<T> getInternalFuture() {
-        return delegate().getInternalFuture();
-    }
-
-    @Override
-    public boolean isQueued() {
-        return delegate().isQueued();
-    }
-
-    @Override
-    public boolean isQueuedOrSubmitted() {
-        return delegate().isQueuedOrSubmitted();
-    }
-
-    @Override
-    public boolean isQueuedAndNotSubmitted() {
-        return delegate().isQueuedAndNotSubmitted();
-    }
-
-    @Override
-    public void markQueued() {
-        delegate().markQueued();
-    }
-
-    @Override
-    public boolean cancel() {
-        return delegate().cancel();
-    }
-
-    @Override
-    public boolean blockUntilStarted(Duration timeout) {
-        return delegate().blockUntilStarted(timeout);
-    }
-
-    @Override
-    public String setBlockingDetails(String blockingDetails) {
-        return delegate().setBlockingDetails(blockingDetails);
-    }
-
-    @Override
-    public Task<?> setBlockingTask(Task<?> blockingTask) {
-        return delegate().setBlockingTask(blockingTask);
-    }
-
-    @Override
-    public void resetBlockingDetails() {
-        delegate().resetBlockingDetails();
-    }
-
-    @Override
-    public void resetBlockingTask() {
-        delegate().resetBlockingTask();
-    }
-
-    @Override
-    public String getBlockingDetails() {
-        return delegate().getBlockingDetails();
-    }
-
-    @Override
-    public Task<?> getBlockingTask() {
-        return delegate().getBlockingTask();
-    }
-
-    @Override
-    public void setExtraStatusText(Object extraStatus) {
-        delegate().setExtraStatusText(extraStatus);
-    }
-
-    @Override
-    public Object getExtraStatusText() {
-        return delegate().getExtraStatusText();
-    }
-
-    @Override
-    public void runListeners() {
-        delegate().runListeners();
-    }
-
-    @Override
-    public void setEndTimeUtc(long val) {
-        delegate().setEndTimeUtc(val);
-    }
-
-    @Override
-    public void setThread(Thread thread) {
-        delegate().setThread(thread);
-    }
-
-    @Override
-    public Callable<T> getJob() {
-        return delegate().getJob();
-    }
-
-    @Override
-    public void setJob(Callable<T> job) {
-        delegate().setJob(job);
-    }
-
-    @Override
-    public ExecutionList getListeners() {
-        return delegate().getListeners();
-    }
-
-    @Override
-    public void setSubmitTimeUtc(long currentTimeMillis) {
-        delegate().setSubmitTimeUtc(currentTimeMillis);
-    }
-
-    @Override
-    public void setSubmittedByTask(Task<?> task) {
-        delegate().setSubmittedByTask(task);
-    }
-
-    @Override
-    public Set<Object> getMutableTags() {
-        return delegate().getMutableTags();
-    }
-
-    @Override
-    public void setStartTimeUtc(long currentTimeMillis) {
-        delegate().setStartTimeUtc(currentTimeMillis);
-    }
-
-    @Override
-    public void applyTagModifier(Function<Set<Object>, Void> modifier) {
-        delegate().applyTagModifier(modifier);
-    }
-    
-    @Override
-    public Task<?> getProxyTarget() {
-        return delegate().getProxyTarget();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ListenableForwardingFuture.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ListenableForwardingFuture.java b/core/src/main/java/brooklyn/util/task/ListenableForwardingFuture.java
deleted file mode 100644
index 8111332..0000000
--- a/core/src/main/java/brooklyn/util/task/ListenableForwardingFuture.java
+++ /dev/null
@@ -1,50 +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 brooklyn.util.task;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.Future;
-
-import com.google.common.util.concurrent.ExecutionList;
-import com.google.common.util.concurrent.ForwardingFuture.SimpleForwardingFuture;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/** Wraps a Future, making it a ListenableForwardingFuture, but with the caller having the resposibility to:
- * <li> invoke the listeners on job completion (success or error)
- * <li> invoke the listeners on cancel */
-public abstract class ListenableForwardingFuture<T> extends SimpleForwardingFuture<T> implements ListenableFuture<T> {
-
-    final ExecutionList listeners;
-    
-    protected ListenableForwardingFuture(Future<T> delegate) {
-        super(delegate);
-        this.listeners = new ExecutionList();
-    }
-
-    protected ListenableForwardingFuture(Future<T> delegate, ExecutionList list) {
-        super(delegate);
-        this.listeners = list;
-    }
-
-    @Override
-    public void addListener(Runnable listener, Executor executor) {
-        listeners.add(listener, executor);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ParallelTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ParallelTask.java b/core/src/main/java/brooklyn/util/task/ParallelTask.java
deleted file mode 100644
index d6e65ab..0000000
--- a/core/src/main/java/brooklyn/util/task/ParallelTask.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 brooklyn.util.task;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
-import org.apache.brooklyn.api.management.Task;
-
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.text.Strings;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
-/**
- * Runs {@link Task}s in parallel.
- *
- * No guarantees of order of starting the tasks, but the return value is a
- * {@link List} of the return values of supplied tasks in the same
- * order they were passed as arguments.
- */
-public class ParallelTask<T> extends CompoundTask<T> {
-    public ParallelTask(Object... tasks) { super(tasks); }
-    
-    public ParallelTask(Map<String,?> flags, Collection<? extends Object> tasks) { super(flags, tasks); }
-    public ParallelTask(Collection<? extends Object> tasks) { super(tasks); }
-    
-    public ParallelTask(Map<String,?> flags, Iterable<? extends Object> tasks) { super(flags, ImmutableList.copyOf(tasks)); }
-    public ParallelTask(Iterable<? extends Object> tasks) { super(ImmutableList.copyOf(tasks)); }
-
-    @Override
-    protected List<T> runJobs() throws InterruptedException, ExecutionException {
-        setBlockingDetails("Executing "+
-                (children.size()==1 ? "1 child task" :
-                children.size()+" children tasks in parallel") );
-        for (Task<? extends T> task : children) {
-            submitIfNecessary(task);
-        }
-
-        List<T> result = Lists.newArrayList();
-        List<Exception> exceptions = Lists.newArrayList();
-        for (Task<? extends T> task : children) {
-            T x;
-            try {
-                x = task.get();
-            } catch (Exception e) {
-                Exceptions.propagateIfFatal(e);
-                if (TaskTags.isInessential(task)) {
-                    // ignore exception as it's inessential
-                } else {
-                    exceptions.add(e);
-                }
-                x = null;
-            }
-            result.add(x);
-        }
-        
-        if (exceptions.isEmpty()) {
-            return result;
-        } else {
-            if (result.size()==1 && exceptions.size()==1)
-                throw Exceptions.propagate( exceptions.get(0) );
-            throw Exceptions.propagate(exceptions.size()+" of "+result.size()+" parallel child task"+Strings.s(result.size())+" failed", exceptions);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/ScheduledTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/ScheduledTask.java b/core/src/main/java/brooklyn/util/task/ScheduledTask.java
deleted file mode 100644
index eabff49..0000000
--- a/core/src/main/java/brooklyn/util/task/ScheduledTask.java
+++ /dev/null
@@ -1,185 +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 brooklyn.util.task;
-
-import static brooklyn.util.GroovyJavaMethods.elvis;
-import static brooklyn.util.GroovyJavaMethods.truth;
-
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.management.Task;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.time.Duration;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Throwables;
-
-/**
- * A task which runs with a fixed period.
- * <p>
- * Note that some termination logic, including {@link #addListener(Runnable, java.util.concurrent.Executor)},
- * is not precisely defined. 
- */
-// TODO ScheduledTask is a very pragmatic implementation; would be nice to tighten, 
-// reduce external assumptions about internal structure, and clarify "done" semantics
-public class ScheduledTask extends BasicTask {
-    
-    final Callable<Task<?>> taskFactory;
-    /** initial delay before running, set as flag in constructor; defaults to 0 */
-    protected Duration delay;
-    /** time to wait between executions, or null if not to repeat (default), set as flag to constructor;
-     * this may be modified for subsequent submissions by a running task generated by the factory 
-     * using getSubmittedByTask().setPeriod(Duration) */
-    protected Duration period = null;
-    /** optional, set as flag in constructor; defaults to null meaning no limit */
-    protected Integer maxIterations = null;
-    
-    protected int runCount=0;
-    protected Task<?> recentRun, nextRun;
-
-    public int getRunCount() { return runCount; }
-    public ScheduledFuture<?> getNextScheduled() { return (ScheduledFuture<?>)internalFuture; }
-
-    public ScheduledTask(Callable<Task<?>> taskFactory) {
-        this(MutableMap.of(), taskFactory);
-    }
-
-    public ScheduledTask(final Task<?> task) {
-        this(MutableMap.of(), task);
-    }
-
-    public ScheduledTask(Map flags, final Task<?> task){
-        this(flags, new Callable<Task<?>>(){
-            @Override
-            public Task<?> call() throws Exception {
-                return task;
-            }});
-    }
-
-    public ScheduledTask(Map flags, Callable<Task<?>> taskFactory) {
-        super(flags);
-        this.taskFactory = taskFactory;
-        
-        delay = Duration.of(elvis(flags.remove("delay"), 0));
-        period = Duration.of(elvis(flags.remove("period"), null));
-        maxIterations = elvis(flags.remove("maxIterations"), null);
-    }
-    
-    public ScheduledTask delay(Duration d) {
-        this.delay = d;
-        return this;
-    }
-    public ScheduledTask delay(long val) {
-        return delay(Duration.millis(val));
-    }
-
-    public ScheduledTask period(Duration d) {
-        this.period = d;
-        return this;
-    }
-    public ScheduledTask period(long val) {
-        return period(Duration.millis(val));
-    }
-
-    public ScheduledTask maxIterations(int val) {
-        this.maxIterations = val;
-        return this;
-    }
-
-    public Callable<Task<?>> getTaskFactory() {
-        return taskFactory;
-    }
-
-    public Task<?> newTask() {
-        try {
-            return taskFactory.call();
-        } catch (Exception e) {
-            throw Throwables.propagate(e);
-        }
-    }
-    
-    protected String getActiveTaskStatusString(int verbosity) {
-        StringBuilder rv = new StringBuilder("Scheduler");
-        if (runCount>0) rv.append(", iteration "+(runCount+1));
-        if (recentRun!=null) rv.append(", last run "+
-            Duration.sinceUtc(recentRun.getStartTimeUtc())+" ms ago");
-        if (truth(getNextScheduled())) {
-            Duration untilNext = Duration.millis(getNextScheduled().getDelay(TimeUnit.MILLISECONDS));
-            if (untilNext.isPositive())
-                rv.append(", next in "+untilNext);
-            else 
-                rv.append(", next imminent");
-        }
-        return rv.toString();
-    }
-    
-    @Override
-    public boolean isDone() {
-        return isCancelled() || (maxIterations!=null && maxIterations <= runCount) || (period==null && nextRun!=null && nextRun.isDone());
-    }
-    
-    public synchronized void blockUntilFirstScheduleStarted() {
-        // TODO Assumes that maxIterations is not negative!
-        while (true) {
-            if (isCancelled()) throw new CancellationException();
-            if (recentRun==null)
-                try {
-                    wait();
-                } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
-                    Throwables.propagate(e);
-                }
-            if (recentRun!=null) return;
-        }
-    }
-    
-    public void blockUntilEnded() {
-        while (!isDone()) super.blockUntilEnded();
-    }
-
-    /** gets the value of the most recently run task */
-    public Object get() throws InterruptedException, ExecutionException {
-        blockUntilStarted();
-        blockUntilFirstScheduleStarted();
-        return (truth(recentRun)) ? recentRun.get() : internalFuture.get();
-    }
-    
-    @Override
-    public synchronized boolean cancel(boolean mayInterrupt) {
-        boolean result = super.cancel(mayInterrupt);
-        if (nextRun!=null) {
-            nextRun.cancel(mayInterrupt);
-            notifyAll();
-        }
-        return result;
-    }
-    
-    /** internal method used to allow callers to wait for underlying tasks to finished in the case of cancellation 
-     * @param duration */ 
-    @Beta
-    public boolean blockUntilNextRunFinished(Duration timeout) {
-        return Tasks.blockUntilInternalTasksEnded(nextRun, timeout);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/SequentialTask.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/SequentialTask.java b/core/src/main/java/brooklyn/util/task/SequentialTask.java
deleted file mode 100644
index e739eb0..0000000
--- a/core/src/main/java/brooklyn/util/task/SequentialTask.java
+++ /dev/null
@@ -1,58 +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 brooklyn.util.task;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
-import org.apache.brooklyn.api.management.Task;
-
-import com.google.common.collect.ImmutableList;
-
-
-/** runs tasks in order, waiting for one to finish before starting the next; return value here is TBD;
- * (currently is all the return values of individual tasks, but we
- * might want some pipeline support and eventually only to return final value...) */
-public class SequentialTask<T> extends CompoundTask<T> {
-
-    public SequentialTask(Object... tasks) { super(tasks); }
-    
-    public SequentialTask(Map<String,?> flags, Collection<? extends Object> tasks) { super(flags, tasks); }
-    public SequentialTask(Collection<? extends Object> tasks) { super(tasks); }
-    
-    public SequentialTask(Map<String,?> flags, Iterable<? extends Object> tasks) { super(flags, ImmutableList.copyOf(tasks)); }
-    public SequentialTask(Iterable<? extends Object> tasks) { super(ImmutableList.copyOf(tasks)); }
-    
-    protected List<T> runJobs() throws InterruptedException, ExecutionException {
-        setBlockingDetails("Executing "+
-                (children.size()==1 ? "1 child task" :
-                children.size()+" children tasks sequentially") );
-
-        List<T> result = new ArrayList<T>();
-        for (Task<? extends T> task : children) {
-            submitIfNecessary(task);
-            // throw exception (and cancel subsequent tasks) on error
-            result.add(task.get());
-        }
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java b/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
deleted file mode 100644
index a48bac8..0000000
--- a/core/src/main/java/brooklyn/util/task/SingleThreadedScheduler.java
+++ /dev/null
@@ -1,216 +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 brooklyn.util.task;
-
-import java.util.Queue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.brooklyn.api.management.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Instances of this class ensures that {@link Task}s execute with in-order
- * single-threaded semantics.
- *
- * Tasks can be presented through {@link #submit(Callable)}. The order of execution is the
- * sumbission order.
- * <p>
- * This implementation does so by blocking on a {@link ConcurrentLinkedQueue}, <em>after</em>
- * the task is started in a thread (and {@link Task#isBegun()} returns true), but (of course)
- * <em>before</em> the {@link TaskInternal#getJob()} actually gets invoked.
- */
-public class SingleThreadedScheduler implements TaskScheduler, CanSetName {
-    private static final Logger LOG = LoggerFactory.getLogger(SingleThreadedScheduler.class);
-    
-    private final Queue<QueuedSubmission<?>> order = new ConcurrentLinkedQueue<QueuedSubmission<?>>();
-    private int queueSize = 0;
-    private final AtomicBoolean running = new AtomicBoolean(false);
-    
-    private ExecutorService executor;
-
-    private String name;
-    
-    @Override
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    @Override
-    public String toString() {
-        return name!=null ? "SingleThreadedScheduler["+name+"]" : super.toString();
-    }
-    
-    @Override
-    public void injectExecutor(ExecutorService executor) {
-        this.executor = executor;
-    }
-
-    @Override
-    public synchronized <T> Future<T> submit(Callable<T> c) {
-        if (running.compareAndSet(false, true)) {
-            return executeNow(c);
-        } else {
-            WrappingFuture<T> f = new WrappingFuture<T>();
-            order.add(new QueuedSubmission<T>(c, f));
-            queueSize++;
-            if (queueSize>0 && (queueSize == 50 || (queueSize<=500 && (queueSize%100)==0) || (queueSize%1000)==0) && queueSize!=lastSizeWarn) {
-                LOG.warn("{} is backing up, {} tasks queued", this, queueSize);
-                if (LOG.isDebugEnabled()) {
-                    LOG.debug("Task queue backing up detail, queue "+this+"; task context is "+Tasks.current()+"; latest task is "+c+"; first task is "+order.peek());
-                }
-                lastSizeWarn = queueSize;
-            }
-            return f;
-        }
-    }
-    int lastSizeWarn = 0;
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    private synchronized void onEnd() {
-        boolean done = false;
-        while (!done) {
-            if (order.isEmpty()) {
-                running.set(false);
-                done = true;
-            } else {
-                QueuedSubmission<?> qs = order.remove();
-                queueSize--;
-                if (!qs.f.isCancelled()) {
-                    Future future = executeNow(qs.c);
-                    qs.f.setDelegate(future);
-                    done = true;
-                }
-            }
-        }
-    }
-
-    private synchronized <T> Future<T> executeNow(final Callable<T> c) {
-        return executor.submit(new Callable<T>() {
-            @Override public T call() throws Exception {
-                try {
-                    return c.call();
-                } finally {
-                    onEnd();
-                }
-            }});
-    }
-    
-    
-    private static class QueuedSubmission<T> {
-        final Callable<T> c;
-        final WrappingFuture<T> f;
-        
-        QueuedSubmission(Callable<T> c, WrappingFuture<T> f) {
-            this.c = c;
-            this.f = f;
-        }
-        
-        @Override
-        public String toString() {
-            return "QueuedSubmission["+c+"]@"+Integer.toHexString(System.identityHashCode(this));
-        }
-    }
-    
-    /**
-     * A future, where the task may not yet have been submitted to the real executor.
-     * It delegates to the real future if present, and otherwise waits for that to appear
-     */
-    private static class WrappingFuture<T> implements Future<T> {
-        private volatile Future<T> delegate;
-        private boolean cancelled;
-        
-        void setDelegate(Future<T> delegate) {
-            synchronized (this) {
-                this.delegate = delegate;
-                notifyAll();
-            }
-        }
-        
-        @Override public boolean cancel(boolean mayInterruptIfRunning) {
-            if (delegate != null) {
-                return delegate.cancel(mayInterruptIfRunning);
-            } else {
-                cancelled = true;
-                synchronized (this) {
-                    notifyAll();
-                }
-                return true;
-            }
-        }
-        
-        @Override public boolean isCancelled() {
-            if (delegate != null) {
-                return delegate.isCancelled();
-            } else {
-                return cancelled;
-            }
-        }
-        
-        @Override public boolean isDone() {
-            return (delegate != null) ? delegate.isDone() : cancelled;
-        }
-        
-        @Override public T get() throws CancellationException, ExecutionException, InterruptedException {
-            if (cancelled) {
-                throw new CancellationException();
-            } else if (delegate != null) {
-                return delegate.get();
-            } else {
-                synchronized (this) {
-                    while (delegate == null && !cancelled) {
-                        wait();
-                    }
-                }
-                return get();
-            }
-        }
-        
-        @Override public T get(long timeout, TimeUnit unit) throws CancellationException, ExecutionException, InterruptedException, TimeoutException {
-            long endtime = System.currentTimeMillis()+unit.toMillis(timeout);
-            
-            if (cancelled) {
-                throw new CancellationException();
-            } else if (delegate != null) {
-                return delegate.get(timeout, unit);
-            } else if (System.currentTimeMillis() >= endtime) {
-                throw new TimeoutException();
-            } else {
-                synchronized (this) {
-                    while (delegate == null && !cancelled && System.currentTimeMillis() < endtime) {
-                        long remaining = endtime - System.currentTimeMillis();
-                        if (remaining > 0) {
-                            wait(remaining);
-                        }
-                    }
-                }
-                long remaining = endtime - System.currentTimeMillis();
-                return get(remaining, TimeUnit.MILLISECONDS);
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/TaskBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/TaskBuilder.java b/core/src/main/java/brooklyn/util/task/TaskBuilder.java
deleted file mode 100644
index ecd4d4f..0000000
--- a/core/src/main/java/brooklyn/util/task/TaskBuilder.java
+++ /dev/null
@@ -1,184 +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 brooklyn.util.task;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskAdaptable;
-import org.apache.brooklyn.api.management.TaskFactory;
-import org.apache.brooklyn.api.management.TaskQueueingContext;
-
-import brooklyn.util.JavaGroovyEquivalents;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.collections.MutableSet;
-
-import com.google.common.collect.Iterables;
-
-/** Convenience for creating tasks; note that DynamicSequentialTask is the default */
-public class TaskBuilder<T> {
-
-    String name = null;
-    String description = null;
-    Callable<T> body = null;
-    Boolean swallowChildrenFailures = null;
-    List<TaskAdaptable<?>> children = MutableList.of();
-    Set<Object> tags = MutableSet.of();
-    Map<String,Object> flags = MutableMap.of();
-    Boolean dynamic = null;
-    boolean parallel = false;
-    
-    public static <T> TaskBuilder<T> builder() {
-        return new TaskBuilder<T>();
-    }
-    
-    public TaskBuilder<T> name(String name) {
-        this.name = name;
-        return this;
-    }
-    
-    public TaskBuilder<T> description(String description) {
-        this.description = description;
-        return this;
-    }
-    
-    /** whether task that is built has been explicitly specified to be a dynamic task 
-     * (ie a Task which is also a {@link TaskQueueingContext}
-     * whereby new tasks can be added after creation */
-    public TaskBuilder<T> dynamic(boolean dynamic) {
-        this.dynamic = dynamic;
-        return this;
-    }
-    
-    /** whether task that is built should be parallel; cannot (currently) also be dynamic */
-    public TaskBuilder<T> parallel(boolean parallel) {
-        this.parallel = parallel;
-        return this;
-    }
-    
-    public TaskBuilder<T> body(Callable<T> body) {
-        this.body = body;
-        return this;
-    }
-    
-    /** sets up a dynamic task not to fail even if children fail */
-    public TaskBuilder<T> swallowChildrenFailures(boolean swallowChildrenFailures) {
-        this.swallowChildrenFailures = swallowChildrenFailures;
-        return this;
-    }
-    
-    public TaskBuilder<T> body(Runnable body) {
-        this.body = JavaGroovyEquivalents.<T>toCallable(body);
-        return this;
-    }
-
-    /** adds a child to the given task; the semantics of how the child is executed is set using
-     * {@link #dynamic(boolean)} and {@link #parallel(boolean)} */
-    public TaskBuilder<T> add(TaskAdaptable<?> child) {
-        children.add(child);
-        return this;
-    }
-
-    public TaskBuilder<T> addAll(Iterable<? extends TaskAdaptable<?>> additionalChildren) {
-        Iterables.addAll(children, additionalChildren);
-        return this;
-    }
-
-    public TaskBuilder<T> add(TaskAdaptable<?>... additionalChildren) {
-        children.addAll(Arrays.asList(additionalChildren));
-        return this;
-    }
-
-    /** adds a tag to the given task */
-    public TaskBuilder<T> tag(Object tag) {
-        tags.add(tag);
-        return this;
-    }
-    
-    /** adds a flag to the given task */
-    public TaskBuilder<T> flag(String flag, Object value) {
-        flags.put(flag, value);
-        return this;
-    }
-
-    /** adds the given flags to the given task */
-    public TaskBuilder<T> flags(Map<String,Object> flags) {
-        this.flags.putAll(flags);
-        return this;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public Task<T> build() {
-        MutableMap<String, Object> taskFlags = MutableMap.copyOf(flags);
-        if (name!=null) taskFlags.put("displayName", name);
-        if (description!=null) taskFlags.put("description", description);
-        if (!tags.isEmpty()) taskFlags.put("tags", tags);
-        
-        if (Boolean.FALSE.equals(dynamic) && children.isEmpty()) {
-            if (swallowChildrenFailures!=null)
-                throw new IllegalArgumentException("Cannot set swallowChildrenFailures for non-dynamic task: "+this);
-            return new BasicTask<T>(taskFlags, body);
-        }
-        
-        // prefer dynamic set unless (a) user has said not dynamic, or (b) it's parallel (since there is no dynamic parallel yet)
-        // dynamic has better cancel (will interrupt the thread) and callers can submit tasks flexibly;
-        // however dynamic uses an extra thread and task and is noisy for contexts which don't need it
-        if (Boolean.TRUE.equals(dynamic) || (dynamic==null && !parallel)) {
-            if (parallel)
-                throw new UnsupportedOperationException("No implementation of parallel dynamic aggregate task available");
-            DynamicSequentialTask<T> result = new DynamicSequentialTask<T>(taskFlags, body);
-            if (swallowChildrenFailures!=null && swallowChildrenFailures.booleanValue()) result.swallowChildrenFailures();
-            for (TaskAdaptable t: children)
-                result.queue(t.asTask());
-            return result;
-        }
-        
-        // T must be of type List<V> for these to be valid
-        if (body != null) {
-            throw new UnsupportedOperationException("No implementation of non-dynamic task with both body and children");
-        }
-        if (swallowChildrenFailures!=null) {
-            throw new IllegalArgumentException("Cannot set swallowChildrenFailures for non-dynamic task: "+this);
-        }
-        
-        if (parallel)
-            return new ParallelTask(taskFlags, children);
-        else
-            return new SequentialTask(taskFlags, children);
-    }
-
-    /** returns a a factory based on this builder */
-    public TaskFactory<Task<T>> buildFactory() {
-        return new TaskFactory<Task<T>>() {
-            public Task<T> newTask() {
-                return build();
-            }
-        };
-    }
-    
-    @Override
-    public String toString() {
-        return super.toString()+"["+name+"]";
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/TaskInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/TaskInternal.java b/core/src/main/java/brooklyn/util/task/TaskInternal.java
deleted file mode 100644
index 51dbddb..0000000
--- a/core/src/main/java/brooklyn/util/task/TaskInternal.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 brooklyn.util.task;
-
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-
-import org.apache.brooklyn.api.management.ExecutionManager;
-import org.apache.brooklyn.api.management.Task;
-
-import brooklyn.util.time.Duration;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.util.concurrent.ExecutionList;
-import com.google.common.util.concurrent.ListenableFuture;
-
-/**
- * All tasks being passed to the {@link ExecutionManager} should implement this.
- * Users are strongly encouraged to use (or extend) {@link BasicTask}, rather than
- * implementing a task from scratch.
- * 
- * The methods on this interface will change in subsequent releases. Because this is
- * marked as beta, the normal deprecation policy for these methods does not apply.
- * 
- * @author aled
- */
-@Beta
-public interface TaskInternal<T> extends Task<T> {
-    
-    /** sets the internal future object used to record the association to a job submitted to an {@link ExecutorService} */
-    void initInternalFuture(ListenableFuture<T> result);
-
-    /** returns the underlying future where this task's results will come in; see {@link #initInternalFuture(ListenableFuture)} */
-    Future<T> getInternalFuture();
-    
-    /** if the job is queued for submission (e.g. by another task) it can indicate that fact (and time) here;
-     * note tasks can (and often are) submitted without any queueing, in which case this value may be -1 */
-    long getQueuedTimeUtc();
-    
-    boolean isQueuedOrSubmitted();
-    boolean isQueuedAndNotSubmitted();
-    boolean isQueued();
-
-    /** marks the task as queued for execution */
-    void markQueued();
-
-    boolean cancel();
-    
-    boolean blockUntilStarted(Duration timeout);
-
-    /** allows a task user to specify why a task is blocked; for use immediately before a blocking/wait,
-     * and typically cleared immediately afterwards; referenced by management api to inspect a task
-     * which is blocking
-     * <p>
-     * returns previous details, in case caller wishes to recall and restore it (e.g. if it is doing a sub-blocking)
-     */
-    String setBlockingDetails(String blockingDetails);
-
-    /** as {@link #setBlockingDetails(String)} but records a task which is blocking,
-     * for use e.g. in a gui to navigate to the current active subtask
-     * <p>
-     * returns previous blocking task, in case caller wishes to recall and restore it
-     */
-    Task<?> setBlockingTask(Task<?> blockingTask);
-    
-    void resetBlockingDetails();
-    
-    void resetBlockingTask();
-
-    /** returns a textual message giving details while the task is blocked */
-    String getBlockingDetails();
-    
-    /** returns a task that this task is blocked on */
-    Task<?> getBlockingTask();
-    
-    void setExtraStatusText(Object extraStatus);
-    
-    Object getExtraStatusText();
-
-    void runListeners();
-
-    void setEndTimeUtc(long val);
-
-    void setThread(Thread thread);
-
-    Callable<T> getJob();
-    
-    void setJob(Callable<T> job);
-
-    ExecutionList getListeners();
-
-    void setSubmitTimeUtc(long currentTimeMillis);
-
-    void setSubmittedByTask(Task<?> task);
-    
-    Set<Object> getMutableTags();
-
-    void setStartTimeUtc(long currentTimeMillis);
-
-    void applyTagModifier(Function<Set<Object>,Void> modifier);
-    
-    /** if a task is a proxy for another one (used mainly for internal tasks),
-     * this returns the "real" task represented by this one */
-    Task<?> getProxyTarget();
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/TaskScheduler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/TaskScheduler.java b/core/src/main/java/brooklyn/util/task/TaskScheduler.java
deleted file mode 100644
index a10e63a..0000000
--- a/core/src/main/java/brooklyn/util/task/TaskScheduler.java
+++ /dev/null
@@ -1,41 +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 brooklyn.util.task;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-
-import org.apache.brooklyn.api.management.Task;
-
-/**
- * The scheduler is an internal mechanism to decorate {@link Task}s.
- *
- * It can control how the tasks are scheduled for execution (e.g. single-threaded execution,
- * prioritised, etc).
- */
-public interface TaskScheduler {
-    
-    public void injectExecutor(ExecutorService executor);
-
-    /**
-     * Called by {@link BasicExecutionManager} to schedule tasks.
-     */
-    public <T> Future<T> submit(Callable<T> c);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/TaskTags.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/TaskTags.java b/core/src/main/java/brooklyn/util/task/TaskTags.java
deleted file mode 100644
index a9da252..0000000
--- a/core/src/main/java/brooklyn/util/task/TaskTags.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 brooklyn.util.task;
-
-import java.util.Set;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskAdaptable;
-
-import com.google.common.base.Function;
-
-public class TaskTags {
-
-    /** marks a task which is allowed to fail without failing his parent */
-    public static final String INESSENTIAL_TASK = "inessential";
-
-    /** marks a task which is a subtask of another */
-    public static final String SUB_TASK_TAG = "SUB-TASK";
-
-    public static void addTagDynamically(TaskAdaptable<?> task, final Object tag) {
-        ((BasicTask<?>)task.asTask()).applyTagModifier(new Function<Set<Object>, Void>() {
-            public Void apply(@Nullable Set<Object> input) {
-                input.add(tag);
-                return null;
-            }
-        });
-    }
-    
-    public static void addTagsDynamically(TaskAdaptable<?> task, final Object tag1, final Object ...tags) {
-        ((BasicTask<?>)task.asTask()).applyTagModifier(new Function<Set<Object>, Void>() {
-            public Void apply(@Nullable Set<Object> input) {
-                input.add(tag1);
-                for (Object tag: tags) input.add(tag);
-                return null;
-            }
-        });
-    }
-
-    
-    public static boolean isInessential(Task<?> task) {
-        return hasTag(task, INESSENTIAL_TASK);
-    }
-
-    public static boolean hasTag(Task<?> task, Object tag) {
-        return task.getTags().contains(tag);
-    }
-    
-    public static <U,V extends TaskAdaptable<U>> V markInessential(V task) {
-        addTagDynamically(task, INESSENTIAL_TASK);
-        return task;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/Tasks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/Tasks.java b/core/src/main/java/brooklyn/util/task/Tasks.java
deleted file mode 100644
index c25dd19..0000000
--- a/core/src/main/java/brooklyn/util/task/Tasks.java
+++ /dev/null
@@ -1,488 +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 brooklyn.util.task;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.management.ExecutionContext;
-import org.apache.brooklyn.api.management.HasTaskChildren;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskAdaptable;
-import org.apache.brooklyn.api.management.TaskFactory;
-import org.apache.brooklyn.api.management.TaskQueueingContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.exceptions.ReferenceWithError;
-import brooklyn.util.repeat.Repeater;
-import brooklyn.util.time.CountdownTimer;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.common.collect.Iterables;
-
-public class Tasks {
-    
-    private static final Logger log = LoggerFactory.getLogger(Tasks.class);
-    
-    /** convenience for setting "blocking details" on any task where the current thread is running;
-     * typically invoked prior to a wait, for transparency to a user;
-     * then invoked with 'null' just after the wait */
-    public static String setBlockingDetails(String description) {
-        Task<?> current = current();
-        if (current instanceof TaskInternal)
-            return ((TaskInternal<?>)current).setBlockingDetails(description);
-        return null;
-    }
-    public static void resetBlockingDetails() {
-        Task<?> current = current();
-        if (current instanceof TaskInternal)
-            ((TaskInternal<?>)current).resetBlockingDetails(); 
-    }
-    public static Task<?> setBlockingTask(Task<?> blocker) {
-        Task<?> current = current();
-        if (current instanceof TaskInternal)
-            return ((TaskInternal<?>)current).setBlockingTask(blocker);
-        return null;
-    }
-    public static void resetBlockingTask() {
-        Task<?> current = current();
-        if (current instanceof TaskInternal)
-            ((TaskInternal<?>)current).resetBlockingTask(); 
-    }
-    
-    /** convenience for setting "blocking details" on any task where the current thread is running,
-     * while the passed code is executed; often used from groovy as
-     * <pre>{@code withBlockingDetails("sleeping 5s") { Thread.sleep(5000); } }</pre>
-     * If code block is null, the description is set until further notice (not cleareed). */
-    @SuppressWarnings("rawtypes")
-    public static <T> T withBlockingDetails(String description, Callable<T> code) throws Exception {
-        Task current = current();
-        if (code==null) {
-            log.warn("legacy invocation of withBlockingDetails with null code block, ignoring");
-            return null;
-        }
-        String prevBlockingDetails = null;
-        if (current instanceof TaskInternal) {
-            prevBlockingDetails = ((TaskInternal)current).setBlockingDetails(description);
-        } 
-        try {
-            return code.call();
-        } finally {
-            if (current instanceof TaskInternal)
-                ((TaskInternal)current).setBlockingDetails(prevBlockingDetails); 
-        }
-    }
-
-    /** the {@link Task} where the current thread is executing, if executing in a Task, otherwise null;
-     * if the current task is a proxy, this returns the target of that proxy */
-    @SuppressWarnings("rawtypes")
-    public static Task current() { 
-        return getFinalProxyTarget(BasicExecutionManager.getPerThreadCurrentTask().get());
-    }
-
-    public static Task<?> getFinalProxyTarget(Task<?> task) {
-        if (task==null) return null;
-        Task<?> proxy = ((TaskInternal<?>)task).getProxyTarget();
-        if (proxy==null || proxy.equals(task)) return task;
-        return getFinalProxyTarget(proxy);
-    }
-    
-    /** creates a {@link ValueResolver} instance which allows significantly more customization than
-     * the various {@link #resolveValue(Object, Class, ExecutionContext)} methods here */
-    public static <T> ValueResolver<T> resolving(Object v, Class<T> type) {
-        return new ValueResolver<T>(v, type);
-    }
-
-    public static ValueResolver.ResolverBuilderPretype resolving(Object v) {
-        return new ValueResolver.ResolverBuilderPretype(v);
-    }
-
-    /** @see #resolveValue(Object, Class, ExecutionContext, String) */
-    public static <T> T resolveValue(Object v, Class<T> type, @Nullable ExecutionContext exec) throws ExecutionException, InterruptedException {
-        return new ValueResolver<T>(v, type).context(exec).get();
-    }
-    
-    /** attempt to resolve the given value as the given type, waiting on futures, submitting if necessary,
-     * and coercing as allowed by TypeCoercions;
-     * contextMessage (optional) will be displayed in status reports while it waits (e.g. the name of the config key being looked up).
-     * if no execution context supplied (null) this method will throw an exception if the object is an unsubmitted task */
-    public static <T> T resolveValue(Object v, Class<T> type, @Nullable ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException {
-        return new ValueResolver<T>(v, type).context(exec).description(contextMessage).get();
-    }
-    
-    /**
-     * @see #resolveDeepValue(Object, Class, ExecutionContext, String)
-     */
-    public static Object resolveDeepValue(Object v, Class<?> type, ExecutionContext exec) throws ExecutionException, InterruptedException {
-        return resolveDeepValue(v, type, exec, null);
-    }
-
-    /**
-     * Resolves the given object, blocking on futures and coercing it to the given type. If the object is a 
-     * map or iterable (or a list of map of maps, etc, etc) then walks these maps/iterables to convert all of 
-     * their values to the given type. For example, the following will return a list containing a map with "1"="true":
-     * 
-     *   {@code Object result = resolveDeepValue(ImmutableList.of(ImmutableMap.of(1, true)), String.class, exec)} 
-     *
-     * To perform a deep conversion of futures contained within Iterables or Maps without coercion of each element,
-     * the type should normally be Object, not the type of the collection. This differs from
-     * {@link #resolveValue(Object, Class, ExecutionContext, String)} which will accept Map and Iterable
-     * as the required type.
-     */
-    public static <T> T resolveDeepValue(Object v, Class<T> type, ExecutionContext exec, String contextMessage) throws ExecutionException, InterruptedException {
-        return new ValueResolver<T>(v, type).context(exec).deep(true).description(contextMessage).get();
-    }
-
-    /** sets extra status details on the current task, if possible (otherwise does nothing).
-     * the extra status is presented in Task.getStatusDetails(true)
-     */
-    public static void setExtraStatusDetails(String notes) {
-        Task<?> current = current();
-        if (current instanceof TaskInternal)
-            ((TaskInternal<?>)current).setExtraStatusText(notes); 
-    }
-
-    public static <T> TaskBuilder<T> builder() {
-        return TaskBuilder.<T>builder();
-    }
-    
-    private static Task<?>[] asTasks(TaskAdaptable<?> ...tasks) {
-        Task<?>[] result = new Task<?>[tasks.length];
-        for (int i=0; i<tasks.length; i++)
-            result[i] = tasks[i].asTask();
-        return result;
-    }
-
-    public static Task<List<?>> parallel(TaskAdaptable<?> ...tasks) {
-        return parallelInternal("parallelised tasks", asTasks(tasks));
-    }
-    public static Task<List<?>> parallel(String name, TaskAdaptable<?> ...tasks) {
-        return parallelInternal(name, asTasks(tasks));
-    }
-    public static Task<List<?>> parallel(Iterable<? extends TaskAdaptable<?>> tasks) {
-        return parallel(asTasks(Iterables.toArray(tasks, TaskAdaptable.class)));
-    }
-    public static Task<List<?>> parallel(String name, Iterable<? extends TaskAdaptable<?>> tasks) {
-        return parallelInternal(name, asTasks(Iterables.toArray(tasks, TaskAdaptable.class)));
-    }
-    private static Task<List<?>> parallelInternal(String name, Task<?>[] tasks) {
-        return Tasks.<List<?>>builder().name(name).parallel(true).add(tasks).build();
-    }
-
-    public static Task<List<?>> sequential(TaskAdaptable<?> ...tasks) {
-        return sequentialInternal("sequential tasks", asTasks(tasks));
-    }
-    public static Task<List<?>> sequential(String name, TaskAdaptable<?> ...tasks) {
-        return sequentialInternal(name, asTasks(tasks));
-    }
-    public static TaskFactory<?> sequential(TaskFactory<?> ...taskFactories) {
-        return sequentialInternal("sequential tasks", taskFactories);
-    }
-    public static TaskFactory<?> sequential(String name, TaskFactory<?> ...taskFactories) {
-        return sequentialInternal(name, taskFactories);
-    }
-    public static Task<List<?>> sequential(List<? extends TaskAdaptable<?>> tasks) {
-        return sequential(asTasks(Iterables.toArray(tasks, TaskAdaptable.class)));
-    }
-    public static Task<List<?>> sequential(String name, List<? extends TaskAdaptable<?>> tasks) {
-        return sequential(name, asTasks(Iterables.toArray(tasks, TaskAdaptable.class)));
-    }
-    private static Task<List<?>> sequentialInternal(String name, Task<?>[] tasks) {
-        return Tasks.<List<?>>builder().name(name).parallel(false).add(tasks).build();
-    }
-    private static TaskFactory<?> sequentialInternal(final String name, final TaskFactory<?> ...taskFactories) {
-        return new TaskFactory<TaskAdaptable<?>>() {
-            @Override
-            public TaskAdaptable<?> newTask() {
-                TaskBuilder<List<?>> tb = Tasks.<List<?>>builder().name(name).parallel(false);
-                for (TaskFactory<?> tf: taskFactories)
-                    tb.add(tf.newTask().asTask());
-                return tb.build();
-            }
-        };
-    }
-
-    /** returns the first tag found on the given task which matches the given type, looking up the submission hierarachy if necessary */
-    @SuppressWarnings("unchecked")
-    public static <T> T tag(@Nullable Task<?> task, Class<T> type, boolean recurseHierarchy) {
-        // support null task to make it easier for callers to walk hierarchies
-        if (task==null) return null;
-        for (Object tag: task.getTags())
-            if (type.isInstance(tag)) return (T)tag;
-        if (!recurseHierarchy) return null;
-        return tag(task.getSubmittedByTask(), type, true);
-    }
-    
-    public static boolean isAncestorCancelled(Task<?> t) {
-        if (t==null) return false;
-        if (t.isCancelled()) return true;
-        return isAncestorCancelled(t.getSubmittedByTask());
-    }
-
-    public static boolean isQueued(TaskAdaptable<?> task) {
-        return ((TaskInternal<?>)task.asTask()).isQueued();
-    }
-
-    public static boolean isSubmitted(TaskAdaptable<?> task) {
-        return ((TaskInternal<?>)task.asTask()).isSubmitted();
-    }
-    
-    public static boolean isQueuedOrSubmitted(TaskAdaptable<?> task) {
-        return ((TaskInternal<?>)task.asTask()).isQueuedOrSubmitted();
-    }
-    
-    /**
-     * Adds the given task to the given context. Does not throw an exception if the addition fails.
-     * @return true if the task was added, false otherwise.
-     */
-    public static boolean tryQueueing(TaskQueueingContext adder, TaskAdaptable<?> task) {
-        if (task==null || isQueued(task))
-            return false;
-        try {
-            adder.queue(task.asTask());
-            return true;
-        } catch (Exception e) {
-            if (log.isDebugEnabled())
-                log.debug("Could not add task "+task+" at "+adder+": "+e);
-            return false;
-        }        
-    }
-    
-    /** see also {@link #resolving(Object)} which gives much more control about submission, timeout, etc */
-    public static <T> Supplier<T> supplier(final TaskAdaptable<T> task) {
-        return new Supplier<T>() {
-            @Override
-            public T get() {
-                return task.asTask().getUnchecked();
-            }
-        };
-    }
-    
-    /** return all children tasks of the given tasks, if it has children, else empty list */
-    public static Iterable<Task<?>> children(Task<?> task) {
-        if (task instanceof HasTaskChildren)
-            return ((HasTaskChildren)task).getChildren();
-        return Collections.emptyList();
-    }
-    
-    /** returns failed tasks */
-    public static Iterable<Task<?>> failed(Iterable<Task<?>> subtasks) {
-        return Iterables.filter(subtasks, new Predicate<Task<?>>() {
-            @Override
-            public boolean apply(Task<?> input) {
-                return input.isError();
-            }
-        });
-    }
-    
-    /** returns the task, its children, and all its children, and so on;
-     * @param root task whose descendants should be iterated
-     * @param parentFirst whether to put parents before children or after
-     */
-    public static Iterable<Task<?>> descendants(Task<?> root, final boolean parentFirst) {
-        Iterable<Task<?>> descs = Iterables.concat(Iterables.transform(Tasks.children(root), new Function<Task<?>,Iterable<Task<?>>>() {
-            @Override
-            public Iterable<Task<?>> apply(Task<?> input) {
-                return descendants(input, parentFirst);
-            }
-        }));
-        if (parentFirst) return Iterables.concat(Collections.singleton(root), descs);
-        else return Iterables.concat(descs, Collections.singleton(root));
-    }
-
-    /** returns the error thrown by the task if {@link Task#isError()}, or null if no error or not done */
-    public static Throwable getError(Task<?> t) {
-        if (t==null) return null;
-        if (!t.isDone()) return null;
-        if (t.isCancelled()) return new CancellationException();
-        try {
-            t.get();
-            return null;
-        } catch (Throwable error) {
-            // do not propagate as we are pretty much guaranteed above that it wasn't this
-            // thread which originally threw the error
-            return error;
-        }
-    }
-    public static Task<Void> fail(final String name, final Throwable optionalError) {
-        return Tasks.<Void>builder().dynamic(false).name(name).body(new Runnable() { public void run() { 
-            if (optionalError!=null) throw Exceptions.propagate(optionalError); else throw new RuntimeException("Failed: "+name);
-        } }).build();
-    }
-    public static Task<Void> warning(final String message, final Throwable optionalError) {
-        log.warn(message);
-        return TaskTags.markInessential(fail(message, optionalError));
-    }
-
-    /** marks the current task inessential; this mainly matters if the task is running in a parent
-     * {@link TaskQueueingContext} and we don't want the parent to fail if this task fails
-     * <p>
-     * no-op (silently ignored) if not in a task */
-    public static void markInessential() {
-        Task<?> task = Tasks.current();
-        if (task==null) {
-            TaskQueueingContext qc = DynamicTasks.getTaskQueuingContext();
-            if (qc!=null) task = qc.asTask();
-        }
-        if (task!=null) {
-            TaskTags.markInessential(task);
-        }
-    }
-    
-    /** causes failures in subtasks of the current task not to fail the parent;
-     * no-op if not in a {@link TaskQueueingContext}.
-     * <p>
-     * essentially like a {@link #markInessential()} on all tasks in the current 
-     * {@link TaskQueueingContext}, including tasks queued subsequently */
-    @Beta
-    public static void swallowChildrenFailures() {
-        Preconditions.checkNotNull(DynamicTasks.getTaskQueuingContext(), "Task queueing context required here");
-        TaskQueueingContext qc = DynamicTasks.getTaskQueuingContext();
-        if (qc!=null) {
-            qc.swallowChildrenFailures();
-        }
-    }
-
-    /** as {@link TaskTags#addTagDynamically(TaskAdaptable, Object)} but for current task, skipping if no current task */
-    public static void addTagDynamically(Object tag) {
-        Task<?> t = Tasks.current();
-        if (t!=null) TaskTags.addTagDynamically(t, tag);
-    }
-    
-    /** 
-     * Workaround for limitation described at {@link Task#cancel(boolean)};
-     * internal method used to allow callers to wait for underlying tasks to finished in the case of cancellation.
-     * <p> 
-     * It is irritating that {@link FutureTask} sync's object clears the runner thread, 
-     * so even if {@link BasicTask#getInternalFuture()} is used, there is no means of determining if the underlying object is done.
-     * The {@link Task#getEndTimeUtc()} seems the only way.
-     *  
-     * @return true if tasks ended; false if timed out
-     **/ 
-    @Beta
-    public static boolean blockUntilInternalTasksEnded(Task<?> t, Duration timeout) {
-        CountdownTimer timer = timeout.countdownTimer();
-        
-        if (t==null)
-            return true;
-        
-        if (t instanceof ScheduledTask) {
-            boolean result = ((ScheduledTask)t).blockUntilNextRunFinished(timer.getDurationRemaining());
-            if (!result) return false;
-        }
-
-        t.blockUntilEnded(timer.getDurationRemaining());
-        
-        while (true) {
-            if (t.getEndTimeUtc()>=0) return true;
-            // above should be sufficient; but just in case, trying the below
-            Thread tt = t.getThread();
-            if (t instanceof ScheduledTask) {
-                ((ScheduledTask)t).blockUntilNextRunFinished(timer.getDurationRemaining());
-                return true;
-            } else {
-                if (tt==null || !tt.isAlive()) {
-                    if (!t.isCancelled()) {
-                        // may happen for a cancelled task, interrupted after submit but before start
-                        log.warn("Internal task thread is dead or null ("+tt+") but task not ended: "+t.getEndTimeUtc()+" ("+t+")");
-                    }
-                    return true;
-                }
-            }
-            if (timer.isExpired())
-                return false;
-            Time.sleep(Repeater.DEFAULT_REAL_QUICK_PERIOD);
-        }
-    }
-    
-    /** returns true if either the current thread or the current task is interrupted/cancelled */
-    public static boolean isInterrupted() {
-        if (Thread.currentThread().isInterrupted()) return true;
-        Task<?> t = current();
-        if (t==null) return false;
-        return t.isCancelled();
-    }
-
-    private static class WaitForRepeaterCallable implements Callable<Boolean> {
-        protected Repeater repeater;
-        protected boolean requireTrue;
-
-        public WaitForRepeaterCallable(Repeater repeater, boolean requireTrue) {
-            this.repeater = repeater;
-            this.requireTrue = requireTrue;
-        }
-
-        @Override
-        public Boolean call() {
-            ReferenceWithError<Boolean> result;
-            Tasks.setBlockingDetails(repeater.getDescription());
-            try {
-               result = repeater.runKeepingError();
-            } finally {
-                Tasks.resetBlockingDetails();
-            }
-
-            if (Boolean.TRUE.equals(result.getWithoutError()))
-                return true;
-            if (result.hasError()) 
-                throw Exceptions.propagate(result.getError());
-            if (requireTrue)
-                throw new IllegalStateException("timeout - "+repeater.getDescription());
-            return false;
-        }
-    }
-
-    /** @return a {@link TaskBuilder} which tests whether the repeater terminates with success in its configured timeframe,
-     * returning true or false depending on whether repeater succeed */
-    public static TaskBuilder<Boolean> testing(Repeater repeater) {
-        return Tasks.<Boolean>builder().body(new WaitForRepeaterCallable(repeater, false))
-            .name("waiting for condition")
-            .description("Testing whether " + getTimeoutString(repeater) + ": "+repeater.getDescription());
-    }
-
-    /** @return a {@link TaskBuilder} which requires that the repeater terminate with success in its configured timeframe,
-     * throwing if it does not */
-    public static TaskBuilder<?> requiring(Repeater repeater) {
-        return Tasks.<Boolean>builder().body(new WaitForRepeaterCallable(repeater, true))
-            .name("waiting for condition")
-            .description("Requiring " + getTimeoutString(repeater) + ": " + repeater.getDescription());
-    }
-    
-    private static String getTimeoutString(Repeater repeater) {
-        Duration timeout = repeater.getTimeLimit();
-        if (timeout==null || Duration.PRACTICALLY_FOREVER.equals(timeout))
-            return "eventually";
-        return "in "+timeout;
-    }
-
-}


[51/64] incubator-brooklyn git commit: brooklyn-software-messaging: add org.apache package prefix

Posted by he...@apache.org.
brooklyn-software-messaging: add org.apache package prefix


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

Branch: refs/heads/master
Commit: c14fef53daba011f21f93d85198ca03e1bbb474c
Parents: 5dfe944
Author: Ciprian Ciubotariu <ch...@gmx.net>
Authored: Thu Aug 13 16:34:21 2015 +0300
Committer: Ciprian Ciubotariu <ch...@gmx.net>
Committed: Tue Aug 18 12:33:20 2015 +0300

----------------------------------------------------------------------
 .../brooklyn/demo/KafkaClusterExample.java      |   2 +-
 .../demo/StandaloneQpidBrokerExample.java       |   4 +-
 .../apache/brooklyn/demo/StormSampleApp.java    |   2 +-
 software/messaging/pom.xml                      |  10 +-
 .../entity/messaging/MessageBroker.java         |  34 ---
 .../java/brooklyn/entity/messaging/Queue.java   |  51 ----
 .../java/brooklyn/entity/messaging/Topic.java   |  46 ----
 .../messaging/activemq/ActiveMQBroker.java      |  81 ------
 .../messaging/activemq/ActiveMQBrokerImpl.java  | 124 ---------
 .../messaging/activemq/ActiveMQDestination.java |  24 --
 .../activemq/ActiveMQDestinationImpl.java       |  66 -----
 .../messaging/activemq/ActiveMQDriver.java      |  28 --
 .../messaging/activemq/ActiveMQQueue.java       |  27 --
 .../messaging/activemq/ActiveMQQueueImpl.java   |  69 -----
 .../messaging/activemq/ActiveMQSpecs.java       |  33 ---
 .../messaging/activemq/ActiveMQSshDriver.java   | 145 ----------
 .../messaging/activemq/ActiveMQTopic.java       |  27 --
 .../messaging/activemq/ActiveMQTopicImpl.java   |  50 ----
 .../entity/messaging/amqp/AmqpExchange.java     |  45 ---
 .../entity/messaging/amqp/AmqpServer.java       |  53 ----
 .../entity/messaging/jms/JMSBroker.java         |  58 ----
 .../entity/messaging/jms/JMSBrokerImpl.java     | 168 ------------
 .../entity/messaging/jms/JMSDestination.java    |  29 --
 .../messaging/jms/JMSDestinationImpl.java       |  51 ----
 .../kafka/AbstractfKafkaSshDriver.java          | 133 ---------
 .../brooklyn/entity/messaging/kafka/Kafka.java  |  45 ---
 .../entity/messaging/kafka/KafkaBroker.java     |  85 ------
 .../messaging/kafka/KafkaBrokerDriver.java      |  27 --
 .../entity/messaging/kafka/KafkaBrokerImpl.java | 170 ------------
 .../messaging/kafka/KafkaBrokerSshDriver.java   |  97 -------
 .../entity/messaging/kafka/KafkaCluster.java    |  92 -------
 .../messaging/kafka/KafkaClusterImpl.java       | 206 --------------
 .../entity/messaging/kafka/KafkaZooKeeper.java  |  58 ----
 .../messaging/kafka/KafkaZooKeeperDriver.java   |  28 --
 .../messaging/kafka/KafkaZooKeeperImpl.java     |  47 ----
 .../kafka/KafkaZooKeeperSshDriver.java          |  82 ------
 .../entity/messaging/qpid/QpidBroker.java       |  79 ------
 .../entity/messaging/qpid/QpidBrokerImpl.java   | 147 ----------
 .../entity/messaging/qpid/QpidDestination.java  |  32 ---
 .../messaging/qpid/QpidDestinationImpl.java     | 101 -------
 .../entity/messaging/qpid/QpidDriver.java       |  28 --
 .../entity/messaging/qpid/QpidQueue.java        |  29 --
 .../entity/messaging/qpid/QpidQueueImpl.java    |  66 -----
 .../entity/messaging/qpid/QpidSshDriver.java    | 137 ----------
 .../entity/messaging/qpid/QpidTopic.java        |  27 --
 .../entity/messaging/qpid/QpidTopicImpl.java    |  56 ----
 .../entity/messaging/rabbit/RabbitBroker.java   |  91 -------
 .../messaging/rabbit/RabbitBrokerImpl.java      | 121 ---------
 .../messaging/rabbit/RabbitDestination.java     |  92 -------
 .../entity/messaging/rabbit/RabbitDriver.java   |  32 ---
 .../entity/messaging/rabbit/RabbitQueue.java    |  85 ------
 .../messaging/rabbit/RabbitSshDriver.java       | 208 --------------
 .../brooklyn/entity/messaging/storm/Storm.java  | 105 -------
 .../entity/messaging/storm/StormDeployment.java |  42 ---
 .../messaging/storm/StormDeploymentImpl.java    |  77 ------
 .../entity/messaging/storm/StormDriver.java     |  27 --
 .../entity/messaging/storm/StormImpl.java       | 118 --------
 .../entity/messaging/storm/StormSshDriver.java  | 272 -------------------
 .../entity/zookeeper/AbstractZooKeeperImpl.java | 109 --------
 .../entity/zookeeper/ZooKeeperDriver.java       |  27 --
 .../entity/zookeeper/ZooKeeperEnsemble.java     |  53 ----
 .../entity/zookeeper/ZooKeeperEnsembleImpl.java | 105 -------
 .../entity/zookeeper/ZooKeeperNode.java         |  67 -----
 .../entity/zookeeper/ZooKeeperNodeImpl.java     |  33 ---
 .../entity/zookeeper/ZooKeeperSshDriver.java    | 163 -----------
 .../entity/messaging/MessageBroker.java         |  34 +++
 .../apache/brooklyn/entity/messaging/Queue.java |  51 ++++
 .../apache/brooklyn/entity/messaging/Topic.java |  46 ++++
 .../messaging/activemq/ActiveMQBroker.java      |  81 ++++++
 .../messaging/activemq/ActiveMQBrokerImpl.java  | 124 +++++++++
 .../messaging/activemq/ActiveMQDestination.java |  24 ++
 .../activemq/ActiveMQDestinationImpl.java       |  66 +++++
 .../messaging/activemq/ActiveMQDriver.java      |  28 ++
 .../messaging/activemq/ActiveMQQueue.java       |  27 ++
 .../messaging/activemq/ActiveMQQueueImpl.java   |  69 +++++
 .../messaging/activemq/ActiveMQSpecs.java       |  33 +++
 .../messaging/activemq/ActiveMQSshDriver.java   | 145 ++++++++++
 .../messaging/activemq/ActiveMQTopic.java       |  27 ++
 .../messaging/activemq/ActiveMQTopicImpl.java   |  50 ++++
 .../entity/messaging/amqp/AmqpExchange.java     |  45 +++
 .../entity/messaging/amqp/AmqpServer.java       |  53 ++++
 .../entity/messaging/jms/JMSBroker.java         |  58 ++++
 .../entity/messaging/jms/JMSBrokerImpl.java     | 168 ++++++++++++
 .../entity/messaging/jms/JMSDestination.java    |  29 ++
 .../messaging/jms/JMSDestinationImpl.java       |  51 ++++
 .../kafka/AbstractfKafkaSshDriver.java          | 133 +++++++++
 .../brooklyn/entity/messaging/kafka/Kafka.java  |  45 +++
 .../entity/messaging/kafka/KafkaBroker.java     |  85 ++++++
 .../messaging/kafka/KafkaBrokerDriver.java      |  27 ++
 .../entity/messaging/kafka/KafkaBrokerImpl.java | 170 ++++++++++++
 .../messaging/kafka/KafkaBrokerSshDriver.java   |  97 +++++++
 .../entity/messaging/kafka/KafkaCluster.java    |  92 +++++++
 .../messaging/kafka/KafkaClusterImpl.java       | 206 ++++++++++++++
 .../entity/messaging/kafka/KafkaZooKeeper.java  |  58 ++++
 .../messaging/kafka/KafkaZooKeeperDriver.java   |  28 ++
 .../messaging/kafka/KafkaZooKeeperImpl.java     |  47 ++++
 .../kafka/KafkaZooKeeperSshDriver.java          |  82 ++++++
 .../entity/messaging/qpid/QpidBroker.java       |  79 ++++++
 .../entity/messaging/qpid/QpidBrokerImpl.java   | 147 ++++++++++
 .../entity/messaging/qpid/QpidDestination.java  |  32 +++
 .../messaging/qpid/QpidDestinationImpl.java     | 101 +++++++
 .../entity/messaging/qpid/QpidDriver.java       |  28 ++
 .../entity/messaging/qpid/QpidQueue.java        |  29 ++
 .../entity/messaging/qpid/QpidQueueImpl.java    |  66 +++++
 .../entity/messaging/qpid/QpidSshDriver.java    | 137 ++++++++++
 .../entity/messaging/qpid/QpidTopic.java        |  27 ++
 .../entity/messaging/qpid/QpidTopicImpl.java    |  56 ++++
 .../entity/messaging/rabbit/RabbitBroker.java   |  91 +++++++
 .../messaging/rabbit/RabbitBrokerImpl.java      | 121 +++++++++
 .../messaging/rabbit/RabbitDestination.java     |  92 +++++++
 .../entity/messaging/rabbit/RabbitDriver.java   |  32 +++
 .../entity/messaging/rabbit/RabbitQueue.java    |  85 ++++++
 .../messaging/rabbit/RabbitSshDriver.java       | 208 ++++++++++++++
 .../brooklyn/entity/messaging/storm/Storm.java  | 105 +++++++
 .../entity/messaging/storm/StormDeployment.java |  42 +++
 .../messaging/storm/StormDeploymentImpl.java    |  77 ++++++
 .../entity/messaging/storm/StormDriver.java     |  27 ++
 .../entity/messaging/storm/StormImpl.java       | 118 ++++++++
 .../entity/messaging/storm/StormSshDriver.java  | 272 +++++++++++++++++++
 .../entity/zookeeper/AbstractZooKeeperImpl.java | 109 ++++++++
 .../entity/zookeeper/ZooKeeperDriver.java       |  27 ++
 .../entity/zookeeper/ZooKeeperEnsemble.java     |  53 ++++
 .../entity/zookeeper/ZooKeeperEnsembleImpl.java | 105 +++++++
 .../entity/zookeeper/ZooKeeperNode.java         |  67 +++++
 .../entity/zookeeper/ZooKeeperNodeImpl.java     |  33 +++
 .../entity/zookeeper/ZooKeeperSshDriver.java    | 163 +++++++++++
 .../entity/messaging/activemq/activemq.xml      | 154 -----------
 .../messaging/kafka/kafka-google-doorway.jpg    | Bin 15692 -> 0 bytes
 .../entity/messaging/kafka/server.properties    | 112 --------
 .../entity/messaging/kafka/zookeeper.properties |  13 -
 .../entity/messaging/rabbit/rabbitmq.config     |   5 -
 .../brooklyn/entity/messaging/storm/storm.yaml  |  39 ---
 .../brooklyn/entity/messaging/zookeeper/zoo.cfg |  42 ---
 .../entity/messaging/activemq/activemq.xml      | 154 +++++++++++
 .../messaging/kafka/kafka-google-doorway.jpg    | Bin 0 -> 15692 bytes
 .../entity/messaging/kafka/server.properties    | 112 ++++++++
 .../entity/messaging/kafka/zookeeper.properties |  13 +
 .../entity/messaging/rabbit/rabbitmq.config     |   5 +
 .../brooklyn/entity/messaging/storm/storm.yaml  |  39 +++
 .../brooklyn/entity/messaging/zookeeper/zoo.cfg |  42 +++
 .../messaging/activemq/ActiveMQEc2LiveTest.java | 117 --------
 .../activemq/ActiveMQGoogleComputeLiveTest.java | 117 --------
 .../activemq/ActiveMQIntegrationTest.java       | 258 ------------------
 .../messaging/kafka/KafkaIntegrationTest.java   | 142 ----------
 .../entity/messaging/kafka/KafkaLiveTest.java   |  68 -----
 .../entity/messaging/kafka/KafkaSupport.java    | 109 --------
 .../entity/messaging/qpid/QpidEc2LiveTest.java  |  46 ----
 .../messaging/qpid/QpidIntegrationTest.java     | 254 -----------------
 .../messaging/rabbit/RabbitEc2LiveTest.java     |  98 -------
 .../messaging/rabbit/RabbitIntegrationTest.java | 189 -------------
 .../messaging/storm/LocalhostLiveTest.java      |  32 ---
 .../messaging/storm/SoftLayerLiveTest.java      |  33 ---
 .../storm/StormAbstractCloudLiveTest.java       | 200 --------------
 .../messaging/storm/StormEc2LiveTest.java       |  58 ----
 .../messaging/storm/StormGceLiveTest.java       |  51 ----
 .../storm/topologies/ExclamationBolt.java       |  51 ----
 .../zookeeper/ZooKeeperEc2LiveTest.java         |  48 ----
 .../zookeeper/ZooKeeperEnsembleLiveTest.java    | 127 ---------
 .../messaging/activemq/ActiveMQEc2LiveTest.java | 117 ++++++++
 .../activemq/ActiveMQGoogleComputeLiveTest.java | 117 ++++++++
 .../activemq/ActiveMQIntegrationTest.java       | 258 ++++++++++++++++++
 .../messaging/kafka/KafkaIntegrationTest.java   | 142 ++++++++++
 .../entity/messaging/kafka/KafkaLiveTest.java   |  68 +++++
 .../entity/messaging/kafka/KafkaSupport.java    | 109 ++++++++
 .../entity/messaging/qpid/QpidEc2LiveTest.java  |  46 ++++
 .../messaging/qpid/QpidIntegrationTest.java     | 254 +++++++++++++++++
 .../messaging/rabbit/RabbitEc2LiveTest.java     |  98 +++++++
 .../messaging/rabbit/RabbitIntegrationTest.java | 189 +++++++++++++
 .../messaging/storm/LocalhostLiveTest.java      |  32 +++
 .../messaging/storm/SoftLayerLiveTest.java      |  33 +++
 .../storm/StormAbstractCloudLiveTest.java       | 200 ++++++++++++++
 .../messaging/storm/StormEc2LiveTest.java       |  58 ++++
 .../messaging/storm/StormGceLiveTest.java       |  51 ++++
 .../storm/topologies/ExclamationBolt.java       |  51 ++++
 .../zookeeper/ZooKeeperEc2LiveTest.java         |  48 ++++
 .../zookeeper/ZooKeeperEnsembleLiveTest.java    | 127 +++++++++
 .../src/test/resources/opengamma-cluster.yaml   |   2 +-
 .../src/test/resources/storm-blueprint.yaml     |   2 +-
 178 files changed, 7182 insertions(+), 7182 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/examples/simple-messaging-pubsub/src/main/java/org/apache/brooklyn/demo/KafkaClusterExample.java
----------------------------------------------------------------------
diff --git a/examples/simple-messaging-pubsub/src/main/java/org/apache/brooklyn/demo/KafkaClusterExample.java b/examples/simple-messaging-pubsub/src/main/java/org/apache/brooklyn/demo/KafkaClusterExample.java
index ea316b5..63bc3fd 100644
--- a/examples/simple-messaging-pubsub/src/main/java/org/apache/brooklyn/demo/KafkaClusterExample.java
+++ b/examples/simple-messaging-pubsub/src/main/java/org/apache/brooklyn/demo/KafkaClusterExample.java
@@ -22,7 +22,7 @@ import java.util.List;
 
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.Entities;
-import brooklyn.entity.messaging.kafka.KafkaCluster;
+import org.apache.brooklyn.entity.messaging.kafka.KafkaCluster;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.launcher.BrooklynLauncher;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/examples/simple-messaging-pubsub/src/main/java/org/apache/brooklyn/demo/StandaloneQpidBrokerExample.java
----------------------------------------------------------------------
diff --git a/examples/simple-messaging-pubsub/src/main/java/org/apache/brooklyn/demo/StandaloneQpidBrokerExample.java b/examples/simple-messaging-pubsub/src/main/java/org/apache/brooklyn/demo/StandaloneQpidBrokerExample.java
index aecd1be..c3969a5 100644
--- a/examples/simple-messaging-pubsub/src/main/java/org/apache/brooklyn/demo/StandaloneQpidBrokerExample.java
+++ b/examples/simple-messaging-pubsub/src/main/java/org/apache/brooklyn/demo/StandaloneQpidBrokerExample.java
@@ -23,8 +23,8 @@ import java.util.List;
 import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.messaging.amqp.AmqpServer;
-import brooklyn.entity.messaging.qpid.QpidBroker;
+import org.apache.brooklyn.entity.messaging.amqp.AmqpServer;
+import org.apache.brooklyn.entity.messaging.qpid.QpidBroker;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.launcher.BrooklynLauncher;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/StormSampleApp.java
----------------------------------------------------------------------
diff --git a/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/StormSampleApp.java b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/StormSampleApp.java
index 52f5cdc..26f4e37 100644
--- a/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/StormSampleApp.java
+++ b/examples/simple-nosql-cluster/src/main/java/org/apache/brooklyn/demo/StormSampleApp.java
@@ -28,7 +28,7 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.messaging.storm.StormDeployment;
+import org.apache.brooklyn.entity.messaging.storm.StormDeployment;
 
 import org.apache.brooklyn.launcher.BrooklynLauncher;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/pom.xml
----------------------------------------------------------------------
diff --git a/software/messaging/pom.xml b/software/messaging/pom.xml
index 8d26aa9..bd0a84d 100644
--- a/software/messaging/pom.xml
+++ b/software/messaging/pom.xml
@@ -53,11 +53,11 @@
                                 the given components. These are files "without any degree of creativity" from the
                                 perspective of the Brooklyn/Apache contribution.
                             -->
-                            <exclude>src/main/resources/brooklyn/entity/messaging/activemq/activemq.xml</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/messaging/kafka/server.properties</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/messaging/kafka/zookeeper.properties</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/messaging/storm/storm.yaml</exclude>
-                            <exclude>src/main/resources/brooklyn/entity/messaging/rabbit/rabbitmq.config</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/messaging/activemq/activemq.xml</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/messaging/kafka/server.properties</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/messaging/kafka/zookeeper.properties</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/messaging/storm/storm.yaml</exclude>
+                            <exclude>src/main/resources/org/apache/brooklyn/entity/messaging/rabbit/rabbitmq.config</exclude>
                         </excludes>
                     </configuration>
                 </plugin>

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/MessageBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/MessageBroker.java b/software/messaging/src/main/java/brooklyn/entity/messaging/MessageBroker.java
deleted file mode 100644
index 60405e3..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/MessageBroker.java
+++ /dev/null
@@ -1,34 +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 brooklyn.entity.messaging;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.event.AttributeSensor;
-
-import brooklyn.event.basic.Sensors;
-
-/**
- * Marker interface identifying message brokers.
- */
-public interface MessageBroker extends Entity {
-    AttributeSensor<String> BROKER_URL = Sensors.newStringSensor("broker.url", "Broker Connection URL");
-
-    /** Setup the URL for external connections to the broker. */
-    void setBrokerUrl();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/Queue.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/Queue.java b/software/messaging/src/main/java/brooklyn/entity/messaging/Queue.java
deleted file mode 100644
index 2bf2cb2..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/Queue.java
+++ /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 brooklyn.entity.messaging;
-
-import org.apache.brooklyn.api.event.AttributeSensor;
-
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-
-/**
- * An interface that describes a messaging queue.
- */
-public interface Queue {
-    BasicAttributeSensorAndConfigKey<String> QUEUE_NAME = new BasicAttributeSensorAndConfigKey<String>(String.class, "queue.name", "Queue name");
-
-    AttributeSensor<Integer> QUEUE_DEPTH_BYTES = Sensors.newIntegerSensor("queue.depth.bytes", "Queue depth in bytes");
-    AttributeSensor<Integer> QUEUE_DEPTH_MESSAGES = Sensors.newIntegerSensor("queue.depth.messages", "Queue depth in messages");
-    
-    /**
-     * Create the queue.
-     *
-     * TODO make this an effector
-     */
-    abstract void create();
-
-    /**
-     * Delete the queue.
-     *
-     * TODO make this an effector
-     */
-    abstract void delete();
-
-    String getQueueName();
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/Topic.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/Topic.java b/software/messaging/src/main/java/brooklyn/entity/messaging/Topic.java
deleted file mode 100644
index bf45ee5..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/Topic.java
+++ /dev/null
@@ -1,46 +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 brooklyn.entity.messaging;
-
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-
-/**
- * An interface that describes a messaging topic.
- */
-public interface Topic {
-    BasicAttributeSensorAndConfigKey<String> TOPIC_NAME = new BasicAttributeSensorAndConfigKey<String>(
-            String.class, "topic.name", "Topic name");
-
-    /**
-     * Create the topic.
-     * 
-     * TODO make this an effector
-     */
-    public abstract void create();
-
-    /**
-     * Delete the topic.
-     * 
-     * TODO make this an effector
-     */
-    public abstract void delete();
-
-    String getTopicName();
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBroker.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
deleted file mode 100644
index b8bbdca..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
+++ /dev/null
@@ -1,81 +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 brooklyn.entity.messaging.activemq;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.java.UsesJmx;
-import brooklyn.entity.messaging.MessageBroker;
-import brooklyn.entity.messaging.jms.JMSBroker;
-import brooklyn.event.basic.AttributeSensorAndConfigKey;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.util.time.Duration;
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single ActiveMQ broker instance.
- */
-@Catalog(name="ActiveMQ Broker", description="ActiveMQ is an open source message broker which fully implements the Java Message Service 1.1 (JMS)", iconUrl="classpath:///activemq-logo.png")
-@ImplementedBy(ActiveMQBrokerImpl.class)
-public interface ActiveMQBroker extends SoftwareProcess, MessageBroker, UsesJmx, JMSBroker<ActiveMQQueue, ActiveMQTopic> {
-
-    @SetFromFlag("startTimeout")
-    ConfigKey<Duration> START_TIMEOUT = SoftwareProcess.START_TIMEOUT;
-    
-    @SetFromFlag("version")
-    public static final ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "5.10.2");
-
-    @SetFromFlag("downloadUrl")
-    public static final AttributeSensorAndConfigKey<String,String> DOWNLOAD_URL = new StringAttributeSensorAndConfigKey(
-            Attributes.DOWNLOAD_URL, "${driver.mirrorUrl}/${version}/apache-activemq-${version}-bin.tar.gz");
-
-    /** download mirror, if desired */
-    @SetFromFlag("mirrorUrl")
-    public static final BasicConfigKey<String> MIRROR_URL = new BasicConfigKey<String>(String.class, "activemq.install.mirror.url", "URL of mirror",
-        "http://www.mirrorservice.org/sites/ftp.apache.org/activemq");
-
-    @SetFromFlag("brokerName")
-    public static final AttributeSensorAndConfigKey<String,String> BROKER_NAME = 
-        ConfigKeys.newStringSensorAndConfigKey("activemq.brokerName", "ActiveMQ Broker Name", "localhost");
-
-    @SetFromFlag("openWirePort")
-    public static final PortAttributeSensorAndConfigKey OPEN_WIRE_PORT = new PortAttributeSensorAndConfigKey("openwire.port", "OpenWire port", "61616+");
-
-    @SetFromFlag("jettyPort")
-    public static final PortAttributeSensorAndConfigKey AMQ_JETTY_PORT = new PortAttributeSensorAndConfigKey("activemq.jetty.port", "jetty port", "8161+");
-
-    @SetFromFlag("jmxUser")
-    public static final BasicAttributeSensorAndConfigKey<String> JMX_USER = new BasicAttributeSensorAndConfigKey<String>(UsesJmx.JMX_USER, "admin");
-    
-    @SetFromFlag("jmxPassword")
-    public static final BasicAttributeSensorAndConfigKey<String> JMX_PASSWORD = new BasicAttributeSensorAndConfigKey<String>(UsesJmx.JMX_PASSWORD, "admin");
-    
-    @SetFromFlag("templateConfigurationUrl")
-    public static final BasicAttributeSensorAndConfigKey<String> TEMPLATE_CONFIGURATION_URL = new BasicAttributeSensorAndConfigKey<String>(
-            String.class, "activemq.templateConfigurationUrl", "Template file (in freemarker format) for the conf/activemq.xml file", 
-            "classpath://brooklyn/entity/messaging/activemq/activemq.xml");
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java
deleted file mode 100644
index c849df1..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java
+++ /dev/null
@@ -1,124 +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 brooklyn.entity.messaging.activemq;
-
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.java.UsesJmx;
-import brooklyn.entity.messaging.jms.JMSBrokerImpl;
-import brooklyn.event.feed.jmx.JmxAttributePollConfig;
-import brooklyn.event.feed.jmx.JmxFeed;
-
-import com.google.common.base.Functions;
-import com.google.common.base.Objects.ToStringHelper;
-import com.google.common.base.Predicates;
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single ActiveMQ broker instance.
- */
-public class ActiveMQBrokerImpl extends JMSBrokerImpl<ActiveMQQueue, ActiveMQTopic> implements ActiveMQBroker {
-    private static final Logger log = LoggerFactory.getLogger(ActiveMQBrokerImpl.class);
-
-    private volatile JmxFeed jmxFeed;
-
-    public ActiveMQBrokerImpl() {
-        super();
-    }
-
-    @Override
-    public void init() {
-        super.init();
-        Entities.getRequiredUrlConfig(this, TEMPLATE_CONFIGURATION_URL);
-    }
-    
-    public void setBrokerUrl() {
-        setAttribute(BROKER_URL, String.format("tcp://%s:%d", getAttribute(HOSTNAME), getAttribute(OPEN_WIRE_PORT)));
-    }
-    
-    public Integer getJmxPort() {
-        return !isJmxEnabled() ? Integer.valueOf(-1) : getAttribute(UsesJmx.JMX_PORT);
-    }
-    
-    public String getBrokerName() {
-        return getAttribute(BROKER_NAME);
-    }
-    
-    public Integer getOpenWirePort() {
-        return getAttribute(OPEN_WIRE_PORT);
-    }
-    
-    public boolean isJmxEnabled() {
-        return Boolean.TRUE.equals(getConfig(USE_JMX));
-    }
-
-    @Override
-    public ActiveMQQueue createQueue(Map properties) {
-        ActiveMQQueue result = addChild(EntitySpec.create(ActiveMQQueue.class).configure(properties));
-        Entities.manage(result);
-        result.create();
-        return result;
-    }
-
-    @Override
-    public ActiveMQTopic createTopic(Map properties) {
-        ActiveMQTopic result = addChild(EntitySpec.create(ActiveMQTopic.class).configure(properties));
-        Entities.manage(result);
-        result.create();
-        return result;
-    }
-
-    @Override     
-    protected void connectSensors() {
-        setAttribute(BROKER_URL, String.format("tcp://%s:%d", getAttribute(HOSTNAME), getAttribute(OPEN_WIRE_PORT)));
-        
-        String brokerMbeanName = "org.apache.activemq:type=Broker,brokerName=" + getBrokerName();
-        
-        jmxFeed = JmxFeed.builder()
-                .entity(this)
-                .period(500, TimeUnit.MILLISECONDS)
-                .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP)
-                        .objectName(brokerMbeanName)
-                        .attributeName("BrokerName")
-                        .onSuccess(Functions.forPredicate(Predicates.notNull()))
-                        .onFailureOrException(Functions.constant(false))
-                        .suppressDuplicates(true))
-                .build();
-    }
-
-    @Override
-    public void disconnectSensors() {
-        super.disconnectSensors();
-        if (jmxFeed != null) jmxFeed.stop();
-    }
-
-    @Override
-    protected ToStringHelper toStringHelper() {
-        return super.toStringHelper().add("openWirePort", getAttribute(OPEN_WIRE_PORT));
-    }
-
-    @Override
-    public Class getDriverInterface() {
-        return ActiveMQDriver.class;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDestination.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDestination.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDestination.java
deleted file mode 100644
index b33942c..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDestination.java
+++ /dev/null
@@ -1,24 +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 brooklyn.entity.messaging.activemq;
-
-import brooklyn.entity.messaging.jms.JMSDestination;
-
-public interface ActiveMQDestination extends JMSDestination {
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDestinationImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDestinationImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDestinationImpl.java
deleted file mode 100644
index 02b4d29..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDestinationImpl.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 brooklyn.entity.messaging.activemq;
-
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.basic.EntityLocal;
-
-import com.google.common.base.Preconditions;
-
-import brooklyn.entity.messaging.jms.JMSDestinationImpl;
-import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.event.feed.jmx.JmxHelper;
-import brooklyn.util.exceptions.Exceptions;
-
-public abstract class ActiveMQDestinationImpl extends JMSDestinationImpl implements ActiveMQDestination {
-    protected ObjectName brokerMBeanName;
-    protected transient JmxHelper jmxHelper;
-    protected volatile JmxFeed jmxFeed;
-
-    public ActiveMQDestinationImpl() {
-    }
-    
-    @Override
-    public void onManagementStarting() {
-        super.onManagementStarting();
-
-        String brokerName = getBrokerName();
-        Preconditions.checkArgument(brokerName != null && !brokerName.isEmpty(), "ActiveMQ brokerName attribute must be specified");
-
-        try {
-            brokerMBeanName = new ObjectName("org.apache.activemq:type=Broker,brokerName=" + brokerName);
-            jmxHelper = new JmxHelper((EntityLocal) getParent());
-        } catch (MalformedObjectNameException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    
-    @Override
-    protected void disconnectSensors() {
-        if (jmxFeed != null) jmxFeed.stop();
-    }
-    
-    protected String getBrokerName() {
-        Preconditions.checkNotNull(getParent(), "JMS Destination must have a broker parent");
-        return getParent().getAttribute(ActiveMQBroker.BROKER_NAME);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDriver.java
deleted file mode 100644
index 8e69017..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQDriver.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 brooklyn.entity.messaging.activemq;
-
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-
-public interface ActiveMQDriver extends JavaSoftwareProcessDriver {
-
-    String getBrokerName();
-
-    Integer getOpenWirePort();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQQueue.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQQueue.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQQueue.java
deleted file mode 100644
index 458b6f0..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQQueue.java
+++ /dev/null
@@ -1,27 +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 brooklyn.entity.messaging.activemq;
-
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-
-import brooklyn.entity.messaging.Queue;
-
-@ImplementedBy(ActiveMQQueueImpl.class)
-public interface ActiveMQQueue extends ActiveMQDestination, Queue {
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQQueueImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQQueueImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQQueueImpl.java
deleted file mode 100644
index 856b2db..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQQueueImpl.java
+++ /dev/null
@@ -1,69 +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 brooklyn.entity.messaging.activemq;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.event.feed.jmx.JmxAttributePollConfig;
-import brooklyn.event.feed.jmx.JmxFeed;
-
-public class ActiveMQQueueImpl extends ActiveMQDestinationImpl implements ActiveMQQueue {
-    public static final Logger log = LoggerFactory.getLogger(ActiveMQQueue.class);
-
-    public ActiveMQQueueImpl() {
-    }
-
-    @Override
-    public void onManagementStarting() {
-        super.onManagementStarting();
-        setAttribute(QUEUE_NAME, getName());
-    }
-
-    public String getQueueName() {
-        return getName();
-    }
-    
-    public void create() {
-        log.debug("{} adding queue {} to broker {}", new Object[] {this, getName(), jmxHelper.getAttribute(brokerMBeanName, "BrokerName")});
-        
-        jmxHelper.operation(brokerMBeanName, "addQueue", getName());
-        
-        connectSensors();
-    }
-
-    public void delete() {
-        jmxHelper.operation(brokerMBeanName, "removeQueue", getName());
-        disconnectSensors();
-    }
-
-    @Override
-    protected void connectSensors() {
-        String queue = String.format("org.apache.activemq:type=Broker,brokerName=%s,destinationType=Queue,destinationName=%s", getBrokerName(), getName());
-        
-        jmxFeed = JmxFeed.builder()
-                .entity(this)
-                .helper(jmxHelper)
-                .pollAttribute(new JmxAttributePollConfig<Integer>(QUEUE_DEPTH_MESSAGES)
-                        .objectName(queue)
-                        .attributeName("QueueSize"))
-                .build();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQSpecs.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQSpecs.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQSpecs.java
deleted file mode 100644
index 4a481ec..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQSpecs.java
+++ /dev/null
@@ -1,33 +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 brooklyn.entity.messaging.activemq;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-
-public class ActiveMQSpecs {
-
-    public static EntitySpec<ActiveMQBroker> brokerSpec() {
-        return EntitySpec.create(ActiveMQBroker.class);
-    }
-    
-    public static EntitySpec<ActiveMQBroker> brokerSpecChef() {
-        return EntitySpec.create(ActiveMQBroker.class);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQSshDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQSshDriver.java
deleted file mode 100644
index 43096ed..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQSshDriver.java
+++ /dev/null
@@ -1,145 +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 brooklyn.entity.messaging.activemq;
-
-import static java.lang.String.format;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.net.Networking;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-
-import com.google.common.collect.ImmutableMap;
-
-public class ActiveMQSshDriver extends JavaSoftwareProcessSshDriver implements ActiveMQDriver {
-
-    public ActiveMQSshDriver(ActiveMQBrokerImpl entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    @Override
-    protected String getLogFileLocation() { 
-        return Os.mergePathsUnix(getRunDir(), "data/activemq.log");
-    }
-
-    @Override
-    public String getBrokerName() { 
-        return entity.getAttribute(ActiveMQBroker.BROKER_NAME);
-    }
-
-    @Override
-    public Integer getOpenWirePort() { 
-        return entity.getAttribute(ActiveMQBroker.OPEN_WIRE_PORT);
-    }
-
-    public String getMirrorUrl() {
-        return entity.getConfig(ActiveMQBroker.MIRROR_URL);
-    }
-
-    protected String getTemplateConfigurationUrl() {
-        return entity.getAttribute(ActiveMQBroker.TEMPLATE_CONFIGURATION_URL);
-    }
-
-    public String getPidFile() {
-        return "data/activemq.pid";
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("apache-activemq-%s", getVersion()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-
-        List<String> commands = new LinkedList<String>();
-        commands.addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs));
-        commands.add(BashCommands.INSTALL_TAR);
-        commands.add("tar xzfv "+saveAs);
-
-        newScript(INSTALLING)
-                .body.append(commands)
-                .execute();
-    }
-
-    @Override
-    public void customize() {
-        Networking.checkPortsValid(ImmutableMap.of("jmxPort", getJmxPort(), "openWirePort", getOpenWirePort()));
-        newScript(CUSTOMIZING)
-                .body.append(
-                        format("cp -R %s/{bin,conf,data,lib,webapps} .", getExpandedInstallDir()),
-                        // Required in version 5.5.1 (at least), but not in version 5.7.0
-                        "sed -i.bk 's/\\[-z \"$JAVA_HOME\"]/\\[ -z \"$JAVA_HOME\" ]/g' bin/activemq",
-                        // Stop it writing to dev null on start
-                        "sed -i.bk \"s/\\(ACTIVEMQ_HOME..bin.run.jar.*\\)>.dev.null/\\1/\" bin/activemq",
-                        // Required if launching multiple AMQ's, prevent jetty port conflicts
-                        "sed -i.bk 's/8161/"+getEntity().getAttribute(ActiveMQBroker.AMQ_JETTY_PORT)+"/g' conf/jetty.xml"
-                        // TODO disable persistence (this should be a flag -- but it seems to have no effect, despite ):
-                        // "sed -i.bk 's/broker /broker persistent=\"false\" /g' conf/activemq.xml",
-                    )
-                .execute();
-
-        // Copy the configuration file across
-        String destinationConfigFile = Os.mergePathsUnix(getRunDir(), "conf/activemq.xml");
-        copyTemplate(getTemplateConfigurationUrl(), destinationConfigFile);
-    }
-
-    @Override
-    public void launch() {
-        // Using nohup, as recommended at http://activemq.apache.org/run-broker.html
-        newScript(ImmutableMap.of(USE_PID_FILE, false), LAUNCHING)
-                .body.append("nohup ./bin/activemq start > ./data/activemq-extra.log 2>&1 &")
-                .execute();
-    }
-    
-    @Override
-    public boolean isRunning() {
-        return newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), CHECK_RUNNING).execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), STOPPING).execute();
-    }
-
-    @Override
-    public void kill() {
-        newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), KILLING).execute();
-    }
-
-    @Override
-    public Map<String, String> getShellEnvironment() {
-        return MutableMap.<String,String>builder()
-                .putAll(super.getShellEnvironment())
-                .put("ACTIVEMQ_HOME", getRunDir())
-                .put("ACTIVEMQ_PIDFILE", getPidFile())
-                .renameKey("JAVA_OPTS", "ACTIVEMQ_OPTS")
-                .build();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQTopic.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQTopic.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQTopic.java
deleted file mode 100644
index 304e3e9..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQTopic.java
+++ /dev/null
@@ -1,27 +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 brooklyn.entity.messaging.activemq;
-
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-
-import brooklyn.entity.messaging.Topic;
-
-@ImplementedBy(ActiveMQTopicImpl.class)
-public interface ActiveMQTopic extends ActiveMQDestination, Topic {
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQTopicImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQTopicImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQTopicImpl.java
deleted file mode 100644
index c3cdd86..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQTopicImpl.java
+++ /dev/null
@@ -1,50 +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 brooklyn.entity.messaging.activemq;
-
-
-public class ActiveMQTopicImpl extends ActiveMQDestinationImpl implements ActiveMQTopic {
-    public ActiveMQTopicImpl() {
-    }
-
-    @Override
-    public void onManagementStarting() {
-        super.onManagementStarting();
-        setAttribute(TOPIC_NAME, getName());
-    }
-
-    @Override
-    public void create() {
-        jmxHelper.operation(brokerMBeanName, "addTopic", getName());
-        connectSensors();
-    }
-
-    public void delete() {
-        jmxHelper.operation(brokerMBeanName, "removeTopic", getName());
-        disconnectSensors();
-    }
-
-    public void connectSensors() {
-        //TODO add sensors for topics
-    }
-
-    public String getTopicName() {
-        return getName();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpExchange.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpExchange.java b/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpExchange.java
deleted file mode 100644
index 0ddd854..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpExchange.java
+++ /dev/null
@@ -1,45 +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 brooklyn.entity.messaging.amqp;
-
-import org.apache.brooklyn.api.event.Sensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-
-/**
- * An interface that describes an AMQP exchange.
- */
-public interface AmqpExchange {
-
-    /* AMQP standard exchange names. */
-    
-    String DIRECT = "amq.direct";
-    String TOPIC = "amq.topic";
-
-    /** The AMQP exchange name {@link Sensor}. */
-    @SetFromFlag("exchange")
-    BasicAttributeSensorAndConfigKey<String> EXCHANGE_NAME = new BasicAttributeSensorAndConfigKey<String>(
-            String.class, "amqp.exchange.name", "AMQP exchange name");
-
-    /**
-     * Return the AMQP exchange name.
-     */
-    public String getExchangeName();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpServer.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpServer.java b/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpServer.java
deleted file mode 100644
index a044d45..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpServer.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 brooklyn.entity.messaging.amqp;
-
-import org.apache.brooklyn.api.entity.Entity;
-
-import brooklyn.entity.basic.Attributes;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-
-/**
- * Marker interface identifying AMQP servers.
- */
-public interface AmqpServer extends Entity {
-    
-    /* AMQP protocol version strings. */
-
-    String AMQP_0_8 = "0-8";
-    String AMQP_0_9 = "0-9";
-    String AMQP_0_9_1 = "0-9-1";
-    String AMQP_0_10 = "0-10";
-    String AMQP_1_0 = "1-0";
-
-    PortAttributeSensorAndConfigKey AMQP_PORT = Attributes.AMQP_PORT;
-
-    BasicAttributeSensorAndConfigKey<String> VIRTUAL_HOST_NAME = new BasicAttributeSensorAndConfigKey<String>(
-            String.class, "amqp.virtualHost", "AMQP virtual host name", "localhost");
-
-    BasicAttributeSensorAndConfigKey<String> AMQP_VERSION = new BasicAttributeSensorAndConfigKey<String>(
-            String.class, "amqp.version", "AMQP protocol version");
-
-    String getVirtualHost();
-
-    String getAmqpVersion();
-
-    Integer getAmqpPort();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBroker.java b/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBroker.java
deleted file mode 100644
index d121c56..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBroker.java
+++ /dev/null
@@ -1,58 +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 brooklyn.entity.messaging.jms;
-
-import java.util.Collection;
-import java.util.Map;
-
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.messaging.MessageBroker;
-import brooklyn.entity.messaging.Queue;
-import brooklyn.entity.messaging.Topic;
-
-import com.google.common.annotations.VisibleForTesting;
-
-public interface JMSBroker<Q extends JMSDestination & Queue, T extends JMSDestination & Topic> extends SoftwareProcess, MessageBroker {
-    
-    @VisibleForTesting
-    public Collection<String> getQueueNames();
-    
-    @VisibleForTesting
-    public Collection<String> getTopicNames();
-
-    @VisibleForTesting
-    public Map<String, Q> getQueues();
-    
-    @VisibleForTesting
-    public Map<String, T> getTopics();
-    
-    /** TODO make this an effector */
-    public void addQueue(String name);
-    
-    public void addQueue(String name, Map properties);
-
-    public Q createQueue(Map properties);
-
-    /** TODO make this an effector */
-    public void addTopic(String name);
-    
-    public void addTopic(String name, Map properties);
-
-    public T createTopic(Map properties);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBrokerImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBrokerImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBrokerImpl.java
deleted file mode 100644
index 43f13ba..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSBrokerImpl.java
+++ /dev/null
@@ -1,168 +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 brooklyn.entity.messaging.jms;
-
-import static brooklyn.util.JavaGroovyEquivalents.groovyTruth;
-
-import java.util.Collection;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.Lifecycle;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.messaging.Queue;
-import brooklyn.entity.messaging.Topic;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
-public abstract class JMSBrokerImpl<Q extends JMSDestination & Queue, T extends JMSDestination & Topic> extends SoftwareProcessImpl implements JMSBroker<Q,T> {
-    private static final Logger log = LoggerFactory.getLogger(JMSBroker.class);
-    
-    Collection<String> queueNames;
-    Collection<String> topicNames;
-    Map<String, Q> queues = Maps.newLinkedHashMap();
-    Map<String, T> topics = Maps.newLinkedHashMap();
-
-    public JMSBrokerImpl() {
-    }
-
-    @Override
-    public JMSBrokerImpl configure(Map properties) {
-        if (queueNames==null) queueNames = Lists.newArrayList();
-        if (groovyTruth(properties.get("queue"))) queueNames.add((String) properties.remove("queue"));
-        if (groovyTruth(properties.get("queues"))) queueNames.addAll((Collection<String>) properties.remove("queues"));
-
-        if (topicNames==null) topicNames = Lists.newArrayList();
-        if (groovyTruth(properties.get("topic"))) topicNames.add((String) properties.remove("topic"));
-        if (groovyTruth(properties.get("topics"))) topicNames.addAll((Collection<String>) properties.remove("topics"));
-        
-        return (JMSBrokerImpl) super.configure(properties);
-    }
-
-    @Override
-    public Collection<String> getQueueNames() {
-        return queueNames;
-    }
-    
-    @Override
-    public Collection<String> getTopicNames() {
-        return topicNames;
-    }
-
-    @Override
-    public Map<String, Q> getQueues() {
-        return queues;
-    }
-    
-    @Override
-    public Map<String, T> getTopics() {
-        return topics;
-    }
-    
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-        setBrokerUrl();
-    }
-
-    // should be called after sensor-polling is activated etc
-    @Override
-    protected void postStart() {
-        super.postStart();
-        // stupid to do this here, but there appears to be a race where sometimes the
-        // broker throws a BrokerStopped exception, even though the sensor indicates it is up
-        Time.sleep(Duration.FIVE_SECONDS);
-        for (String name : queueNames) {
-            addQueue(name);
-        }
-        for (String name : topicNames) {
-            addTopic(name);
-        }
-    }
-    
-    @Override
-    public abstract void setBrokerUrl();
-
-    @Override
-    public void preStop() {
-        // If can't delete queues, continue trying to stop.
-        // (e.g. in CI have seen activemq "BrokerStoppedException" thrown in queue.destroy()). 
-        try {
-            for (JMSDestination queue : queues.values()) {
-                queue.destroy();
-            }
-        } catch (Exception e) {
-            log.warn("Error deleting queues from broker "+this+"; continuing with stop...", e);
-        }
-        
-        try {
-            for (JMSDestination topic : topics.values()) {
-                topic.destroy();
-            }
-        } catch (Exception e) {
-            log.warn("Error deleting topics from broker "+this+"; continuing with stop...", e);
-        }
-        
-        super.preStop();
-    }
-    
-    @Override
-    public void addQueue(String name) {
-        addQueue(name, MutableMap.of());
-    }
-    
-    public void checkStartingOrRunning() {
-        Lifecycle state = getAttribute(SERVICE_STATE_ACTUAL);
-        if (getAttribute(SERVICE_STATE_ACTUAL) == Lifecycle.RUNNING) return;
-        if (getAttribute(SERVICE_STATE_ACTUAL) == Lifecycle.STARTING) return;
-        // TODO this check may be redundant or even inappropriate
-        throw new IllegalStateException("Cannot run against "+this+" in state "+state);
-    }
-
-    @Override
-    public void addQueue(String name, Map properties) {
-        checkStartingOrRunning();
-        properties.put("name", name);
-        queues.put(name, createQueue(properties));
-    }
-
-    @Override
-    public abstract Q createQueue(Map properties);
-
-    @Override
-    public void addTopic(String name) {
-        addTopic(name, MutableMap.of());
-    }
-    
-    @Override
-    public void addTopic(String name, Map properties) {
-        checkStartingOrRunning();
-        properties.put("name", name);
-        topics.put(name, createTopic(properties));
-    }
-
-    @Override
-    public abstract T createTopic(Map properties);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSDestination.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSDestination.java b/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSDestination.java
deleted file mode 100644
index 6257551..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSDestination.java
+++ /dev/null
@@ -1,29 +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 brooklyn.entity.messaging.jms;
-
-import org.apache.brooklyn.api.entity.Entity;
-
-public interface JMSDestination extends Entity {
-    public String getName();
-    
-    public void delete();
-
-    public void destroy();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSDestinationImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSDestinationImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSDestinationImpl.java
deleted file mode 100644
index 7f65cef..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/jms/JMSDestinationImpl.java
+++ /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 brooklyn.entity.messaging.jms;
-
-import brooklyn.entity.basic.AbstractEntity;
-
-import com.google.common.base.Preconditions;
-
-public abstract class JMSDestinationImpl extends AbstractEntity implements JMSDestination {
-    public JMSDestinationImpl() {
-    }
-
-    @Override
-    public void onManagementStarting() {
-        super.onManagementStarting();
-        Preconditions.checkNotNull(getName(), "Name must be specified");
-    }
-
-    @Override
-    public String getName() {
-        return getDisplayName();
-    }
-    
-    protected abstract void connectSensors();
-
-    protected abstract void disconnectSensors();
-
-    public abstract void delete();
-
-    public void destroy() {
-        disconnectSensors();
-        delete();
-        super.destroy();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/AbstractfKafkaSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/AbstractfKafkaSshDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/AbstractfKafkaSshDriver.java
deleted file mode 100644
index b797f7e..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/AbstractfKafkaSshDriver.java
+++ /dev/null
@@ -1,133 +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 brooklyn.entity.messaging.kafka;
-
-import static java.lang.String.format;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.basic.EntityLocal;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.net.Networking;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-
-public abstract class AbstractfKafkaSshDriver extends JavaSoftwareProcessSshDriver {
-
-    @SuppressWarnings("unused")
-    private static final Logger log = LoggerFactory.getLogger(KafkaZooKeeperSshDriver.class);
-
-    public AbstractfKafkaSshDriver(EntityLocal entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    protected abstract Map<String, Integer> getPortMap();
-
-    protected abstract ConfigKey<String> getConfigTemplateKey();
-
-    protected abstract String getConfigFileName();
-
-    protected abstract String getLaunchScriptName();
-
-    protected abstract String getTopicsScriptName();
-
-    protected abstract String getProcessIdentifier();
-
-    @Override
-    protected String getLogFileLocation() { return Os.mergePaths(getRunDir(), "console.out"); }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("kafka_%s", getVersion()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-
-        List<String> commands = new LinkedList<String>();
-        commands.addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs));
-        commands.add(BashCommands.INSTALL_TAR);
-        commands.add("tar xzfv "+saveAs);
-        commands.add("cd "+getExpandedInstallDir());
-
-        newScript(INSTALLING)
-                .body.append(commands)
-                .execute();
-    }
-
-    @Override
-    public void customize() {
-        Networking.checkPortsValid(getPortMap());
-
-        newScript(CUSTOMIZING)
-                .failOnNonZeroResultCode()
-                .body.append(format("cp -R %s/* %s", getExpandedInstallDir(), getRunDir()))
-                .execute();
-
-        String config = entity.getConfig(getConfigTemplateKey());
-        copyTemplate(config, getConfigFileName());
-    }
-
-    @Override
-    public void launch() {
-        newScript(MutableMap.of(USE_PID_FILE, getPidFile()), LAUNCHING)
-                .failOnNonZeroResultCode()
-                .body.append(String.format("nohup ./bin/%s ./%s > console.out 2>&1 &", getLaunchScriptName(), getConfigFileName()))
-                .execute();
-    }
-
-    public String getPidFile() { return Os.mergePathsUnix(getRunDir(), "kafka.pid"); }
-
-    @Override
-    public boolean isRunning() {
-        return newScript(MutableMap.of(USE_PID_FILE, getPidFile()), CHECK_RUNNING).execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        newScript(MutableMap.of(USE_PID_FILE, false), STOPPING)
-                .body.append(String.format("ps ax | grep %s | awk '{print $1}' | xargs kill", getProcessIdentifier()))
-                .body.append(String.format("ps ax | grep %s | awk '{print $1}' | xargs kill -9", getProcessIdentifier()))
-                .execute();
-    }
-
-    /**
-     * Use RMI agent to provide JMX.
-     */
-    @Override
-    public Map<String, String> getShellEnvironment() {
-        return MutableMap.<String, String>builder()
-                .putAll(super.getShellEnvironment())
-                .renameKey("JAVA_OPTS", "KAFKA_JMX_OPTS")
-                .build();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/Kafka.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/Kafka.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/Kafka.java
deleted file mode 100644
index 64123b3..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/Kafka.java
+++ /dev/null
@@ -1,45 +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 brooklyn.entity.messaging.kafka;
-
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-
-/**
- * Shared Kafka broker and zookeeper properties.
- */
-public interface Kafka {
-
-    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "2.9.2-0.8.2.1");
-
-    @SetFromFlag("downloadUrl")
-    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
-            Attributes.DOWNLOAD_URL, "http://apache.cbox.biz/kafka/0.8.2.1/kafka_${version}.tgz");
-
-    // TODO: Upgrade to version 0.8.0, which will require refactoring of the sensors to reflect the changes to the JMX beans
-//    @SetFromFlag("downloadUrl")
-//    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
-//            Attributes.DOWNLOAD_URL, "http://mirror.catn.com/pub/apache/kafka/${version}/kafka-${version}-src.tgz");
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBroker.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBroker.java
deleted file mode 100644
index 71b20c5..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBroker.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 brooklyn.entity.messaging.kafka;
-
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.java.UsesJmx;
-import brooklyn.entity.messaging.MessageBroker;
-import brooklyn.entity.zookeeper.ZooKeeperNode;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-
-import org.apache.brooklyn.location.basic.PortRanges;
-
-import brooklyn.util.time.Duration;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Kafka broker instance.
- */
-@ImplementedBy(KafkaBrokerImpl.class)
-public interface KafkaBroker extends SoftwareProcess, MessageBroker, UsesJmx, Kafka {
-
-    @SetFromFlag("startTimeout")
-    ConfigKey<Duration> START_TIMEOUT = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.START_TIMEOUT, Duration.FIVE_MINUTES);
-
-    @SetFromFlag("version")
-    ConfigKey<String> SUGGESTED_VERSION = Kafka.SUGGESTED_VERSION;
-
-    @SetFromFlag("kafkaPort")
-    PortAttributeSensorAndConfigKey KAFKA_PORT = new PortAttributeSensorAndConfigKey("kafka.port", "Kafka port", "9092+");
-
-    /** Location of the configuration file template to be copied to the server.*/
-    @SetFromFlag("kafkaServerConfig")
-    ConfigKey<String> KAFKA_BROKER_CONFIG_TEMPLATE = new BasicConfigKey<String>(String.class,
-            "kafka.broker.configTemplate", "Kafka broker configuration template (in freemarker format)",
-            "classpath://brooklyn/entity/messaging/kafka/server.properties");
-
-    @SetFromFlag("zookeeper")
-    ConfigKey<ZooKeeperNode> ZOOKEEPER = new BasicConfigKey<ZooKeeperNode>(ZooKeeperNode.class, "kafka.broker.zookeeper", "Kafka zookeeper entity");
-
-    PortAttributeSensorAndConfigKey INTERNAL_JMX_PORT = new PortAttributeSensorAndConfigKey(
-            "internal.jmx.direct.port", "JMX internal port (started by Kafka broker, if using UsesJmx.JMX_AGENT_MODE is not null)", PortRanges.fromString("9999+"));
-
-    AttributeSensor<Integer> BROKER_ID = Sensors.newIntegerSensor("kafka.broker.id", "Kafka unique broker ID");
-
-    AttributeSensor<Long> FETCH_REQUEST_COUNT = Sensors.newLongSensor("kafka.broker.fetch.total", "Fetch request count");
-    AttributeSensor<Long> TOTAL_FETCH_TIME = Sensors.newLongSensor("kafka.broker.fetch.time.total", "Total fetch request processing time (millis)");
-    AttributeSensor<Double> MAX_FETCH_TIME = Sensors.newDoubleSensor("kafka.broker.fetch.time.max", "Max fetch request processing time (millis)");
-
-    AttributeSensor<Long> PRODUCE_REQUEST_COUNT = Sensors.newLongSensor("kafka.broker.produce.total", "Produce request count");
-    AttributeSensor<Long> TOTAL_PRODUCE_TIME = Sensors.newLongSensor("kafka.broker.produce.time.total", "Total produce request processing time (millis)");
-    AttributeSensor<Double> MAX_PRODUCE_TIME = Sensors.newDoubleSensor("kafka.broker.produce.time.max", "Max produce request processing time (millis)");
-
-    AttributeSensor<Long> BYTES_RECEIVED = Sensors.newLongSensor("kafka.broker.bytes.received", "Total bytes received");
-    AttributeSensor<Long> BYTES_SENT = Sensors.newLongSensor("kafka.broker.bytes.sent", "Total bytes sent");
-    
-    Integer getKafkaPort();
-
-    Integer getBrokerId();
-
-    ZooKeeperNode getZookeeper();
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerDriver.java
deleted file mode 100644
index c20deff..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerDriver.java
+++ /dev/null
@@ -1,27 +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 brooklyn.entity.messaging.kafka;
-
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-
-public interface KafkaBrokerDriver extends JavaSoftwareProcessDriver {
-
-    Integer getKafkaPort();
-
-}



[04/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/service/InitdServiceInstaller.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/service/InitdServiceInstaller.java b/software/base/src/main/java/brooklyn/entity/service/InitdServiceInstaller.java
index 6cde4d3..04048af 100644
--- a/software/base/src/main/java/brooklyn/entity/service/InitdServiceInstaller.java
+++ b/software/base/src/main/java/brooklyn/entity/service/InitdServiceInstaller.java
@@ -27,6 +27,12 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.trait.HasShortName;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.policy.Enricher;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ssh.SshPutTaskWrapper;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
@@ -38,15 +44,9 @@ import brooklyn.entity.effector.EffectorTasks;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 import org.apache.brooklyn.location.cloud.names.AbstractCloudMachineNamer;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshPutTaskWrapper;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-import brooklyn.util.text.TemplateProcessor;
 
 
 public class InitdServiceInstaller implements SystemServiceInstaller {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/service/SystemServiceEnricher.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/service/SystemServiceEnricher.java b/software/base/src/main/java/brooklyn/entity/service/SystemServiceEnricher.java
index 7c4ada5..bbad039 100644
--- a/software/base/src/main/java/brooklyn/entity/service/SystemServiceEnricher.java
+++ b/software/base/src/main/java/brooklyn/entity/service/SystemServiceEnricher.java
@@ -25,6 +25,13 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.management.ExecutionContext;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.policy.Enricher;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.ssh.SshPutTaskWrapper;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
@@ -39,13 +46,6 @@ import brooklyn.entity.effector.EffectorTasks;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.util.net.Urls;
-import brooklyn.util.task.BasicExecutionManager;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.ssh.SshPutTaskWrapper;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.system.ProcessTaskFactory;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 
 import com.google.common.collect.ImmutableSet;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/software/MachineInitTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/MachineInitTasks.java b/software/base/src/main/java/brooklyn/entity/software/MachineInitTasks.java
index 2e68f6f..3173aa4 100644
--- a/software/base/src/main/java/brooklyn/entity/software/MachineInitTasks.java
+++ b/software/base/src/main/java/brooklyn/entity/software/MachineInitTasks.java
@@ -22,6 +22,9 @@ import java.util.List;
 import java.util.concurrent.Callable;
 
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,15 +35,14 @@ import com.google.common.collect.Lists;
 
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.EntityInternal;
+
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.net.Protocol;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.ssh.IptablesCommands;
 import brooklyn.util.ssh.IptablesCommands.Chain;
 import brooklyn.util.ssh.IptablesCommands.Policy;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshTasks;
 import brooklyn.util.text.Strings;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java b/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java
index 97add55..34cd86e 100644
--- a/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java
+++ b/software/base/src/main/java/brooklyn/entity/software/MachineLifecycleEffectorTasks.java
@@ -37,6 +37,10 @@ import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.api.location.MachineManagementMixins.SuspendsMachines;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -77,15 +81,11 @@ import org.apache.brooklyn.location.basic.SshMachineLocation;
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.net.UserAndHostAndPort;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/software/ProvidesProvisioningFlags.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/ProvidesProvisioningFlags.java b/software/base/src/main/java/brooklyn/entity/software/ProvidesProvisioningFlags.java
index 91c6666..8052ece 100644
--- a/software/base/src/main/java/brooklyn/entity/software/ProvidesProvisioningFlags.java
+++ b/software/base/src/main/java/brooklyn/entity/software/ProvidesProvisioningFlags.java
@@ -19,8 +19,7 @@
 package brooklyn.entity.software;
 
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
-
-import brooklyn.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import com.google.common.annotations.Beta;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/software/SshEffectorTasks.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/SshEffectorTasks.java b/software/base/src/main/java/brooklyn/entity/software/SshEffectorTasks.java
index e40170c..f5ca922 100644
--- a/software/base/src/main/java/brooklyn/entity/software/SshEffectorTasks.java
+++ b/software/base/src/main/java/brooklyn/entity/software/SshEffectorTasks.java
@@ -27,6 +27,18 @@ import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ssh.SshFetchTaskFactory;
+import org.apache.brooklyn.core.util.task.ssh.SshFetchTaskWrapper;
+import org.apache.brooklyn.core.util.task.ssh.SshPutTaskFactory;
+import org.apache.brooklyn.core.util.task.ssh.SshPutTaskWrapper;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.ssh.internal.AbstractSshExecTaskFactory;
+import org.apache.brooklyn.core.util.task.ssh.internal.PlainSshExecTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskFactory;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,19 +56,7 @@ import brooklyn.entity.effector.EffectorTasks.EffectorTaskFactory;
 import org.apache.brooklyn.location.basic.LocationInternal;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshFetchTaskFactory;
-import brooklyn.util.task.ssh.SshFetchTaskWrapper;
-import brooklyn.util.task.ssh.SshPutTaskFactory;
-import brooklyn.util.task.ssh.SshPutTaskWrapper;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.ssh.internal.AbstractSshExecTaskFactory;
-import brooklyn.util.task.ssh.internal.PlainSshExecTaskFactory;
-import brooklyn.util.task.system.ProcessTaskFactory;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java b/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
index a0c1b82..b0d8881 100644
--- a/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/StaticSensor.java
@@ -20,6 +20,9 @@ package brooklyn.entity.software;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ValueResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -27,10 +30,7 @@ import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.Propagator;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.effector.AddSensor;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ValueResolver;
 
 import com.google.common.base.Supplier;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/software/http/HttpRequestSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/http/HttpRequestSensor.java b/software/base/src/main/java/brooklyn/entity/software/http/HttpRequestSensor.java
index 8d0047a..c9f87a5 100644
--- a/software/base/src/main/java/brooklyn/entity/software/http/HttpRequestSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/http/HttpRequestSensor.java
@@ -23,6 +23,7 @@ import java.net.URI;
 import net.minidev.json.JSONObject;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,7 +35,6 @@ import brooklyn.entity.software.ssh.SshCommandSensor;
 import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/software/java/JmxAttributeSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/java/JmxAttributeSensor.java b/software/base/src/main/java/brooklyn/entity/software/java/JmxAttributeSensor.java
index b866be3..0802b22 100644
--- a/software/base/src/main/java/brooklyn/entity/software/java/JmxAttributeSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/java/JmxAttributeSensor.java
@@ -25,6 +25,9 @@ import javax.management.ObjectName;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -38,9 +41,6 @@ import brooklyn.event.basic.DependentConfiguration;
 import brooklyn.event.feed.jmx.JmxAttributePollConfig;
 import brooklyn.event.feed.jmx.JmxFeed;
 import brooklyn.event.feed.jmx.JmxHelper;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandEffector.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandEffector.java b/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandEffector.java
index ca26baa..8d15270 100644
--- a/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandEffector.java
+++ b/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandEffector.java
@@ -22,6 +22,7 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.ParameterType;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -33,7 +34,6 @@ import brooklyn.entity.effector.Effectors.EffectorBuilder;
 import brooklyn.entity.software.SshEffectorTasks;
 import brooklyn.entity.software.SshEffectorTasks.SshEffectorTaskFactory;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java b/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
index 4443ece..1b6e99b 100644
--- a/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
@@ -22,6 +22,8 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntityInitializer;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,8 +37,6 @@ import brooklyn.event.feed.ssh.SshFeed;
 import brooklyn.event.feed.ssh.SshPollConfig;
 import brooklyn.event.feed.ssh.SshValueFunctions;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java b/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
index 1a3656f..310f855 100644
--- a/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
+++ b/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
@@ -23,6 +23,7 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntityInitializer;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,7 +32,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.event.basic.Sensors;
 import brooklyn.event.feed.windows.WindowsPerformanceCounterFeed;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.text.Strings;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java b/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java
index c39ca9f..f809d31 100644
--- a/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java
+++ b/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java
@@ -61,12 +61,12 @@ import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.java.JmxSupport;
 import brooklyn.entity.java.UsesJmx;
-import brooklyn.util.crypto.SecureKeys;
 import brooklyn.util.crypto.SslTrustUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.RuntimeInterruptedException;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityLatchTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityLatchTest.java b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityLatchTest.java
index aa46dd1..ab59e39 100644
--- a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityLatchTest.java
+++ b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityLatchTest.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.TaskInternal;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.BeforeMethod;
@@ -44,7 +45,6 @@ import org.apache.brooklyn.location.basic.FixedListMachineProvisioningLocation;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.test.Asserts;
-import brooklyn.util.task.TaskInternal;
 import brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityRebindTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityRebindTest.java b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityRebindTest.java
index 7ae7b54..ee9723a 100644
--- a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityRebindTest.java
+++ b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityRebindTest.java
@@ -34,6 +34,7 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.testng.annotations.AfterMethod;
@@ -48,8 +49,6 @@ import brooklyn.entity.rebind.RebindTestUtils;
 import org.apache.brooklyn.location.basic.AbstractLocation;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
-import brooklyn.util.flags.SetFromFlag;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.io.Files;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityTest.java b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityTest.java
index 3d8ddda..7a1deb4 100644
--- a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityTest.java
+++ b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessEntityTest.java
@@ -40,6 +40,9 @@ import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.management.EntityManager;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.jclouds.util.Throwables2;
@@ -74,13 +77,10 @@ import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.PropagatedRuntimeException;
 import brooklyn.util.net.UserAndHostAndPort;
 import brooklyn.util.os.Os;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessSshDriverIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessSshDriverIntegrationTest.java b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessSshDriverIntegrationTest.java
index f528f7c..aadb1ea 100644
--- a/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessSshDriverIntegrationTest.java
+++ b/software/base/src/test/java/brooklyn/entity/basic/SoftwareProcessSshDriverIntegrationTest.java
@@ -34,6 +34,7 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.BrooklynNetworkUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
@@ -45,7 +46,6 @@ import brooklyn.entity.trait.Startable;
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
-import brooklyn.util.BrooklynNetworkUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.os.Os;
 import brooklyn.util.stream.KnownSizeInputStream;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/basic/VanillaSoftwareProcessAndChildrenIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/basic/VanillaSoftwareProcessAndChildrenIntegrationTest.java b/software/base/src/test/java/brooklyn/entity/basic/VanillaSoftwareProcessAndChildrenIntegrationTest.java
index 8b516ad..f8fb978 100644
--- a/software/base/src/test/java/brooklyn/entity/basic/VanillaSoftwareProcessAndChildrenIntegrationTest.java
+++ b/software/base/src/test/java/brooklyn/entity/basic/VanillaSoftwareProcessAndChildrenIntegrationTest.java
@@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.slf4j.Logger;
@@ -33,7 +34,6 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.SoftwareProcess.ChildStartableMode;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/basic/lifecycle/MyEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/basic/lifecycle/MyEntityImpl.java b/software/base/src/test/java/brooklyn/entity/basic/lifecycle/MyEntityImpl.java
index c8eca43..9f7c290 100644
--- a/software/base/src/test/java/brooklyn/entity/basic/lifecycle/MyEntityImpl.java
+++ b/software/base/src/test/java/brooklyn/entity/basic/lifecycle/MyEntityImpl.java
@@ -26,11 +26,13 @@ import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.basic.SoftwareProcessDriver;
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
+
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.ResourceUtils;
+
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.Identifiers;
 
 public class MyEntityImpl extends SoftwareProcessImpl implements MyEntity {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunnerTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunnerTest.java b/software/base/src/test/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunnerTest.java
index 5ab4228..aedc116 100644
--- a/software/base/src/test/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunnerTest.java
+++ b/software/base/src/test/java/brooklyn/entity/basic/lifecycle/NaiveScriptRunnerTest.java
@@ -26,6 +26,9 @@ import java.util.concurrent.Callable;
 
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.BasicExecutionContext;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -39,9 +42,6 @@ import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.repeat.Repeater;
-import brooklyn.util.task.BasicExecutionContext;
-import brooklyn.util.task.BasicExecutionManager;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Throwables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/basic/lifecycle/StartStopSshDriverTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/basic/lifecycle/StartStopSshDriverTest.java b/software/base/src/test/java/brooklyn/entity/basic/lifecycle/StartStopSshDriverTest.java
index 1ef3e94..83c7dec 100644
--- a/software/base/src/test/java/brooklyn/entity/basic/lifecycle/StartStopSshDriverTest.java
+++ b/software/base/src/test/java/brooklyn/entity/basic/lifecycle/StartStopSshDriverTest.java
@@ -31,6 +31,9 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.cli.SshCliTool;
+import org.apache.brooklyn.core.util.internal.ssh.sshj.SshjTool;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestApplicationImpl;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -41,13 +44,12 @@ import org.testng.annotations.Test;
 import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
 import brooklyn.entity.basic.BrooklynConfigKeys;
 import brooklyn.entity.basic.Entities;
+
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.internal.ssh.cli.SshCliTool;
-import brooklyn.util.internal.ssh.sshj.SshjTool;
 import brooklyn.util.stream.StreamGobbler;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java b/software/base/src/test/java/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
index a088996..e473f52 100644
--- a/software/base/src/test/java/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
+++ b/software/base/src/test/java/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
@@ -35,6 +35,9 @@ import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.HttpTestUtils;
 import org.apache.http.auth.UsernamePasswordCredentials;
@@ -58,17 +61,16 @@ import brooklyn.entity.brooklynnode.BrooklynNode.ExistingFileBehaviour;
 import brooklyn.entity.brooklynnode.BrooklynNode.StopNodeAndKillAppsEffector;
 import brooklyn.entity.proxying.EntityProxyImpl;
 import brooklyn.event.feed.http.JsonFunctions;
+
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.basic.Locations;
 import org.apache.brooklyn.location.basic.PortRanges;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Functionals;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.net.Networking;
 import brooklyn.util.net.Urls;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/brooklynnode/CallbackEntityHttpClient.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/brooklynnode/CallbackEntityHttpClient.java b/software/base/src/test/java/brooklyn/entity/brooklynnode/CallbackEntityHttpClient.java
index ad5d1f2..e9a73bf 100644
--- a/software/base/src/test/java/brooklyn/entity/brooklynnode/CallbackEntityHttpClient.java
+++ b/software/base/src/test/java/brooklyn/entity/brooklynnode/CallbackEntityHttpClient.java
@@ -23,13 +23,13 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
+import org.apache.brooklyn.core.util.http.HttpTool.HttpClientBuilder;
 import org.apache.http.HttpStatus;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 
 import brooklyn.entity.brooklynnode.EntityHttpClient;
-import brooklyn.util.http.HttpTool.HttpClientBuilder;
-import brooklyn.util.http.HttpToolResponse;
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/chef/ChefLiveTestSupport.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/chef/ChefLiveTestSupport.java b/software/base/src/test/java/brooklyn/entity/chef/ChefLiveTestSupport.java
index a04d9fa..2b65f58 100644
--- a/software/base/src/test/java/brooklyn/entity/chef/ChefLiveTestSupport.java
+++ b/software/base/src/test/java/brooklyn/entity/chef/ChefLiveTestSupport.java
@@ -25,6 +25,7 @@ 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.management.ManagementContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.BeforeMethod;
@@ -34,7 +35,6 @@ import brooklyn.entity.basic.EntityInternal;
 
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.io.FileUtil;
 import brooklyn.util.stream.InputStreamSupplier;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/chef/ChefServerTasksIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/chef/ChefServerTasksIntegrationTest.java b/software/base/src/test/java/brooklyn/entity/chef/ChefServerTasksIntegrationTest.java
index ff7dfb1..1d175b1 100644
--- a/software/base/src/test/java/brooklyn/entity/chef/ChefServerTasksIntegrationTest.java
+++ b/software/base/src/test/java/brooklyn/entity/chef/ChefServerTasksIntegrationTest.java
@@ -22,6 +22,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,7 +34,6 @@ import org.testng.annotations.Test;
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.Entities;
 import brooklyn.util.stream.StreamGobbler;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java b/software/base/src/test/java/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
index 941ba0f..75133c7 100644
--- a/software/base/src/test/java/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
+++ b/software/base/src/test/java/brooklyn/entity/chef/mysql/ChefSoloDriverMySqlEntityLiveTest.java
@@ -20,12 +20,12 @@ package brooklyn.entity.chef.mysql;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.software.SshEffectorTasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 
 public class ChefSoloDriverMySqlEntityLiveTest extends AbstractChefToyMySqlEntityLiveTest {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java
----------------------------------------------------------------------
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 b7034e0..f5213d9 100644
--- a/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java
@@ -31,6 +31,9 @@ import java.util.Set;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.core.util.internal.ssh.RecordingSshTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.internal.ssh.RecordingSshTool.ExecCmd;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterMethod;
@@ -44,9 +47,6 @@ import org.apache.brooklyn.location.basic.SshMachineLocation;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.internal.ssh.RecordingSshTool;
-import brooklyn.util.internal.ssh.RecordingSshTool.ExecCmd;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.jmx.jmxmp.JmxmpAgent;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/java/JmxSupportTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/java/JmxSupportTest.java b/software/base/src/test/java/brooklyn/entity/java/JmxSupportTest.java
index caaf757..97df90b 100644
--- a/software/base/src/test/java/brooklyn/entity/java/JmxSupportTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/JmxSupportTest.java
@@ -20,6 +20,8 @@ package brooklyn.entity.java;
 
 import static org.testng.Assert.assertEquals;
 
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -29,9 +31,7 @@ import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.java.UsesJmx.JmxAgentModes;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.maven.MavenRetriever;
 import brooklyn.util.stream.Streams;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/java/SslKeyConfigTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/java/SslKeyConfigTest.java b/software/base/src/test/java/brooklyn/entity/java/SslKeyConfigTest.java
index 01c2cfb..eab15ca 100644
--- a/software/base/src/test/java/brooklyn/entity/java/SslKeyConfigTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/SslKeyConfigTest.java
@@ -24,12 +24,11 @@ import java.security.Key;
 import java.security.KeyStore;
 import java.security.cert.Certificate;
 
+import org.apache.brooklyn.core.util.crypto.FluentKeySigner;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
-import brooklyn.util.crypto.FluentKeySigner;
-import brooklyn.util.crypto.SecureKeys;
-
 public class SslKeyConfigTest {
 
     @Test

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
----------------------------------------------------------------------
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 dd2b9b0..eaabfed 100644
--- a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
@@ -25,6 +25,7 @@ import java.io.File;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.slf4j.Logger;
@@ -42,7 +43,6 @@ import brooklyn.event.basic.Sensors;
 
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java
index 73a2675..067f86e 100644
--- a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java
@@ -43,6 +43,9 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.crypto.FluentKeySigner;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -53,13 +56,12 @@ import org.testng.annotations.Test;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.Lifecycle;
 import brooklyn.event.feed.jmx.JmxHelper;
+
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.basic.PortRanges;
+
 import brooklyn.test.Asserts;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.crypto.FluentKeySigner;
-import brooklyn.util.crypto.SecureKeys;
 import brooklyn.util.crypto.SslTrustUtils;
 import brooklyn.util.jmx.jmxmp.JmxmpAgent;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/software/MachineLifecycleEffectorTasksTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/software/MachineLifecycleEffectorTasksTest.java b/software/base/src/test/java/brooklyn/entity/software/MachineLifecycleEffectorTasksTest.java
index 2fcd1df..c143adf 100644
--- a/software/base/src/test/java/brooklyn/entity/software/MachineLifecycleEffectorTasksTest.java
+++ b/software/base/src/test/java/brooklyn/entity/software/MachineLifecycleEffectorTasksTest.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.TaskInternal;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
@@ -50,9 +51,10 @@ import brooklyn.entity.basic.SoftwareProcess.StopSoftwareParameters.StopMode;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.DependentConfiguration;
 import brooklyn.event.basic.Sensors;
+
 import org.apache.brooklyn.location.jclouds.BailOutJcloudsLocation;
+
 import brooklyn.test.Asserts;
-import brooklyn.util.task.TaskInternal;
 import brooklyn.util.time.Duration;
 
 public class MachineLifecycleEffectorTasksTest {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/software/SoftwareEffectorTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/software/SoftwareEffectorTest.java b/software/base/src/test/java/brooklyn/entity/software/SoftwareEffectorTest.java
index 599b7ac..61389c9 100644
--- a/software/base/src/test/java/brooklyn/entity/software/SoftwareEffectorTest.java
+++ b/software/base/src/test/java/brooklyn/entity/software/SoftwareEffectorTest.java
@@ -24,6 +24,8 @@ import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -39,9 +41,6 @@ import brooklyn.entity.software.SshEffectorTasks.SshEffectorBody;
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-
 import com.google.common.base.Throwables;
 
 public class SoftwareEffectorTest {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/software/SshEffectorTasksTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/software/SshEffectorTasksTest.java b/software/base/src/test/java/brooklyn/entity/software/SshEffectorTasksTest.java
index 8494e36..f0a4364 100644
--- a/software/base/src/test/java/brooklyn/entity/software/SshEffectorTasksTest.java
+++ b/software/base/src/test/java/brooklyn/entity/software/SshEffectorTasksTest.java
@@ -26,6 +26,9 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.TaskAdaptable;
 import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.core.util.task.ssh.SshFetchTaskWrapper;
+import org.apache.brooklyn.core.util.task.ssh.SshPutTaskWrapper;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
@@ -42,9 +45,6 @@ import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.util.exceptions.PropagatedRuntimeException;
 import brooklyn.util.net.Urls;
-import brooklyn.util.task.ssh.SshFetchTaskWrapper;
-import brooklyn.util.task.ssh.SshPutTaskWrapper;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 
 import com.google.common.io.Files;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java b/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java
index 7ec8952..285122d 100644
--- a/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java
+++ b/software/base/src/test/java/brooklyn/entity/software/StaticSensorTest.java
@@ -19,13 +19,13 @@
 package brooklyn.entity.software;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.BrooklynAppUnitTestSupport;
 import brooklyn.entity.basic.BasicEntity;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/software/http/HttpRequestSensorTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/software/http/HttpRequestSensorTest.java b/software/base/src/test/java/brooklyn/entity/software/http/HttpRequestSensorTest.java
index eb53f3e..8ae262b 100644
--- a/software/base/src/test/java/brooklyn/entity/software/http/HttpRequestSensorTest.java
+++ b/software/base/src/test/java/brooklyn/entity/software/http/HttpRequestSensorTest.java
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -34,7 +35,6 @@ import brooklyn.entity.basic.Entities;
 import brooklyn.event.basic.Sensors;
 import brooklyn.test.TestHttpRequestHandler;
 import brooklyn.test.TestHttpServer;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/software/mysql/AbstractToyMySqlEntityTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/software/mysql/AbstractToyMySqlEntityTest.java b/software/base/src/test/java/brooklyn/entity/software/mysql/AbstractToyMySqlEntityTest.java
index 98bae62..12266b5 100644
--- a/software/base/src/test/java/brooklyn/entity/software/mysql/AbstractToyMySqlEntityTest.java
+++ b/software/base/src/test/java/brooklyn/entity/software/mysql/AbstractToyMySqlEntityTest.java
@@ -21,6 +21,7 @@ package brooklyn.entity.software.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.util.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,7 +39,6 @@ import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/software/mysql/DynamicToyMySqlEntityBuilder.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/software/mysql/DynamicToyMySqlEntityBuilder.java b/software/base/src/test/java/brooklyn/entity/software/mysql/DynamicToyMySqlEntityBuilder.java
index df3e436..8e1ee2e 100644
--- a/software/base/src/test/java/brooklyn/entity/software/mysql/DynamicToyMySqlEntityBuilder.java
+++ b/software/base/src/test/java/brooklyn/entity/software/mysql/DynamicToyMySqlEntityBuilder.java
@@ -26,6 +26,10 @@ import org.apache.brooklyn.api.entity.proxying.EntityInitializer;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,10 +44,6 @@ import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation.L
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.ComparableVersion;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/base/src/test/java/brooklyn/entity/software/ssh/SshCommandIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/software/ssh/SshCommandIntegrationTest.java b/software/base/src/test/java/brooklyn/entity/software/ssh/SshCommandIntegrationTest.java
index 2d142e4..6316d03 100644
--- a/software/base/src/test/java/brooklyn/entity/software/ssh/SshCommandIntegrationTest.java
+++ b/software/base/src/test/java/brooklyn/entity/software/ssh/SshCommandIntegrationTest.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.brooklyn.test.entity.TestEntity;
@@ -43,7 +44,6 @@ import brooklyn.event.basic.Sensors;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/DatastoreMixins.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/DatastoreMixins.java b/software/database/src/main/java/brooklyn/entity/database/DatastoreMixins.java
index 90f8a62..4727473 100644
--- a/software/database/src/main/java/brooklyn/entity/database/DatastoreMixins.java
+++ b/software/database/src/main/java/brooklyn/entity/database/DatastoreMixins.java
@@ -25,13 +25,13 @@ import javax.annotation.Nullable;
 import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.stream.KnownSizeInputStream;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/crate/CrateNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/crate/CrateNode.java b/software/database/src/main/java/brooklyn/entity/database/crate/CrateNode.java
index 8d5fae3..8373648 100644
--- a/software/database/src/main/java/brooklyn/entity/database/crate/CrateNode.java
+++ b/software/database/src/main/java/brooklyn/entity/database/crate/CrateNode.java
@@ -20,6 +20,7 @@ package brooklyn.entity.database.crate;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
@@ -33,8 +34,8 @@ import brooklyn.event.basic.AttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
+
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.flags.SetFromFlag;
 
 @ImplementedBy(CrateNodeImpl.class)
 public interface CrateNode extends SoftwareProcess, UsesJava,UsesJmx, UsesJavaMXBeans, DatastoreCommon {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbDriver.java b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbDriver.java
index 3d92173..2db7f2ef4 100644
--- a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbDriver.java
+++ b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbDriver.java
@@ -18,8 +18,9 @@
  */
 package brooklyn.entity.database.mariadb;
 
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+
 import brooklyn.entity.basic.SoftwareProcessDriver;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 
 /**
  * The {@link SoftwareProcessDriver} for MariaDB.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNode.java b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNode.java
index d067625..ab77af5 100644
--- a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNode.java
+++ b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNode.java
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.entity.trait.HasShortName;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
@@ -34,8 +35,8 @@ import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSens
 import brooklyn.event.basic.MapConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
+
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.flags.SetFromFlag;
 
 @Catalog(name="MariaDB Node", description="MariaDB is an open source relational database management system (RDBMS)", iconUrl="classpath:///mariadb-logo-180x119.png")
 @ImplementedBy(MariaDbNodeImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
index 0212749..a22af08 100644
--- a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
+++ b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java
@@ -26,9 +26,11 @@ import brooklyn.entity.effector.EffectorBody;
 import brooklyn.event.feed.ssh.SshFeed;
 import brooklyn.event.feed.ssh.SshPollConfig;
 import brooklyn.event.feed.ssh.SshPollValue;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.location.basic.Locations;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.config.ConfigBag;
+
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbSshDriver.java b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
index b35a1cd..4d916b9 100644
--- a/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
+++ b/software/database/src/main/java/brooklyn/entity/database/mariadb/MariaDbSshDriver.java
@@ -41,14 +41,14 @@ import brooklyn.entity.database.DatastoreMixins;
 import brooklyn.entity.software.SshEffectorTasks;
 
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.CountdownTimer;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlClusterImpl.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlClusterImpl.java
index 683f13b..f86ad43 100644
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlClusterImpl.java
+++ b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlClusterImpl.java
@@ -31,6 +31,8 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;
@@ -56,8 +58,6 @@ import brooklyn.event.feed.function.FunctionPollConfig;
 import brooklyn.util.collections.CollectionFunctionals;
 import brooklyn.util.guava.Functionals;
 import brooklyn.util.guava.IfFunctions;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskBuilder;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.StringPredicates;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlDriver.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlDriver.java
index ddfce38..2c90142 100644
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlDriver.java
+++ b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlDriver.java
@@ -18,8 +18,9 @@
  */
 package brooklyn.entity.database.mysql;
 
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+
 import brooklyn.entity.basic.SoftwareProcessDriver;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 
 /**
  * The {@link SoftwareProcessDriver} for MySQL.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNode.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNode.java
index 0ab51d0..99b53c5 100644
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNode.java
+++ b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNode.java
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.entity.trait.HasShortName;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.Effector;
@@ -36,8 +37,8 @@ import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSens
 import brooklyn.event.basic.MapConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
+
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.flags.SetFromFlag;
 
 @Catalog(name="MySql Node", description="MySql is an open source relational database management system (RDBMS)", iconUrl="classpath:///mysql-logo-110x57.png")
 @ImplementedBy(MySqlNodeImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNodeImpl.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNodeImpl.java
index 00a591b..dfbcbf1 100644
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNodeImpl.java
+++ b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlNodeImpl.java
@@ -21,6 +21,7 @@ package brooklyn.entity.database.mysql;
 import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,10 +30,11 @@ import brooklyn.entity.effector.EffectorBody;
 import brooklyn.event.feed.ssh.SshFeed;
 import brooklyn.event.feed.ssh.SshPollConfig;
 import brooklyn.event.feed.ssh.SshPollValue;
+
 import org.apache.brooklyn.location.basic.Locations;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlSshDriver.java b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlSshDriver.java
index 2e748e8..32b530d 100644
--- a/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlSshDriver.java
+++ b/software/database/src/main/java/brooklyn/entity/database/mysql/MySqlSshDriver.java
@@ -43,6 +43,8 @@ import brooklyn.entity.database.DatastoreMixins;
 import brooklyn.entity.software.SshEffectorTasks;
 
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.location.basic.BasicOsDetails.OsVersions;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
@@ -53,8 +55,6 @@ import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.ComparableVersion;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlDriver.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
index 9aaf7c2..02ad039 100644
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
+++ b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
@@ -18,8 +18,9 @@
  */
 package brooklyn.entity.database.postgresql;
 
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+
 import brooklyn.entity.basic.SoftwareProcessDriver;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 
 /**
  * The {@link brooklyn.entity.basic.SoftwareProcessDriver} for PostgreSQL.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNode.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNode.java
index 793debf..20f4b76 100644
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNode.java
+++ b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNode.java
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.entity.trait.HasShortName;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -31,8 +32,8 @@ import brooklyn.entity.database.DatastoreMixins;
 import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * PostgreSQL database node entity.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
index 7572845..d82e637 100644
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
+++ b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeChefImplFromScratch.java
@@ -19,6 +19,9 @@
 package brooklyn.entity.database.postgresql;
 
 import org.apache.brooklyn.api.entity.Effector;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,14 +37,13 @@ import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.software.SshEffectorTasks;
 import brooklyn.event.feed.ssh.SshFeed;
 import brooklyn.event.feed.ssh.SshPollConfig;
+
 import org.apache.brooklyn.location.basic.Locations;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.ResourceUtils;
+
 import brooklyn.util.collections.Jsonya;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
 
 public class PostgreSqlNodeChefImplFromScratch extends EffectorStartableImpl implements PostgreSqlNode {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java
index 71f63d9..c4b02de 100644
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java
+++ b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlNodeImpl.java
@@ -18,12 +18,12 @@
  */
 package brooklyn.entity.database.postgresql;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.entity.effector.EffectorBody;
-import brooklyn.util.config.ConfigBag;
 
 public class PostgreSqlNodeImpl extends SoftwareProcessImpl implements PostgreSqlNode {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
index a23f2bc..5ff0175 100644
--- a/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
+++ b/software/database/src/main/java/brooklyn/entity/database/postgresql/PostgreSqlSshDriver.java
@@ -48,6 +48,10 @@ import brooklyn.entity.database.DatastoreMixins;
 import brooklyn.entity.software.SshEffectorTasks;
 
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks.OnFailingTask;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.util.collections.MutableList;
@@ -56,10 +60,6 @@ import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.ssh.SshTasks.OnFailingTask;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.StringFunctions;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNode.java
----------------------------------------------------------------------
diff --git a/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNode.java b/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNode.java
index 8e990dd..edfbda5 100644
--- a/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNode.java
+++ b/software/database/src/main/java/brooklyn/entity/database/rubyrep/RubyRepNode.java
@@ -21,6 +21,7 @@ package brooklyn.entity.database.rubyrep;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
@@ -31,7 +32,6 @@ import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 @Catalog(name = "RubyRep Node", description = "RubyRep is a database replication system", iconUrl = "classpath:///rubyrep-logo.jpeg")
 @ImplementedBy(RubyRepNodeImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
----------------------------------------------------------------------
diff --git a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
index 5d8e984..36eb963 100644
--- a/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
+++ b/software/database/src/test/java/brooklyn/entity/database/postgresql/PostgreSqlChefTest.java
@@ -33,10 +33,10 @@ import brooklyn.entity.effector.EffectorTasks;
 import brooklyn.entity.software.SshEffectorTasks;
 
 import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.location.basic.PortRanges;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBroker.java b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
index 2e59bd4..b8bbdca 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
@@ -20,6 +20,7 @@ package brooklyn.entity.messaging.activemq;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
@@ -33,7 +34,6 @@ import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 /**
  * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single ActiveMQ broker instance.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpExchange.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpExchange.java b/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpExchange.java
index f2eeee3..0ddd854 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpExchange.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/amqp/AmqpExchange.java
@@ -19,9 +19,9 @@
 package brooklyn.entity.messaging.amqp;
 
 import org.apache.brooklyn.api.event.Sensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * An interface that describes an AMQP exchange.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/Kafka.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/Kafka.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/Kafka.java
index ff7c368..64123b3 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/Kafka.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/Kafka.java
@@ -18,12 +18,13 @@
  */
 package brooklyn.entity.messaging.kafka;
 
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * Shared Kafka broker and zookeeper properties.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBroker.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBroker.java
index 28b51c9..71b20c5 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBroker.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBroker.java
@@ -20,6 +20,7 @@ package brooklyn.entity.messaging.kafka;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -30,8 +31,9 @@ import brooklyn.entity.zookeeper.ZooKeeperNode;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
+
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.flags.SetFromFlag;
+
 import brooklyn.util.time.Duration;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaCluster.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaCluster.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaCluster.java
index 8ebe328..3a24377 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaCluster.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaCluster.java
@@ -24,6 +24,7 @@ import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BrooklynConfigKeys;
@@ -35,7 +36,6 @@ import brooklyn.entity.trait.Startable;
 import brooklyn.entity.zookeeper.ZooKeeperNode;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
index fa4e915..106690a 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
@@ -19,6 +19,7 @@
 package brooklyn.entity.messaging.kafka;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.Effector;
@@ -27,7 +28,6 @@ import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.zookeeper.ZooKeeperNode;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBroker.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBroker.java
index 876ade8..a2af8a4 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBroker.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBroker.java
@@ -22,6 +22,7 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
@@ -34,7 +35,6 @@ import brooklyn.entity.messaging.jms.JMSBroker;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Qpid broker instance, using AMQP 0-10.



[32/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/osgi/Osgis.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/osgi/Osgis.java b/core/src/main/java/brooklyn/util/osgi/Osgis.java
deleted file mode 100644
index 3bf972e..0000000
--- a/core/src/main/java/brooklyn/util/osgi/Osgis.java
+++ /dev/null
@@ -1,719 +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 brooklyn.util.osgi;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.jar.Attributes;
-import java.util.jar.JarInputStream;
-import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
-
-import javax.annotation.Nullable;
-
-import org.apache.felix.framework.FrameworkFactory;
-import org.apache.felix.framework.util.StringMap;
-import org.apache.felix.framework.util.manifestparser.ManifestParser;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Version;
-import org.osgi.framework.launch.Framework;
-import org.osgi.framework.namespace.PackageNamespace;
-import org.osgi.framework.wiring.BundleCapability;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
-
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.collections.MutableSet;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.exceptions.ReferenceWithError;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.net.Urls;
-import brooklyn.util.os.Os;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.annotations.Beta;
-import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.base.Stopwatch;
-
-/** 
- * utilities for working with osgi.
- * osgi support is in early days (June 2014) so this class is beta, subject to change,
- * particularly in how framework is started and bundles installed.
- * 
- * @since 0.7.0  */
-@Beta
-public class Osgis {
-    private static final Logger LOG = LoggerFactory.getLogger(Osgis.class);
-
-    private static final String EXTENSION_PROTOCOL = "system";
-    private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
-    private static final Set<String> SYSTEM_BUNDLES = MutableSet.of();
-
-    public static class VersionedName {
-        private final String symbolicName;
-        private final Version version;
-        public VersionedName(Bundle b) {
-            this.symbolicName = b.getSymbolicName();
-            this.version = b.getVersion();
-        }
-        public VersionedName(String symbolicName, Version version) {
-            this.symbolicName = symbolicName;
-            this.version = version;
-        }
-        @Override public String toString() {
-            return symbolicName + ":" + Strings.toString(version);
-        }
-        public boolean equals(String sn, String v) {
-            return symbolicName.equals(sn) && (version == null && v == null || version != null && version.toString().equals(v));
-        }
-        public boolean equals(String sn, Version v) {
-            return symbolicName.equals(sn) && (version == null && v == null || version != null && version.equals(v));
-        }
-        public String getSymbolicName() {
-            return symbolicName;
-        }
-        public Version getVersion() {
-            return version;
-        }
-        @Override
-        public int hashCode() {
-            return Objects.hashCode(symbolicName, version);
-        }
-        @Override
-        public boolean equals(Object other) {
-            if (!(other instanceof VersionedName)) return false;
-            VersionedName o = (VersionedName) other;
-            return Objects.equal(symbolicName, o.symbolicName) && Objects.equal(version, o.version);
-        }
-    }
-    
-    public static class BundleFinder {
-        protected final Framework framework;
-        protected String symbolicName;
-        protected String version;
-        protected String url;
-        protected boolean urlMandatory = false;
-        protected final List<Predicate<? super Bundle>> predicates = MutableList.of();
-        
-        protected BundleFinder(Framework framework) {
-            this.framework = framework;
-        }
-
-        public BundleFinder symbolicName(String symbolicName) {
-            this.symbolicName = symbolicName;
-            return this;
-        }
-
-        public BundleFinder version(String version) {
-            this.version = version;
-            return this;
-        }
-        
-        public BundleFinder id(String symbolicNameOptionallyWithVersion) {
-            if (Strings.isBlank(symbolicNameOptionallyWithVersion))
-                return this;
-            
-            Maybe<VersionedName> nv = parseOsgiIdentifier(symbolicNameOptionallyWithVersion);
-            if (nv.isAbsent())
-                throw new IllegalArgumentException("Cannot parse symbolic-name:version string '"+symbolicNameOptionallyWithVersion+"'");
-
-            return id(nv.get());
-        }
-
-        private BundleFinder id(VersionedName nv) {
-            symbolicName(nv.getSymbolicName());
-            if (nv.getVersion() != null) {
-                version(nv.getVersion().toString());
-            }
-            return this;
-        }
-
-        public BundleFinder bundle(CatalogBundle bundle) {
-            if (bundle.isNamed()) {
-                symbolicName(bundle.getSymbolicName());
-                version(bundle.getVersion());
-            }
-            if (bundle.getUrl() != null) {
-                requiringFromUrl(bundle.getUrl());
-            }
-            return this;
-        }
-
-        /** Looks for a bundle matching the given URL;
-         * unlike {@link #requiringFromUrl(String)} however, if the URL does not match any bundles
-         * it will return other matching bundles <i>if</if> a {@link #symbolicName(String)} is specified.
-         */
-        public BundleFinder preferringFromUrl(String url) {
-            this.url = url;
-            urlMandatory = false;
-            return this;
-        }
-
-        /** Requires the bundle to have the given URL set as its location. */
-        public BundleFinder requiringFromUrl(String url) {
-            this.url = url;
-            urlMandatory = true;
-            return this;
-        }
-
-        /** Finds the best matching bundle. */
-        public Maybe<Bundle> find() {
-            return findOne(false);
-        }
-        
-        /** Finds the matching bundle, requiring it to be unique. */
-        public Maybe<Bundle> findUnique() {
-            return findOne(true);
-        }
-
-        protected Maybe<Bundle> findOne(boolean requireExactlyOne) {
-            if (symbolicName==null && url==null)
-                throw new IllegalStateException(this+" must be given either a symbolic name or a URL");
-            
-            List<Bundle> result = findAll();
-            if (result.isEmpty())
-                return Maybe.absent("No bundle matching "+getConstraintsDescription());
-            if (requireExactlyOne && result.size()>1)
-                return Maybe.absent("Multiple bundles ("+result.size()+") matching "+getConstraintsDescription());
-            
-            return Maybe.of(result.get(0));
-        }
-        
-        /** Finds all matching bundles, in decreasing version order. */
-        public List<Bundle> findAll() {
-            boolean urlMatched = false;
-            List<Bundle> result = MutableList.of();
-            for (Bundle b: framework.getBundleContext().getBundles()) {
-                if (symbolicName!=null && !symbolicName.equals(b.getSymbolicName())) continue;
-                if (version!=null && !Version.parseVersion(version).equals(b.getVersion())) continue;
-                for (Predicate<? super Bundle> predicate: predicates) {
-                    if (!predicate.apply(b)) continue;
-                }
-
-                // check url last, because if it isn't mandatory we should only clear if we find a url
-                // for which the other items also match
-                if (url!=null) {
-                    boolean matches = url.equals(b.getLocation());
-                    if (urlMandatory) {
-                        if (!matches) continue;
-                        else urlMatched = true;
-                    } else {
-                        if (matches) {
-                            if (!urlMatched) {
-                                result.clear();
-                                urlMatched = true;
-                            }
-                        } else {
-                            if (urlMatched) {
-                                // can't use this bundle as we have previously found a preferred bundle, with a matching url
-                                continue;
-                            }
-                        }
-                    }
-                }
-                                
-                result.add(b);
-            }
-            
-            if (symbolicName==null && url!=null && !urlMatched) {
-                // if we only "preferred" the url, and we did not match it, and we did not have a symbolic name,
-                // then clear the results list!
-                result.clear();
-            }
-
-            Collections.sort(result, new Comparator<Bundle>() {
-                @Override
-                public int compare(Bundle o1, Bundle o2) {
-                    return o2.getVersion().compareTo(o1.getVersion());
-                }
-            });
-            
-            return result;
-        }
-        
-        public String getConstraintsDescription() {
-            List<String> parts = MutableList.of();
-            if (symbolicName!=null) parts.add("symbolicName="+symbolicName);
-            if (version!=null) parts.add("version="+version);
-            if (url!=null)
-                parts.add("url["+(urlMandatory ? "required" : "preferred")+"]="+url);
-            if (!predicates.isEmpty())
-                parts.add("predicates="+predicates);
-            return Joiner.on(";").join(parts);
-        }
-        
-        public String toString() {
-            return getClass().getCanonicalName()+"["+getConstraintsDescription()+"]";
-        }
-
-        public BundleFinder version(final Predicate<Version> versionPredicate) {
-            return satisfying(new Predicate<Bundle>() {
-                @Override
-                public boolean apply(Bundle input) {
-                    return versionPredicate.apply(input.getVersion());
-                }
-            });
-        }
-        
-        public BundleFinder satisfying(Predicate<? super Bundle> predicate) {
-            predicates.add(predicate);
-            return this;
-        }
-    }
-    
-    public static BundleFinder bundleFinder(Framework framework) {
-        return new BundleFinder(framework);
-    }
-
-    /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
-    public static List<Bundle> getBundlesByName(Framework framework, String symbolicName, Predicate<Version> versionMatcher) {
-        return bundleFinder(framework).symbolicName(symbolicName).version(versionMatcher).findAll();
-    }
-
-    /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
-    public static List<Bundle> getBundlesByName(Framework framework, String symbolicName) {
-        return bundleFinder(framework).symbolicName(symbolicName).findAll();
-    }
-
-    /**
-     * Tries to find a bundle in the given framework with name matching either `name' or `name:version'.
-     * @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
-    public static Maybe<Bundle> getBundle(Framework framework, String symbolicNameOptionallyWithVersion) {
-        return bundleFinder(framework).id(symbolicNameOptionallyWithVersion).find();
-    }
-    
-    /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
-    public static Maybe<Bundle> getBundle(Framework framework, String symbolicName, String version) {
-        return bundleFinder(framework).symbolicName(symbolicName).version(version).find();
-    }
-
-    /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
-    public static Maybe<Bundle> getBundle(Framework framework, String symbolicName, Version version) {
-        return bundleFinder(framework).symbolicName(symbolicName).version(Predicates.equalTo(version)).findUnique();
-    }
-
-    // -------- creating
-    
-    /*
-     * loading framework factory and starting framework based on:
-     * http://felix.apache.org/documentation/subprojects/apache-felix-framework/apache-felix-framework-launching-and-embedding.html
-     */
-    
-    public static FrameworkFactory newFrameworkFactory() {
-        URL url = Osgis.class.getClassLoader().getResource(
-                "META-INF/services/org.osgi.framework.launch.FrameworkFactory");
-        if (url != null) {
-            try {
-                BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
-                try {
-                    for (String s = br.readLine(); s != null; s = br.readLine()) {
-                        s = s.trim();
-                        // load the first non-empty, non-commented line
-                        if ((s.length() > 0) && (s.charAt(0) != '#')) {
-                            return (FrameworkFactory) Class.forName(s).newInstance();
-                        }
-                    }
-                } finally {
-                    if (br != null) br.close();
-                }
-            } catch (Exception e) {
-                // class creation exceptions are not interesting to caller...
-                throw Exceptions.propagate(e);
-            }
-        }
-        throw new IllegalStateException("Could not find framework factory.");
-    }
-    
-    public static Framework newFrameworkStarted(String felixCacheDir, boolean clean, Map<?,?> extraStartupConfig) {
-        Map<Object,Object> cfg = MutableMap.copyOf(extraStartupConfig);
-        if (clean) cfg.put(Constants.FRAMEWORK_STORAGE_CLEAN, "onFirstInit");
-        if (felixCacheDir!=null) cfg.put(Constants.FRAMEWORK_STORAGE, felixCacheDir);
-        cfg.put(Constants.FRAMEWORK_BSNVERSION, Constants.FRAMEWORK_BSNVERSION_MULTIPLE);
-        FrameworkFactory factory = newFrameworkFactory();
-
-        Stopwatch timer = Stopwatch.createStarted();
-        Framework framework = factory.newFramework(cfg);
-        try {
-            framework.init();
-            installBootBundles(framework);
-            framework.start();
-        } catch (Exception e) {
-            // framework bundle start exceptions are not interesting to caller...
-            throw Exceptions.propagate(e);
-        }
-        LOG.debug("System bundles are: "+SYSTEM_BUNDLES);
-        LOG.debug("OSGi framework started in " + Duration.of(timer));
-        return framework;
-    }
-
-    private static void installBootBundles(Framework framework) {
-        Stopwatch timer = Stopwatch.createStarted();
-        LOG.debug("Installing OSGi boot bundles from "+Osgis.class.getClassLoader()+"...");
-        Enumeration<URL> resources;
-        try {
-            resources = Osgis.class.getClassLoader().getResources(MANIFEST_PATH);
-        } catch (IOException e) {
-            throw Exceptions.propagate(e);
-        }
-        BundleContext bundleContext = framework.getBundleContext();
-        Map<String, Bundle> installedBundles = getInstalledBundlesById(bundleContext);
-        while(resources.hasMoreElements()) {
-            URL url = resources.nextElement();
-            ReferenceWithError<?> installResult = installExtensionBundle(bundleContext, url, installedBundles, getVersionedId(framework));
-            if (installResult.hasError() && !installResult.masksErrorIfPresent()) {
-                // it's reported as a critical error, so warn here
-                LOG.warn("Unable to install manifest from "+url+": "+installResult.getError(), installResult.getError());
-            } else {
-                Object result = installResult.getWithoutError();
-                if (result instanceof Bundle) {
-                    String v = getVersionedId( (Bundle)result );
-                    SYSTEM_BUNDLES.add(v);
-                    if (installResult.hasError()) {
-                        LOG.debug(installResult.getError().getMessage()+(result!=null ? " ("+result+"/"+v+")" : ""));
-                    } else {
-                        LOG.debug("Installed "+v+" from "+url);
-                    }
-                } else if (installResult.hasError()) {
-                    LOG.debug(installResult.getError().getMessage());
-                }
-            }
-        }
-        LOG.debug("Installed OSGi boot bundles in "+Time.makeTimeStringRounded(timer)+": "+Arrays.asList(framework.getBundleContext().getBundles()));
-    }
-
-    private static Map<String, Bundle> getInstalledBundlesById(BundleContext bundleContext) {
-        Map<String, Bundle> installedBundles = new HashMap<String, Bundle>();
-        Bundle[] bundles = bundleContext.getBundles();
-        for (Bundle b : bundles) {
-            installedBundles.put(getVersionedId(b), b);
-        }
-        return installedBundles;
-    }
-
-    /** Wraps the bundle if successful or already installed, wraps TRUE if it's the system entry,
-     * wraps null if the bundle is already installed from somewhere else;
-     * in all these cases <i>masking</i> an explanatory error if already installed or it's the system entry.
-     * <p>
-     * Returns an instance wrapping null and <i>throwing</i> an error if the bundle could not be installed.
-     */
-    private static ReferenceWithError<?> installExtensionBundle(BundleContext bundleContext, URL manifestUrl, Map<String, Bundle> installedBundles, String frameworkVersionedId) {
-        //ignore http://felix.extensions:9/ system entry
-        if("felix.extensions".equals(manifestUrl.getHost())) 
-            return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Skipping install of internal extension bundle from "+manifestUrl));
-
-        try {
-            Manifest manifest = readManifest(manifestUrl);
-            if (!isValidBundle(manifest)) 
-                return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Resource at "+manifestUrl+" is not an OSGi bundle: no valid manifest"));
-            
-            String versionedId = getVersionedId(manifest);
-            URL bundleUrl = ResourceUtils.getContainerUrl(manifestUrl, MANIFEST_PATH);
-
-            Bundle existingBundle = installedBundles.get(versionedId);
-            if (existingBundle != null) {
-                if (!bundleUrl.equals(existingBundle.getLocation()) &&
-                        //the framework bundle is always pre-installed, don't display duplicate info
-                        !versionedId.equals(frameworkVersionedId)) {
-                    return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Bundle "+versionedId+" (from manifest " + manifestUrl + ") is already installed, from " + existingBundle.getLocation()));
-                }
-                return ReferenceWithError.newInstanceMaskingError(existingBundle, new IllegalArgumentException("Bundle "+versionedId+" from manifest " + manifestUrl + " is already installed"));
-            }
-            
-            byte[] jar = buildExtensionBundle(manifest);
-            LOG.debug("Installing boot bundle " + bundleUrl);
-            //mark the bundle as extension so we can detect it later using the "system:" protocol
-            //(since we cannot access BundleImpl.isExtension)
-            Bundle newBundle = bundleContext.installBundle(EXTENSION_PROTOCOL + ":" + bundleUrl.toString(), new ByteArrayInputStream(jar));
-            installedBundles.put(versionedId, newBundle);
-            return ReferenceWithError.newInstanceWithoutError(newBundle);
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            return ReferenceWithError.newInstanceThrowingError(null, 
-                new IllegalStateException("Problem installing extension bundle " + manifestUrl + ": "+e, e));
-        }
-    }
-
-    private static Manifest readManifest(URL manifestUrl) throws IOException {
-        Manifest manifest;
-        InputStream in = null;
-        try {
-            in = manifestUrl.openStream();
-            manifest = new Manifest(in);
-        } finally {
-            if (in != null) {
-                try {in.close();} 
-                catch (Exception e) {};
-            }
-        }
-        return manifest;
-    }
-
-    private static byte[] buildExtensionBundle(Manifest manifest) throws IOException {
-        Attributes atts = manifest.getMainAttributes();
-
-        //the following properties are invalid in extension bundles
-        atts.remove(new Attributes.Name(Constants.IMPORT_PACKAGE));
-        atts.remove(new Attributes.Name(Constants.REQUIRE_BUNDLE));
-        atts.remove(new Attributes.Name(Constants.BUNDLE_NATIVECODE));
-        atts.remove(new Attributes.Name(Constants.DYNAMICIMPORT_PACKAGE));
-        atts.remove(new Attributes.Name(Constants.BUNDLE_ACTIVATOR));
-        
-        //mark as extension bundle
-        atts.putValue(Constants.FRAGMENT_HOST, "system.bundle; extension:=framework");
-
-        //create the jar containing the manifest
-        ByteArrayOutputStream jar = new ByteArrayOutputStream();
-        JarOutputStream out = new JarOutputStream(jar, manifest);
-        out.close();
-        return jar.toByteArray();
-    }
-
-    private static boolean isValidBundle(Manifest manifest) {
-        Attributes atts = manifest.getMainAttributes();
-        return atts.containsKey(new Attributes.Name(Constants.BUNDLE_MANIFESTVERSION));
-    }
-
-    private static String getVersionedId(Bundle b) {
-        return b.getSymbolicName() + ":" + b.getVersion();
-    }
-
-    private static String getVersionedId(Manifest manifest) {
-        Attributes atts = manifest.getMainAttributes();
-        return atts.getValue(Constants.BUNDLE_SYMBOLICNAME) + ":" +
-            atts.getValue(Constants.BUNDLE_VERSION);
-    }
-
-    /**
-     * Installs a bundle from the given URL, doing a check if already installed, and
-     * using the {@link ResourceUtils} loader for this project (brooklyn core)
-     */
-    public static Bundle install(Framework framework, String url) throws BundleException {
-        boolean isLocal = isLocalUrl(url);
-        String localUrl = url;
-        if (!isLocal) {
-            localUrl = cacheFile(url);
-        }
-
-        try {
-            Bundle bundle = getInstalledBundle(framework, localUrl);
-            if (bundle != null) {
-                return bundle;
-            }
-    
-            // use our URL resolution so we get classpath items
-            LOG.debug("Installing bundle into {} from url: {}", framework, url);
-            InputStream stream = getUrlStream(localUrl);
-            Bundle installedBundle = framework.getBundleContext().installBundle(url, stream);
-            
-            return installedBundle;
-        } finally {
-            if (!isLocal) {
-                try {
-                    new File(new URI(localUrl)).delete();
-                } catch (URISyntaxException e) {
-                    throw Exceptions.propagate(e);
-                }
-            }
-        }
-    }
-
-    private static String cacheFile(String url) {
-        InputStream in = getUrlStream(url);
-        File cache = Os.writeToTempFile(in, "bundle-cache", "jar");
-        return cache.toURI().toString();
-    }
-
-    private static boolean isLocalUrl(String url) {
-        String protocol = Urls.getProtocol(url);
-        return "file".equals(protocol) ||
-                "classpath".equals(protocol) ||
-                "jar".equals(protocol);
-    }
-
-    private static Bundle getInstalledBundle(Framework framework, String url) {
-        Bundle bundle = framework.getBundleContext().getBundle(url);
-        if (bundle != null) {
-            return bundle;
-        }
-
-        // We now support same version installed multiple times (avail since OSGi 4.3+).
-        // However we do not support overriding *system* bundles, ie anything already on the classpath.
-        // If we wanted to disable multiple versions, see comments below, and reference to FRAMEWORK_BSNVERSION_MULTIPLE above.
-        
-        // Felix already assumes the stream is pointing to a JAR
-        JarInputStream stream;
-        try {
-            stream = new JarInputStream(getUrlStream(url));
-        } catch (IOException e) {
-            throw Exceptions.propagate(e);
-        }
-        Manifest manifest = stream.getManifest();
-        Streams.closeQuietly(stream);
-        if (manifest == null) {
-            throw new IllegalStateException("Missing manifest file in bundle or not a jar file.");
-        }
-        String versionedId = getVersionedId(manifest);
-        for (Bundle installedBundle : framework.getBundleContext().getBundles()) {
-            if (versionedId.equals(getVersionedId(installedBundle))) {
-                if (SYSTEM_BUNDLES.contains(versionedId)) {
-                    LOG.debug("Already have system bundle "+versionedId+" from "+installedBundle+"/"+installedBundle.getLocation()+" when requested "+url+"; not installing");
-                    // "System bundles" (ie things on the classpath) cannot be overridden
-                    return installedBundle;
-                } else {
-                    LOG.debug("Already have bundle "+versionedId+" from "+installedBundle+"/"+installedBundle.getLocation()+" when requested "+url+"; but it is not a system bundle so proceeding");
-                    // Other bundles can be installed multiple times. To ignore multiples and continue to use the old one, 
-                    // just return the installedBundle as done just above for system bundles.
-                }
-            }
-        }
-        return null;
-    }
-
-    private static InputStream getUrlStream(String url) {
-        return ResourceUtils.create(Osgis.class).getResourceFromUrl(url);
-    }
-    
-    public static boolean isExtensionBundle(Bundle bundle) {
-        String location = bundle.getLocation();
-        return location != null && 
-                EXTENSION_PROTOCOL.equals(Urls.getProtocol(location));
-    }
-
-    /** Takes a string which might be of the form "symbolic-name" or "symbolic-name:version" (or something else entirely)
-     * and returns a VersionedName. The versionedName.getVersion() will be null if if there was no version in the input
-     * (or returning {@link Maybe#absent()} if not valid, with a suitable error message). */
-    public static Maybe<VersionedName> parseOsgiIdentifier(String symbolicNameOptionalWithVersion) {
-        if (Strings.isBlank(symbolicNameOptionalWithVersion))
-            return Maybe.absent("OSGi identifier is blank");
-        
-        String[] parts = symbolicNameOptionalWithVersion.split(":");
-        if (parts.length>2)
-            return Maybe.absent("OSGi identifier has too many parts; max one ':' symbol");
-        
-        Version v = null;
-        if (parts.length == 2) {
-            try {
-                v = Version.parseVersion(parts[1]);
-            } catch (IllegalArgumentException e) {
-                return Maybe.absent("OSGi identifier has invalid version string ("+e.getMessage()+")");
-            }
-        }
-        
-        return Maybe.of(new VersionedName(parts[0], v));
-    }
-
-    /**
-     * The class is not used, staying for future reference.
-     * Remove after OSGi transition is completed.
-     */
-    public static class ManifestHelper {
-        
-        private static ManifestParser parse;
-        private Manifest manifest;
-        private String source;
-
-        private static final String WIRING_PACKAGE = PackageNamespace.PACKAGE_NAMESPACE;
-        
-        public static ManifestHelper forManifestContents(String contents) throws IOException, BundleException {
-            ManifestHelper result = forManifest(Streams.newInputStreamWithContents(contents));
-            result.source = contents;
-            return result;
-        }
-        
-        public static ManifestHelper forManifest(URL url) throws IOException, BundleException {
-            InputStream in = null;
-            try {
-                in = url.openStream();
-                return forManifest(in);
-            } finally {
-                if (in != null) in.close();
-            }
-        }
-        
-        public static ManifestHelper forManifest(InputStream in) throws IOException, BundleException {
-            return forManifest(new Manifest(in));
-        }
-
-        public static ManifestHelper forManifest(Manifest manifest) throws BundleException {
-            ManifestHelper result = new ManifestHelper();
-            result.manifest = manifest;
-            parse = new ManifestParser(null, null, null, new StringMap(manifest.getMainAttributes()));
-            return result;
-        }
-        
-        public String getSymbolicName() {
-            return parse.getSymbolicName();
-        }
-
-        public Version getVersion() {
-            return parse.getBundleVersion();
-        }
-
-        public String getSymbolicNameVersion() {
-            return getSymbolicName()+":"+getVersion();
-        }
-
-        public List<String> getExportedPackages() {
-            MutableList<String> result = MutableList.of();
-            for (BundleCapability c: parse.getCapabilities()) {
-                if (WIRING_PACKAGE.equals(c.getNamespace())) {
-                    result.add((String)c.getAttributes().get(WIRING_PACKAGE));
-                }
-            }
-            return result;
-        }
-        
-        @Nullable public String getSource() {
-            return source;
-        }
-        
-        public Manifest getManifest() {
-            return manifest;
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/AbstractExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/AbstractExecutionContext.java b/core/src/main/java/brooklyn/util/task/AbstractExecutionContext.java
deleted file mode 100644
index f3511d7..0000000
--- a/core/src/main/java/brooklyn/util/task/AbstractExecutionContext.java
+++ /dev/null
@@ -1,75 +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 brooklyn.util.task;
-
-import java.util.Map;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.management.ExecutionContext;
-import org.apache.brooklyn.api.management.ExecutionManager;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskAdaptable;
-
-import com.google.common.collect.Maps;
-
-public abstract class AbstractExecutionContext implements ExecutionContext {
-
-    /**
-     * Submits the given runnable/callable/task for execution (in a separate thread);
-     * supported keys in the map include: tags (add'l tags to put on the resulting task), 
-     * description (string), and others as described in the reference below
-     *   
-     * @see ExecutionManager#submit(Map, Task) 
-     */
-    @Override
-    public Task<?> submit(Map<?,?> properties, Runnable runnable) { return submitInternal(properties, runnable); }
-    
-    /** @see #submit(Map, Runnable) */
-    @Override
-    public Task<?> submit(Runnable runnable) { return submitInternal(Maps.newLinkedHashMap(), runnable); }
- 
-    /** @see #submit(Map, Runnable) */
-    @Override
-    public <T> Task<T> submit(Callable<T> callable) { return submitInternal(Maps.newLinkedHashMap(), callable); }
-    
-    /** @see #submit(Map, Runnable) */
-    @Override
-    public <T> Task<T> submit(Map<?,?> properties, Callable<T> callable) { return submitInternal(properties, callable); }
- 
-    /** @see #submit(Map, Runnable) */
-    @Override
-    public <T> Task<T> submit(TaskAdaptable<T> task) { return submitInternal(Maps.newLinkedHashMap(), task.asTask()); }
-
-    /** @see #submit(Map, Runnable) */
-    @Override
-    public <T> Task<T> submit(Map<?,?> properties, TaskAdaptable<T> task) { return submitInternal(properties, task.asTask()); }
-
-    /**
-     * Provided for compatibility
-     * 
-     * Submit is preferred if a handle on the resulting Task is desired (although a task can be passed in so this is not always necessary) 
-     *
-     * @see #submit(Map, Runnable) 
-     */
-    public void execute(Runnable r) { submit(r); }
-
-    /** does the work internally of submitting the task; note that the return value may be a wrapper task even if a task is passed in,
-     * if the execution context where the target should run is different (e.g. submitting an effector task cross-context) */
-    protected abstract <T> Task<T> submitInternal(Map<?,?> properties, Object task);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicExecutionContext.java b/core/src/main/java/brooklyn/util/task/BasicExecutionContext.java
deleted file mode 100644
index 8942a18..0000000
--- a/core/src/main/java/brooklyn/util/task/BasicExecutionContext.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 brooklyn.util.task;
-
-import java.lang.reflect.Proxy;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.management.ExecutionContext;
-import org.apache.brooklyn.api.management.ExecutionManager;
-import org.apache.brooklyn.api.management.HasTaskChildren;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskAdaptable;
-import org.apache.brooklyn.api.management.entitlement.EntitlementContext;
-import org.apache.brooklyn.core.management.entitlement.Entitlements;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.BrooklynTaskTags;
-import brooklyn.entity.basic.BrooklynTaskTags.WrappedEntity;
-import brooklyn.entity.basic.EntityInternal;
-
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-
-/**
- * A means of executing tasks against an ExecutionManager with a given bucket/set of tags pre-defined
- * (so that it can look like an {@link Executor} and also supply {@link ExecutorService#submit(Callable)}
- */
-public class BasicExecutionContext extends AbstractExecutionContext {
-    
-    private static final Logger log = LoggerFactory.getLogger(BasicExecutionContext.class);
-    
-    static final ThreadLocal<BasicExecutionContext> perThreadExecutionContext = new ThreadLocal<BasicExecutionContext>();
-    
-    public static BasicExecutionContext getCurrentExecutionContext() { return perThreadExecutionContext.get(); }
-
-    final ExecutionManager executionManager;
-    final Set<Object> tags = new LinkedHashSet<Object>();
-
-    public BasicExecutionContext(ExecutionManager executionManager) {
-        this(Collections.emptyMap(), executionManager);
-    }
-    
-    /**
-     * Supported flags are {@code tag} and {@code tags}
-     * 
-     * @see ExecutionManager#submit(Map, Task)
-     */
-    public BasicExecutionContext(Map<?, ?> flags, ExecutionManager executionManager) {
-        this.executionManager = executionManager;
-
-        if (flags.get("tag") != null) tags.add(flags.remove("tag"));
-        if (flags.containsKey("tags")) tags.addAll((Collection<?>)flags.remove("tags"));
-
-        // FIXME brooklyn-specific check, just for sanity
-        // the context tag should always be a non-proxy entity, because that is what is passed to effector tasks
-        // which may require access to internal methods
-        for (Object tag: tags) {
-            if (tag instanceof BrooklynTaskTags.WrappedEntity) {
-                if (Proxy.isProxyClass(((WrappedEntity)tag).entity.getClass())) {
-                    log.warn(""+this+" has entity proxy in "+tag);
-                }
-            }
-        }
-    }
-
-    public ExecutionManager getExecutionManager() {
-        return executionManager;
-    }
-    
-    /** returns tasks started by this context (or tasks which have all the tags on this object) */
-    public Set<Task<?>> getTasks() { return executionManager.getTasksWithAllTags((Set<?>)tags); }
-     
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    protected <T> Task<T> submitInternal(Map<?,?> propertiesQ, final Object task) {
-        if (task instanceof TaskAdaptable<?> && !(task instanceof Task<?>)) 
-            return submitInternal(propertiesQ, ((TaskAdaptable<?>)task).asTask());
-        
-        Map properties = propertiesQ;
-        if (properties.get("tags")==null) properties.put("tags", new ArrayList()); 
-        Collection taskTags = (Collection)properties.get("tags");
-        
-        // FIXME some of this is brooklyn-specific logic, should be moved to a BrooklynExecContext subclass;
-        // the issue is that we want to ensure that cross-entity calls switch execution contexts;
-        // previously it was all very messy how that was handled (and it didn't really handle it in many cases)
-        if (task instanceof Task<?>) taskTags.addAll( ((Task<?>)task).getTags() ); 
-        Entity target = BrooklynTaskTags.getWrappedEntityOfType(taskTags, BrooklynTaskTags.TARGET_ENTITY);
-        
-        if (target!=null && !tags.contains(BrooklynTaskTags.tagForContextEntity(target))) {
-            // task is switching execution context boundaries
-            /* 
-             * longer notes:
-             * you fall in to this block if the caller requests a target entity different to the current context 
-             * (e.g. where entity X is invoking an effector on Y, it will start in X's context, 
-             * but the effector should run in Y's context).
-             * 
-             * if X is invoking an effector on himself in his own context, or a sensor or other task, it will not come in to this block.
-             */
-            final ExecutionContext tc = ((EntityInternal)target).getExecutionContext();
-            if (log.isDebugEnabled())
-                log.debug("Switching task context on execution of "+task+": from "+this+" to "+target+" (in "+Tasks.current()+")");
-            
-            if (task instanceof Task<?>) {
-                final Task<T> t = (Task<T>)task;
-                if (!Tasks.isQueuedOrSubmitted(t) && (!(Tasks.current() instanceof HasTaskChildren) || 
-                        !Iterables.contains( ((HasTaskChildren)Tasks.current()).getChildren(), t ))) {
-                    // this task is switching execution context boundaries _and_ it is not a child and not yet queued,
-                    // so wrap it in a task running in this context to keep a reference to the child
-                    // (this matters when we are navigating in the GUI; without it we lose the reference to the child 
-                    // when browsing in the context of the parent)
-                    return submit(Tasks.<T>builder().name("Cross-context execution: "+t.getDescription()).dynamic(true).body(new Callable<T>() {
-                        public T call() { 
-                            return DynamicTasks.get(t); 
-                        }
-                    }).build());
-                } else {
-                    // if we are already tracked by parent, just submit it 
-                    return tc.submit(t);
-                }
-            } else {
-                // as above, but here we are definitely not a child (what we are submitting isn't even a task)
-                // (will only come here if properties defines tags including a target entity, which probably never happens) 
-                submit(Tasks.<T>builder().name("Cross-context execution").dynamic(true).body(new Callable<T>() {
-                    public T call() {
-                        if (task instanceof Callable) {
-                            return DynamicTasks.queue( Tasks.<T>builder().dynamic(false).body((Callable<T>)task).build() ).getUnchecked();
-                        } else if (task instanceof Runnable) {
-                            return DynamicTasks.queue( Tasks.<T>builder().dynamic(false).body((Runnable)task).build() ).getUnchecked();
-                        } else {
-                            throw new IllegalArgumentException("Unhandled task type: "+task+"; type="+(task!=null ? task.getClass() : "null"));
-                        }
-                    }
-                }).build());
-            }
-        }
-        
-        EntitlementContext entitlementContext = BrooklynTaskTags.getEntitlement(taskTags);
-        if (entitlementContext==null)
-        entitlementContext = Entitlements.getEntitlementContext();
-        if (entitlementContext!=null) {
-            taskTags.add(BrooklynTaskTags.tagForEntitlement(entitlementContext));
-        }
-
-        taskTags.addAll(tags);
-        
-        if (Tasks.current()!=null && BrooklynTaskTags.isTransient(Tasks.current()) 
-                && !taskTags.contains(BrooklynTaskTags.NON_TRANSIENT_TASK_TAG) && !taskTags.contains(BrooklynTaskTags.TRANSIENT_TASK_TAG)) {
-            // tag as transient if submitter is transient, unless explicitly tagged as non-transient
-            taskTags.add(BrooklynTaskTags.TRANSIENT_TASK_TAG);
-        }
-        
-        final Object startCallback = properties.get("newTaskStartCallback");
-        properties.put("newTaskStartCallback", new Function<Object,Void>() {
-            public Void apply(Object it) {
-                registerPerThreadExecutionContext();
-                if (startCallback!=null) ExecutionUtils.invoke(startCallback, it);
-                return null;
-            }});
-        
-        final Object endCallback = properties.get("newTaskEndCallback");
-        properties.put("newTaskEndCallback", new Function<Object,Void>() {
-            public Void apply(Object it) {
-                try {
-                    if (endCallback!=null) ExecutionUtils.invoke(endCallback, it);
-                } finally {
-                    clearPerThreadExecutionContext();
-                }
-                return null;
-            }});
-        
-        if (task instanceof Task) {
-            return executionManager.submit(properties, (Task)task);
-        } else if (task instanceof Callable) {
-            return executionManager.submit(properties, (Callable)task);
-        } else if (task instanceof Runnable) {
-            return (Task<T>) executionManager.submit(properties, (Runnable)task);
-        } else {
-            throw new IllegalArgumentException("Unhandled task type: task="+task+"; type="+(task!=null ? task.getClass() : "null"));
-        }
-    }
-    
-    private void registerPerThreadExecutionContext() { perThreadExecutionContext.set(this); }
-
-    private void clearPerThreadExecutionContext() { perThreadExecutionContext.remove(); }
-
-    @Override
-    public boolean isShutdown() {
-        return getExecutionManager().isShutdown();
-    }
-
-    @Override
-    public String toString() {
-        return super.toString()+"("+tags+")";
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java b/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
deleted file mode 100644
index 13d035b..0000000
--- a/core/src/main/java/brooklyn/util/task/BasicExecutionManager.java
+++ /dev/null
@@ -1,755 +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 brooklyn.util.task;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.apache.brooklyn.api.management.ExecutionManager;
-import org.apache.brooklyn.api.management.HasTaskChildren;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.api.management.TaskAdaptable;
-import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.text.Identifiers;
-
-import com.google.common.annotations.Beta;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.CaseFormat;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Sets;
-import com.google.common.util.concurrent.ExecutionList;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-
-/**
- * Manages the execution of atomic tasks and scheduled (recurring) tasks,
- * including setting tags and invoking callbacks.
- */
-public class BasicExecutionManager implements ExecutionManager {
-    private static final Logger log = LoggerFactory.getLogger(BasicExecutionManager.class);
-
-    private static final boolean RENAME_THREADS = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_RENAME_THREADS);
-    
-    private static class PerThreadCurrentTaskHolder {
-        public static final ThreadLocal<Task<?>> perThreadCurrentTask = new ThreadLocal<Task<?>>();
-    }
-
-    public static ThreadLocal<Task<?>> getPerThreadCurrentTask() {
-        return PerThreadCurrentTaskHolder.perThreadCurrentTask;
-    }
-
-    private final ThreadFactory threadFactory;
-    
-    private final ThreadFactory daemonThreadFactory;
-    
-    private final ExecutorService runner;
-        
-    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...
-
-    //access to this field AND to members in this field is synchronized, 
-    //to allow us to preserve order while guaranteeing thread-safe
-    //(but more testing is needed before we are completely sure it is thread-safe!)
-    //synch blocks are as finely grained as possible for efficiency;
-    //NB CopyOnWriteArraySet is a perf bottleneck, and the simple map makes it easier to remove when a tag is empty
-    private Map<Object,Set<Task<?>>> tasksByTag = new HashMap<Object,Set<Task<?>>>();
-    
-    private ConcurrentMap<String,Task<?>> tasksById = new ConcurrentHashMap<String,Task<?>>();
-
-    private ConcurrentMap<Object, TaskScheduler> schedulerByTag = new ConcurrentHashMap<Object, TaskScheduler>();
-
-    /** count of all tasks submitted, including finished */
-    private final AtomicLong totalTaskCount = new AtomicLong();
-    
-    /** tasks submitted but not yet done (or in cases of interruption/cancelled not yet GC'd) */
-    private Map<String,String> incompleteTaskIds = new ConcurrentHashMap<String,String>();
-    
-    /** tasks started but not yet finished */
-    private final AtomicInteger activeTaskCount = new AtomicInteger();
-    
-    private final List<ExecutionListener> listeners = new CopyOnWriteArrayList<ExecutionListener>();
-    
-    private final static ThreadLocal<String> threadOriginalName = new ThreadLocal<String>() {
-        protected String initialValue() {
-            // should not happen, as only access is in _afterEnd with a check that _beforeStart was invoked 
-            log.warn("No original name recorded for thread "+Thread.currentThread().getName()+"; task "+Tasks.current());
-            return "brooklyn-thread-pool-"+Identifiers.makeRandomId(8);
-        }
-    };
-    
-    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, 10L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), 
-                daemonThreadFactory);
-            
-        delayedRunner = new ScheduledThreadPoolExecutor(1, daemonThreadFactory);
-    }
-    
-    private final static class UncaughtExceptionHandlerImplementation implements Thread.UncaughtExceptionHandler {
-        @Override
-        public void uncaughtException(Thread t, Throwable e) {
-            log.error("Uncaught exception in thread "+t.getName(), e);
-        }
-    }
-    
-    /** 
-     * 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 UncaughtExceptionHandlerImplementation())
-                .build();
-    }
-    
-    public void shutdownNow() {
-        runner.shutdownNow();
-        delayedRunner.shutdownNow();
-    }
-    
-    public void addListener(ExecutionListener listener) {
-        listeners.add(listener);
-    }
-    
-    public void removeListener(ExecutionListener listener) {
-        listeners.remove(listener);
-    }
-    
-    /**
-     * Deletes the given tag, including all tasks using this tag.
-     * 
-     * Useful, for example, if an entity is being expunged so that we don't keep holding
-     * a reference to it as a tag.
-     */
-    public void deleteTag(Object tag) {
-        Set<Task<?>> tasks;
-        synchronized (tasksByTag) {
-            tasks = tasksByTag.remove(tag);
-        }
-        if (tasks != null) {
-            for (Task<?> task : tasks) {
-                deleteTask(task);
-            }
-        }
-    }
-
-    public void deleteTask(Task<?> task) {
-        boolean removed = deleteTaskNonRecursive(task);
-        if (!removed) return;
-        
-        if (task instanceof HasTaskChildren) {
-            List<Task<?>> children = ImmutableList.copyOf(((HasTaskChildren)task).getChildren());
-            for (Task<?> child : children) {
-                deleteTask(child);
-            }
-        }
-    }
-
-    protected boolean deleteTaskNonRecursive(Task<?> task) {
-        Set<?> tags = checkNotNull(task, "task").getTags();
-        for (Object tag : tags) {
-            synchronized (tasksByTag) {
-                Set<Task<?>> tasks = tasksWithTagLiveOrNull(tag);
-                if (tasks != null) {
-                    tasks.remove(task);
-                    if (tasks.isEmpty()) {
-                        tasksByTag.remove(tag);
-                    }
-                }
-            }
-        }
-        Task<?> removed = tasksById.remove(task.getId());
-        incompleteTaskIds.remove(task.getId());
-        if (removed!=null && removed.isSubmitted() && !removed.isDone()) {
-            log.warn("Deleting submitted task before completion: "+removed+"; this task will continue to run in the background outwith "+this+", but perhaps it should have been cancelled?");
-        }
-        return removed != null;
-    }
-
-    public boolean isShutdown() {
-        return runner.isShutdown();
-    }
-    
-    /** count of all tasks submitted */
-    public long getTotalTasksSubmitted() {
-        return totalTaskCount.get();
-    }
-    
-    /** count of tasks submitted but not ended */
-    public long getNumIncompleteTasks() {
-        return incompleteTaskIds.size();
-    }
-    
-    /** count of tasks started but not ended */
-    public long getNumActiveTasks() {
-        return activeTaskCount.get();
-    }
-
-    /** count of tasks kept in memory, often including ended tasks */
-    public long getNumInMemoryTasks() {
-        return tasksById.size();
-    }
-
-    private Set<Task<?>> tasksWithTagCreating(Object tag) {
-        Preconditions.checkNotNull(tag);
-        synchronized (tasksByTag) {
-            Set<Task<?>> result = tasksWithTagLiveOrNull(tag);
-            if (result==null) {
-                result = Collections.synchronizedSet(new LinkedHashSet<Task<?>>());
-                tasksByTag.put(tag, result);
-            }
-            return result;
-        }
-    }
-
-    /** exposes live view, for internal use only */
-    @Beta
-    public Set<Task<?>> tasksWithTagLiveOrNull(Object tag) {
-        synchronized (tasksByTag) {
-            return tasksByTag.get(tag);
-        }
-    }
-
-    @Override
-    public Task<?> getTask(String id) {
-        return tasksById.get(id);
-    }
-    
-    /** not on interface because potentially expensive */
-    public List<Task<?>> getAllTasks() {
-        // not sure if synching makes any difference; have not observed CME's yet
-        // (and so far this is only called when a CME was caught on a previous operation)
-        synchronized (tasksById) {
-            return MutableList.copyOf(tasksById.values());
-        }
-    }
-    
-    @Override
-    public Set<Task<?>> getTasksWithTag(Object tag) {
-        Set<Task<?>> result = tasksWithTagLiveOrNull(tag);
-        if (result==null) return Collections.emptySet();
-        synchronized (result) {
-            return (Set<Task<?>>)Collections.unmodifiableSet(new LinkedHashSet<Task<?>>(result));
-        }
-    }
-    
-    @Override
-    public Set<Task<?>> getTasksWithAnyTag(Iterable<?> tags) {
-        Set<Task<?>> result = new LinkedHashSet<Task<?>>();
-        Iterator<?> ti = tags.iterator();
-        while (ti.hasNext()) {
-            Set<Task<?>> tasksForTag = tasksWithTagLiveOrNull(ti.next());
-            if (tasksForTag!=null) {
-                synchronized (tasksForTag) {
-                    result.addAll(tasksForTag);
-                }
-            }
-        }
-        return Collections.unmodifiableSet(result);
-    }
-
-    /** only works with at least one tag; returns empty if no tags */
-    @Override
-    public Set<Task<?>> getTasksWithAllTags(Iterable<?> tags) {
-        //NB: for this method retrieval for multiple tags could be made (much) more efficient (if/when it is used with multiple tags!)
-        //by first looking for the least-used tag, getting those tasks, and then for each of those tasks
-        //checking whether it contains the other tags (looking for second-least used, then third-least used, etc)
-        Set<Task<?>> result = new LinkedHashSet<Task<?>>();
-        boolean first = true;
-        Iterator<?> ti = tags.iterator();
-        while (ti.hasNext()) {
-            Object tag = ti.next();
-            if (first) { 
-                first = false;
-                result.addAll(getTasksWithTag(tag));
-            } else {
-                result.retainAll(getTasksWithTag(tag));
-            }
-        }
-        return Collections.unmodifiableSet(result);
-    }
-
-    /** live view of all tasks, for internal use only */
-    @Beta
-    public Collection<Task<?>> allTasksLive() { return tasksById.values(); }
-    
-    public Set<Object> getTaskTags() { 
-        synchronized (tasksByTag) {
-            return Collections.unmodifiableSet(Sets.newLinkedHashSet(tasksByTag.keySet())); 
-        }
-    }
-
-    public Task<?> submit(Runnable r) { return submit(new LinkedHashMap<Object,Object>(1), r); }
-    public Task<?> submit(Map<?,?> flags, Runnable r) { return submit(flags, new BasicTask<Void>(flags, r)); }
-
-    public <T> Task<T> submit(Callable<T> c) { return submit(new LinkedHashMap<Object,Object>(1), c); }
-    public <T> Task<T> submit(Map<?,?> flags, Callable<T> c) { return submit(flags, new BasicTask<T>(flags, c)); }
-
-    public <T> Task<T> submit(TaskAdaptable<T> t) { return submit(new LinkedHashMap<Object,Object>(1), t); }
-    public <T> Task<T> submit(Map<?,?> flags, TaskAdaptable<T> task) {
-        if (!(task instanceof Task))
-            task = task.asTask();
-        synchronized (task) {
-            if (((TaskInternal<?>)task).getInternalFuture()!=null) return (Task<T>)task;
-            return submitNewTask(flags, (Task<T>) task);
-        }
-    }
-
-    public <T> Task<T> scheduleWith(Task<T> task) { return scheduleWith(Collections.emptyMap(), task); }
-    public <T> Task<T> scheduleWith(Map<?,?> flags, Task<T> task) {
-        synchronized (task) {
-            if (((TaskInternal<?>)task).getInternalFuture()!=null) return task;
-            return submitNewTask(flags, task);
-        }
-    }
-
-    protected Task<?> submitNewScheduledTask(final Map<?,?> flags, final ScheduledTask task) {
-        tasksById.put(task.getId(), task);
-        totalTaskCount.incrementAndGet();
-        
-        beforeSubmitScheduledTaskAllIterations(flags, task);
-        
-        return submitSubsequentScheduledTask(flags, task);
-    }
-    
-    @SuppressWarnings("unchecked")
-    protected Task<?> submitSubsequentScheduledTask(final Map<?,?> flags, final ScheduledTask task) {
-        if (!task.isDone()) {
-            task.internalFuture = delayedRunner.schedule(new ScheduledTaskCallable(task, flags),
-                task.delay.toNanoseconds(), TimeUnit.NANOSECONDS);
-        } else {
-            afterEndScheduledTaskAllIterations(flags, task);
-        }
-        return task;
-    }
-
-    protected class ScheduledTaskCallable implements Callable<Object> {
-        public ScheduledTask task;
-        public Map<?,?> flags;
-
-        public ScheduledTaskCallable(ScheduledTask task, Map<?, ?> flags) {
-            this.task = task;
-            this.flags = flags;
-        }
-
-        @SuppressWarnings({ "rawtypes", "unchecked" })
-        public Object call() {
-            if (task.startTimeUtc==-1) task.startTimeUtc = System.currentTimeMillis();
-            TaskInternal<?> taskScheduled = null;
-            try {
-                beforeStartScheduledTaskSubmissionIteration(flags, task);
-                taskScheduled = (TaskInternal<?>) task.newTask();
-                taskScheduled.setSubmittedByTask(task);
-                final Callable<?> oldJob = taskScheduled.getJob();
-                final TaskInternal<?> taskScheduledF = taskScheduled;
-                taskScheduled.setJob(new Callable() { public Object call() {
-                    boolean resubmitted = false;
-                    task.recentRun = taskScheduledF;
-                    try {
-                        synchronized (task) {
-                            task.notifyAll();
-                        }
-                        Object result;
-                        try {
-                            result = oldJob.call();
-                        } catch (Exception e) {
-                            if (!Tasks.isInterrupted()) {
-                                log.warn("Error executing "+oldJob+" (scheduled job of "+task+" - "+task.getDescription()+"); cancelling scheduled execution", e);
-                            } else {
-                                log.debug("Interrupted executing "+oldJob+" (scheduled job of "+task+" - "+task.getDescription()+"); cancelling scheduled execution: "+e);
-                            }
-                            throw Exceptions.propagate(e);
-                        }
-                        task.runCount++;
-                        if (task.period!=null && !task.isCancelled()) {
-                            task.delay = task.period;
-                            submitSubsequentScheduledTask(flags, task);
-                            resubmitted = true;
-                        }
-                        return result;
-                    } finally {
-                        // do in finally block in case we were interrupted
-                        if (!resubmitted)
-                            afterEndScheduledTaskAllIterations(flags, task);
-                    }
-                }});
-                task.nextRun = taskScheduled;
-                BasicExecutionContext ec = BasicExecutionContext.getCurrentExecutionContext();
-                if (ec!=null) return ec.submit(taskScheduled);
-                else return submit(taskScheduled);
-            } finally {
-                afterEndScheduledTaskSubmissionIteration(flags, task, taskScheduled);
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "ScheduledTaskCallable["+task+","+flags+"]";
-        }
-    }
-
-    private final class SubmissionCallable<T> implements Callable<T> {
-        private final Map<?, ?> flags;
-        private final Task<T> task;
-
-        private SubmissionCallable(Map<?, ?> flags, Task<T> task) {
-            this.flags = flags;
-            this.task = task;
-        }
-
-        public T call() {
-            try {
-                T result = null;
-                Throwable error = null;
-                String oldThreadName = Thread.currentThread().getName();
-                try {
-                    if (RENAME_THREADS) {
-                        String newThreadName = oldThreadName+"-"+task.getDisplayName()+
-                            "["+task.getId().substring(0, 8)+"]";
-                        Thread.currentThread().setName(newThreadName);
-                    }
-                    beforeStartAtomicTask(flags, task);
-                    if (!task.isCancelled()) {
-                        result = ((TaskInternal<T>)task).getJob().call();
-                    } else throw new CancellationException();
-                } catch(Throwable e) {
-                    error = e;
-                } finally {
-                    if (RENAME_THREADS) {
-                        Thread.currentThread().setName(oldThreadName);
-                    }
-                    afterEndAtomicTask(flags, task);
-                }
-                if (error!=null) {
-                    /* we throw, after logging debug.
-                     * the throw means the error is available for task submitters to monitor.
-                     * however it is possible no one is monitoring it, in which case we will have debug logging only for errors.
-                     * (the alternative, of warn-level logging in lots of places where we don't want it, seems worse!) 
-                     */
-                    if (log.isDebugEnabled()) {
-                        // debug only here, because most submitters will handle failures
-                        log.debug("Exception running task "+task+" (rethrowing): "+error.getMessage(), error);
-                        if (log.isTraceEnabled())
-                            log.trace("Trace for exception running task "+task+" (rethrowing): "+error.getMessage(), error);
-                    }
-                    throw Exceptions.propagate(error);
-                }
-                return result;
-            } finally {
-                ((TaskInternal<?>)task).runListeners();
-            }
-        }
-
-        @Override
-        public String toString() {
-            return "BEM.call("+task+","+flags+")";
-        }
-    }
-
-    private final static class ListenableForwardingFutureForTask<T> extends ListenableForwardingFuture<T> {
-        private final Task<T> task;
-
-        private ListenableForwardingFutureForTask(Future<T> delegate, ExecutionList list, Task<T> task) {
-            super(delegate, list);
-            this.task = task;
-        }
-
-        @Override
-        public boolean cancel(boolean mayInterruptIfRunning) {
-            boolean result = false;
-            if (!task.isCancelled()) result |= task.cancel(mayInterruptIfRunning);
-            result |= super.cancel(mayInterruptIfRunning);
-            ((TaskInternal<?>)task).runListeners();
-            return result;
-        }
-    }
-
-    private final class SubmissionListenerToCallOtherListeners<T> implements Runnable {
-        private final Task<T> task;
-
-        private SubmissionListenerToCallOtherListeners(Task<T> task) {
-            this.task = task;
-        }
-
-        @Override
-        public void run() {
-            try {
-                ((TaskInternal<?>)task).runListeners();
-            } catch (Exception e) {
-                log.warn("Error running task listeners for task "+task+" done", e);
-            }
-            
-            for (ExecutionListener listener : listeners) {
-                try {
-                    listener.onTaskDone(task);
-                } catch (Exception e) {
-                    log.warn("Error running execution listener "+listener+" of task "+task+" done", e);
-                }
-            }
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    protected <T> Task<T> submitNewTask(final Map<?,?> flags, final Task<T> task) {
-        if (task instanceof ScheduledTask)
-            return (Task<T>) submitNewScheduledTask(flags, (ScheduledTask)task);
-        
-        tasksById.put(task.getId(), task);
-        totalTaskCount.incrementAndGet();
-        
-        beforeSubmitAtomicTask(flags, task);
-        
-        if (((TaskInternal<T>)task).getJob() == null) 
-            throw new NullPointerException("Task "+task+" submitted with with null job: job must be supplied.");
-        
-        Callable<T> job = new SubmissionCallable<T>(flags, task);
-        
-        // If there's a scheduler then use that; otherwise execute it directly
-        Set<TaskScheduler> schedulers = null;
-        for (Object tago: task.getTags()) {
-            TaskScheduler scheduler = getTaskSchedulerForTag(tago);
-            if (scheduler!=null) {
-                if (schedulers==null) schedulers = new LinkedHashSet<TaskScheduler>(2);
-                schedulers.add(scheduler);
-            }
-        }
-        Future<T> future;
-        if (schedulers!=null && !schedulers.isEmpty()) {
-            if (schedulers.size()>1) log.warn("multiple schedulers detected, using only the first, for "+task+": "+schedulers);
-            future = schedulers.iterator().next().submit(job);
-        } else {
-            future = runner.submit(job);
-        }
-        // on completion, listeners get triggered above; here, below we ensure they get triggered on cancel
-        // (and we make sure the same ExecutionList is used in the future as in the task)
-        ListenableFuture<T> listenableFuture = new ListenableForwardingFutureForTask<T>(future, ((TaskInternal<T>)task).getListeners(), task);
-        // doesn't matter whether the listener is added to the listenableFuture or the task,
-        // except that for the task we can more easily wrap it so that it only logs debug if the executor is shutdown
-        // (avoid a bunch of ugly warnings in tests which start and stop things a lot!)
-        // [probably even nicer to run this in the same thread, it doesn't do much; but that is messier to implement]
-        ((TaskInternal<T>)task).addListener(new SubmissionListenerToCallOtherListeners<T>(task), runner);
-        
-        ((TaskInternal<T>)task).initInternalFuture(listenableFuture);
-        
-        return task;
-    }
-    
-    protected void beforeSubmitScheduledTaskAllIterations(Map<?,?> flags, Task<?> task) {
-        internalBeforeSubmit(flags, task);
-    }
-    protected void beforeSubmitAtomicTask(Map<?,?> flags, Task<?> task) {
-        internalBeforeSubmit(flags, task);
-    }
-    /** invoked when a task is submitted */
-    protected void internalBeforeSubmit(Map<?,?> flags, Task<?> task) {
-        incompleteTaskIds.put(task.getId(), task.getId());
-        
-        Task<?> currentTask = Tasks.current();
-        if (currentTask!=null) ((TaskInternal<?>)task).setSubmittedByTask(currentTask);
-        ((TaskInternal<?>)task).setSubmitTimeUtc(System.currentTimeMillis());
-        
-        if (flags.get("tag")!=null) ((TaskInternal<?>)task).getMutableTags().add(flags.remove("tag"));
-        if (flags.get("tags")!=null) ((TaskInternal<?>)task).getMutableTags().addAll((Collection<?>)flags.remove("tags"));
-
-        for (Object tag: ((TaskInternal<?>)task).getTags()) {
-            tasksWithTagCreating(tag).add(task);
-        }
-    }
-
-    protected void beforeStartScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> task) {
-        internalBeforeStart(flags, task);
-    }
-    protected void beforeStartAtomicTask(Map<?,?> flags, Task<?> task) {
-        internalBeforeStart(flags, task);
-    }
-    
-    /** invoked in a task's thread when a task is starting to run (may be some time after submitted), 
-     * but before doing any of the task's work, so that we can update bookkeeping and notify callbacks */
-    protected void internalBeforeStart(Map<?,?> flags, Task<?> task) {
-        activeTaskCount.incrementAndGet();
-        
-        //set thread _before_ start time, so we won't get a null thread when there is a start-time
-        if (log.isTraceEnabled()) log.trace(""+this+" beforeStart, task: "+task);
-        if (!task.isCancelled()) {
-            Thread thread = Thread.currentThread();
-            ((TaskInternal<?>)task).setThread(thread);
-            if (RENAME_THREADS) {
-                threadOriginalName.set(thread.getName());
-                String newThreadName = "brooklyn-" + CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, task.getDisplayName().replace(" ", "")) + "-" + task.getId().substring(0, 8);
-                thread.setName(newThreadName);
-            }
-            PerThreadCurrentTaskHolder.perThreadCurrentTask.set(task);
-            ((TaskInternal<?>)task).setStartTimeUtc(System.currentTimeMillis());
-        }
-        ExecutionUtils.invoke(flags.get("newTaskStartCallback"), task);
-    }
-
-    /** normally (if not interrupted) called once for each call to {@link #beforeSubmitScheduledTaskAllIterations(Map, Task)} */
-    protected void afterEndScheduledTaskAllIterations(Map<?,?> flags, Task<?> task) {
-        internalAfterEnd(flags, task, false, true);
-    }
-    /** called once for each call to {@link #beforeStartScheduledTaskSubmissionIteration(Map, Task)},
-     * with a per-iteration task generated by the surrounding scheduled task */
-    protected void afterEndScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> scheduledTask, Task<?> taskIteration) {
-        internalAfterEnd(flags, scheduledTask, true, false);
-    }
-    /** called once for each task on which {@link #beforeStartAtomicTask(Map, Task)} is invoked,
-     * and normally (if not interrupted prior to start) 
-     * called once for each task on which {@link #beforeSubmitAtomicTask(Map, Task)} */
-    protected void afterEndAtomicTask(Map<?,?> flags, Task<?> task) {
-        internalAfterEnd(flags, task, true, true);
-    }
-    /** normally (if not interrupted) called once for each call to {@link #internalBeforeSubmit(Map, Task)},
-     * and, for atomic tasks and scheduled-task submission iterations where 
-     * always called once if {@link #internalBeforeStart(Map, Task)} is invoked and in the same thread as that method */
-    protected void internalAfterEnd(Map<?,?> flags, Task<?> task, boolean startedInThisThread, boolean isEndingAllIterations) {
-        if (log.isTraceEnabled()) log.trace(this+" afterEnd, task: "+task);
-        if (startedInThisThread) {
-            activeTaskCount.decrementAndGet();
-        }
-        if (isEndingAllIterations) {
-            incompleteTaskIds.remove(task.getId());
-            ExecutionUtils.invoke(flags.get("newTaskEndCallback"), task);
-            ((TaskInternal<?>)task).setEndTimeUtc(System.currentTimeMillis());
-        }
-
-        if (startedInThisThread) {
-            PerThreadCurrentTaskHolder.perThreadCurrentTask.remove();
-            //clear thread _after_ endTime set, so we won't get a null thread when there is no end-time
-            if (RENAME_THREADS && startedInThisThread) {
-                Thread thread = task.getThread();
-                if (thread==null) {
-                    log.warn("BasicTask.afterEnd invoked without corresponding beforeStart");
-                } else {
-                    thread.setName(threadOriginalName.get());
-                    threadOriginalName.remove();
-                }
-            }
-            ((TaskInternal<?>)task).setThread(null);
-        }
-        synchronized (task) { task.notifyAll(); }
-    }
-
-    public TaskScheduler getTaskSchedulerForTag(Object tag) {
-        return schedulerByTag.get(tag);
-    }
-    
-    public void setTaskSchedulerForTag(Object tag, Class<? extends TaskScheduler> scheduler) {
-        synchronized (schedulerByTag) {
-            TaskScheduler old = getTaskSchedulerForTag(tag);
-            if (old!=null) {
-                if (scheduler.isAssignableFrom(old.getClass())) {
-                    /* already have such an instance */
-                    return;
-                }
-                //might support multiple in future...
-                throw new IllegalStateException("Not allowed to set multiple TaskSchedulers on ExecutionManager tag (tag "+tag+", has "+old+", setting new "+scheduler+")");
-            }
-            try {
-                TaskScheduler schedulerI = scheduler.newInstance();
-                // allow scheduler to have a nice name, for logging etc
-                if (schedulerI instanceof CanSetName) ((CanSetName)schedulerI).setName(""+tag);
-                setTaskSchedulerForTag(tag, schedulerI);
-            } catch (InstantiationException e) {
-                throw Exceptions.propagate(e);
-            } catch (IllegalAccessException e) {
-                throw Exceptions.propagate(e);
-            }
-        }
-    }
-    
-    /**
-     * Defines a {@link TaskScheduler} to run on all subsequently submitted jobs with the given tag.
-     *
-     * Maximum of one allowed currently. Resubmissions of the same scheduler (or scheduler class)
-     * allowed. If changing, you must call {@link #clearTaskSchedulerForTag(Object)} between the two.
-     *
-     * @see #setTaskSchedulerForTag(Object, Class)
-     */
-    public void setTaskSchedulerForTag(Object tag, TaskScheduler scheduler) {
-        synchronized (schedulerByTag) {
-            scheduler.injectExecutor(runner);
-
-            Object old = schedulerByTag.put(tag, scheduler);
-            if (old!=null && old!=scheduler) {
-                //might support multiple in future...
-                throw new IllegalStateException("Not allowed to set multiple TaskSchedulers on ExecutionManager tag (tag "+tag+")");
-            }
-        }
-    }
-
-    /**
-     * Forgets that any scheduler was associated with a tag.
-     *
-     * @see #setTaskSchedulerForTag(Object, TaskScheduler)
-     * @see #setTaskSchedulerForTag(Object, Class)
-     */
-    public boolean clearTaskSchedulerForTag(Object tag) {
-        synchronized (schedulerByTag) {
-            Object old = schedulerByTag.remove(tag);
-            return (old!=null);
-        }
-    }
-    
-    @VisibleForTesting
-    public ConcurrentMap<Object, TaskScheduler> getSchedulerByTag() {
-        return schedulerByTag;
-    }
-
-}


[24/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/http/HttpTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/http/HttpTool.java b/core/src/main/java/org/apache/brooklyn/core/util/http/HttpTool.java
new file mode 100644
index 0000000..43b1aee
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/http/HttpTool.java
@@ -0,0 +1,387 @@
+/*
+ * 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.util.http;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.net.URI;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeSocketFactory;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.conn.ssl.X509HostnameVerifier;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.client.LaxRedirectStrategy;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.crypto.SslTrustUtils;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.net.URLParamEncoder;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+
+public class HttpTool {
+
+    private static final Logger LOG = LoggerFactory.getLogger(HttpTool.class);
+
+    /** Apache HTTP commons utility for trusting all.
+     * <p>
+     * For generic java HTTP usage, see {@link SslTrustUtils#trustAll(java.net.URLConnection)} 
+     * and static constants in the same class. */
+    public static class TrustAllStrategy implements TrustStrategy {
+        @Override
+        public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+            return true;
+        }
+    }
+
+    public static HttpClientBuilder httpClientBuilder() {
+        return new HttpClientBuilder();
+    }
+    
+    public static class HttpClientBuilder {
+        private ClientConnectionManager clientConnectionManager;
+        private HttpParams httpParams;
+        private URI uri;
+        private Integer port;
+        private Credentials credentials;
+        private boolean laxRedirect;
+        private Boolean https;
+        private SchemeSocketFactory socketFactory;
+        private ConnectionReuseStrategy reuseStrategy;
+        private boolean trustAll;
+        private boolean trustSelfSigned;
+
+        public HttpClientBuilder clientConnectionManager(ClientConnectionManager val) {
+            this.clientConnectionManager = checkNotNull(val, "clientConnectionManager");
+            return this;
+        }
+        public HttpClientBuilder httpParams(HttpParams val) {
+            checkState(httpParams == null, "Must not call httpParams multiple times, or after other methods like connectionTimeout");
+            this.httpParams = checkNotNull(val, "httpParams");
+            return this;
+        }
+        public HttpClientBuilder connectionTimeout(Duration val) {
+            if (httpParams == null) httpParams = new BasicHttpParams();
+            long millis = checkNotNull(val, "connectionTimeout").toMilliseconds();
+            if (millis > Integer.MAX_VALUE) throw new IllegalStateException("HttpClient only accepts upto max-int millis for connectionTimeout, but given "+val);
+            HttpConnectionParams.setConnectionTimeout(httpParams, (int) millis);
+            return this;
+        }
+        public HttpClientBuilder socketTimeout(Duration val) {
+            if (httpParams == null) httpParams = new BasicHttpParams();
+            long millis = checkNotNull(val, "socketTimeout").toMilliseconds();
+            if (millis > Integer.MAX_VALUE) throw new IllegalStateException("HttpClient only accepts upto max-int millis for socketTimeout, but given "+val);
+            HttpConnectionParams.setSoTimeout(httpParams, (int) millis);
+            return this;
+        }
+        public HttpClientBuilder reuseStrategy(ConnectionReuseStrategy val) {
+            this.reuseStrategy = checkNotNull(val, "reuseStrategy");
+            return this;
+        }
+        public HttpClientBuilder uri(String val) {
+            return uri(URI.create(checkNotNull(val, "uri")));
+        }
+        public HttpClientBuilder uri(URI val) {
+            this.uri = checkNotNull(val, "uri");
+            if (https == null) https = ("https".equalsIgnoreCase(uri.getScheme()));
+            return this;
+        }
+        public HttpClientBuilder port(int val) {
+            this.port = val;
+            return this;
+        }
+        public HttpClientBuilder credentials(Credentials val) {
+            this.credentials = checkNotNull(val, "credentials");
+            return this;
+        }
+        public void credential(Optional<Credentials> val) {
+            if (val.isPresent()) credentials = val.get();
+        }
+        /** similar to curl --post301 -L` */
+        public HttpClientBuilder laxRedirect(boolean val) {
+            this.laxRedirect = val;
+            return this;
+        }
+        public HttpClientBuilder https(boolean val) {
+            this.https = val;
+            return this;
+        }
+        public HttpClientBuilder socketFactory(SchemeSocketFactory val) {
+            this.socketFactory = checkNotNull(val, "socketFactory");
+            return this;
+        }
+        public HttpClientBuilder trustAll() {
+            this.trustAll = true;
+            return this;
+        }
+        public HttpClientBuilder trustSelfSigned() {
+            this.trustSelfSigned = true;
+            return this;
+        }
+        public HttpClient build() {
+            final DefaultHttpClient httpClient = new DefaultHttpClient(clientConnectionManager);
+            httpClient.setParams(httpParams);
+    
+            // support redirects for POST (similar to `curl --post301 -L`)
+            // http://stackoverflow.com/questions/3658721/httpclient-4-error-302-how-to-redirect
+            if (laxRedirect) {
+                httpClient.setRedirectStrategy(new LaxRedirectStrategy());
+            }
+            if (reuseStrategy != null) {
+                httpClient.setReuseStrategy(reuseStrategy);
+            }
+            if (https == Boolean.TRUE || (uri!=null && uri.toString().startsWith("https:"))) {
+                try {
+                    if (port == null) {
+                        port = (uri != null && uri.getPort() >= 0) ? uri.getPort() : 443;
+                    }
+                    if (socketFactory == null) {
+                        if (trustAll) {
+                            TrustStrategy trustStrategy = new TrustAllStrategy();
+                            X509HostnameVerifier hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
+                            socketFactory = new SSLSocketFactory(trustStrategy, hostnameVerifier);
+                        } else if (trustSelfSigned) {
+                            TrustStrategy trustStrategy = new TrustSelfSignedStrategy();
+                            X509HostnameVerifier hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
+                            socketFactory = new SSLSocketFactory(trustStrategy, hostnameVerifier);
+                        } else {
+                            // Using default https scheme: based on default java truststore, which is pretty strict!
+                        }
+                    }
+                    if (socketFactory != null) {
+                        Scheme sch = new Scheme("https", port, socketFactory);
+                        httpClient.getConnectionManager().getSchemeRegistry().register(sch);
+                    }
+                } catch (Exception e) {
+                    LOG.warn("Error setting trust for uri {}", uri);
+                    throw Exceptions.propagate(e);
+                }
+            }
+    
+            // Set credentials
+            if (uri != null && credentials != null) {
+                String hostname = uri.getHost();
+                int port = uri.getPort();
+                httpClient.getCredentialsProvider().setCredentials(new AuthScope(hostname, port), credentials);
+            }
+            if (uri==null && credentials!=null) {
+                LOG.warn("credentials have no effect in builder unless URI for host is specified");
+            }
+    
+            return httpClient;
+        }
+    }
+
+    protected static abstract class HttpRequestBuilder<B extends HttpRequestBuilder<B, R>, R extends HttpRequest> {
+        protected R req;
+        
+        protected HttpRequestBuilder(R req) {
+            this.req = req;
+        }
+        @SuppressWarnings("unchecked")
+        protected B self() {
+            return (B) this;
+        }
+        public B headers(Map<String,String> headers) {
+            if (headers!=null) {
+                for (Map.Entry<String,String> entry : headers.entrySet()) {
+                    req.addHeader(entry.getKey(), entry.getValue());
+                }
+            }
+            return self();
+        }
+        public B headers(Multimap<String,String> headers) {
+            if (headers!=null) {
+                for (Map.Entry<String,String> entry : headers.entries()) {
+                    req.addHeader(entry.getKey(), entry.getValue());
+                }
+            }
+            return self();
+        }
+        public R build() {
+            return req;
+        }
+    }
+    
+    protected static abstract class HttpEntityEnclosingRequestBaseBuilder<B extends HttpEntityEnclosingRequestBaseBuilder<B,R>, R extends HttpEntityEnclosingRequestBase> extends HttpRequestBuilder<B, R> {
+        protected HttpEntityEnclosingRequestBaseBuilder(R req) {
+            super(req);
+        }
+        public B body(byte[] body) {
+            if (body != null) {
+                HttpEntity httpEntity = new ByteArrayEntity(body);
+                req.setEntity(httpEntity);
+            }
+            return self();
+        }
+    }
+    
+    public static class HttpGetBuilder extends HttpRequestBuilder<HttpGetBuilder, HttpGet> {
+        public HttpGetBuilder(URI uri) {
+            super(new HttpGet(uri));
+        }
+    }
+    
+    public static class HttpHeadBuilder extends HttpRequestBuilder<HttpHeadBuilder, HttpHead> {
+        public HttpHeadBuilder(URI uri) {
+            super(new HttpHead(uri));
+        }
+    }
+    
+    public static class HttpDeleteBuilder extends HttpRequestBuilder<HttpDeleteBuilder, HttpDelete> {
+        public HttpDeleteBuilder(URI uri) {
+            super(new HttpDelete(uri));
+        }
+    }
+    
+    public static class HttpPostBuilder extends HttpEntityEnclosingRequestBaseBuilder<HttpPostBuilder, HttpPost> {
+        HttpPostBuilder(URI uri) {
+            super(new HttpPost(uri));
+        }
+    }
+
+    public static class HttpFormPostBuilder extends HttpRequestBuilder<HttpFormPostBuilder, HttpPost> {
+        HttpFormPostBuilder(URI uri) {
+            super(new HttpPost(uri));
+        }
+
+        public HttpFormPostBuilder params(Map<String, String> params) {
+            if (params != null) {
+                Collection<NameValuePair> httpParams = new ArrayList<NameValuePair>(params.size());
+                for (Entry<String, String> param : params.entrySet()) {
+                    httpParams.add(new BasicNameValuePair(param.getKey(), param.getValue()));
+                }
+                req.setEntity(new UrlEncodedFormEntity(httpParams));
+            }
+            return self();
+        }
+    }
+
+    public static class HttpPutBuilder extends HttpEntityEnclosingRequestBaseBuilder<HttpPutBuilder, HttpPut> {
+        public HttpPutBuilder(URI uri) {
+            super(new HttpPut(uri));
+        }
+    }
+    
+    public static HttpToolResponse httpGet(HttpClient httpClient, URI uri, Map<String,String> headers) {
+        HttpGet req = new HttpGetBuilder(uri).headers(headers).build();
+        return execAndConsume(httpClient, req);
+    }
+
+    public static HttpToolResponse httpPost(HttpClient httpClient, URI uri, Map<String,String> headers, byte[] body) {
+        HttpPost req = new HttpPostBuilder(uri).headers(headers).body(body).build();
+        return execAndConsume(httpClient, req);
+    }
+
+    public static HttpToolResponse httpPut(HttpClient httpClient, URI uri, Map<String, String> headers, byte[] body) {
+        HttpPut req = new HttpPutBuilder(uri).headers(headers).body(body).build();
+        return execAndConsume(httpClient, req);
+    }
+
+    public static HttpToolResponse httpPost(HttpClient httpClient, URI uri, Map<String,String> headers, Map<String, String> params) {
+        HttpPost req = new HttpFormPostBuilder(uri).headers(headers).params(params).build();
+        return execAndConsume(httpClient, req);
+    }
+
+    public static HttpToolResponse httpDelete(HttpClient httpClient, URI uri, Map<String,String> headers) {
+        HttpDelete req = new HttpDeleteBuilder(uri).headers(headers).build();
+        return execAndConsume(httpClient, req);
+    }
+    
+    public static HttpToolResponse httpHead(HttpClient httpClient, URI uri, Map<String,String> headers) {
+        HttpHead req = new HttpHeadBuilder(uri).headers(headers).build();
+        return execAndConsume(httpClient, req);
+    }
+    
+    public static HttpToolResponse execAndConsume(HttpClient httpClient, HttpUriRequest req) {
+        long startTime = System.currentTimeMillis();
+        try {
+            HttpResponse httpResponse = httpClient.execute(req);
+            
+            try {
+                return new HttpToolResponse(httpResponse, startTime);
+            } finally {
+                EntityUtils.consume(httpResponse.getEntity());
+            }
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    public static boolean isStatusCodeHealthy(int code) { return (code>=200 && code<=299); }
+
+    public static String toBasicAuthorizationValue(UsernamePasswordCredentials credentials) {
+        return "Basic "+Base64.encodeBase64String( (credentials.getUserName()+":"+credentials.getPassword()).getBytes() );
+    }
+
+    public static String encodeUrlParams(Map<?,?> data) {
+        if (data==null) return "";
+        Iterable<String> args = Iterables.transform(data.entrySet(), 
+            new Function<Map.Entry<?,?>,String>() {
+            @Override public String apply(Map.Entry<?,?> entry) {
+                Object k = entry.getKey();
+                Object v = entry.getValue();
+                return URLParamEncoder.encode(Strings.toString(k)) + (v != null ? "=" + URLParamEncoder.encode(Strings.toString(v)) : "");
+            }
+        });
+        return Joiner.on("&").join(args);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/http/HttpToolResponse.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/http/HttpToolResponse.java b/core/src/main/java/org/apache/brooklyn/core/util/http/HttpToolResponse.java
new file mode 100644
index 0000000..97e7793
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/http/HttpToolResponse.java
@@ -0,0 +1,185 @@
+/*
+ * 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.util.http;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.event.feed.http.HttpPollValue;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.google.common.io.ByteStreams;
+
+public class HttpToolResponse implements HttpPollValue {
+
+    private static final Logger log = LoggerFactory.getLogger(HttpToolResponse.class);
+    
+    private final Object mutex = new Object();
+    private final HttpResponse response;
+    private final long startTime;
+    private final long durationMillisOfFirstResponse;
+    private final long durationMillisOfFullContent;
+    private int responseCode;
+    private String reasonPhrase;
+    private Map<String,List<String>> headerLists;
+    private byte[] content;
+
+
+    public HttpToolResponse(HttpResponse response, long startTime) {
+        this.response = response;
+        this.startTime = startTime; 
+        
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            HttpEntity entity = response.getEntity();
+            if (entity != null) {
+                entity.getContentLength();
+                durationMillisOfFirstResponse = Duration.sinceUtc(startTime).toMilliseconds();
+
+                ByteStreams.copy(entity.getContent(), out);
+                content = out.toByteArray();
+
+                entity.getContentLength();
+            } else {
+                durationMillisOfFirstResponse = Duration.sinceUtc(startTime).toMilliseconds();
+                content = new byte[0];
+            }
+            durationMillisOfFullContent = Duration.sinceUtc(startTime).toMilliseconds();
+            if (log.isTraceEnabled())
+                log.trace("HttpPollValue latency "+Time.makeTimeStringRounded(durationMillisOfFirstResponse)+" / "+Time.makeTimeStringRounded(durationMillisOfFullContent)+", content size "+content.length);
+        } catch (IOException e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
+    public HttpToolResponse(int responseCode, Map<String,? extends List<String>> headers, byte[] content,
+            long startTime, long durationMillisOfFirstResponse, long durationMillisOfFullContent) {
+        this.response = null;
+        this.responseCode = responseCode;
+        this.headerLists = ImmutableMap.copyOf(headers);
+        this.content = content;
+        this.startTime = startTime;
+        this.durationMillisOfFirstResponse = durationMillisOfFirstResponse;
+        this.durationMillisOfFullContent = durationMillisOfFullContent;
+    }
+    
+    public int getResponseCode() {
+        synchronized (mutex) {
+            if (responseCode == 0) {
+                responseCode = response.getStatusLine().getStatusCode();
+            }
+        }
+        return responseCode;
+    }
+
+    public String getReasonPhrase() {
+        synchronized (mutex) {
+            if (reasonPhrase == null) {
+                reasonPhrase = response.getStatusLine().getReasonPhrase();
+            }
+        }
+        return reasonPhrase;
+    }
+
+    /** returns the timestamp (millis since 1970) when this request was started */ 
+    public long getStartTime() {
+        return startTime;
+    }
+    
+    /** returns latency, in milliseconds, if value was initialized with a start time */
+    public long getLatencyFullContent() {
+        return durationMillisOfFullContent;
+    }
+    
+    /** returns latency, in milliseconds, before response started coming in */
+    public long getLatencyFirstResponse() {
+        return durationMillisOfFirstResponse;
+    }
+    
+    public Map<String, List<String>> getHeaderLists() {
+        synchronized (mutex) {
+            if (headerLists == null) {
+                Map<String, List<String>> headerListsMutable = Maps.newLinkedHashMap();
+                for (Header header : response.getAllHeaders()) {
+                    List<String> vals = headerListsMutable.get(header.getName());
+                    if (vals == null) {
+                        vals = new ArrayList<String>();
+                        headerListsMutable.put(header.getName(), vals);
+                    }
+                    vals.add(header.getValue());
+                }
+                headerLists = Collections.unmodifiableMap(headerListsMutable);
+            }
+        }
+        return headerLists;
+    }
+    
+    public byte[] getContent() {
+        synchronized (mutex) {
+            if (content == null) {
+                InputStream in = null;
+                try {
+                    in = response.getEntity().getContent();
+                    ByteArrayOutputStream out = new ByteArrayOutputStream();
+                    ByteStreams.copy(in, out);
+                    content = out.toByteArray();
+                } catch (IOException e) {
+                    throw Throwables.propagate(e);
+                } finally {
+                    Streams.closeQuietly(in);
+                }
+            }
+        }
+        return content;
+    }
+
+    public String getContentAsString() {
+        return new String(getContent());
+    }
+    
+    public Maybe<HttpResponse> getResponse() {
+        return Maybe.fromNullable(response);
+    }
+
+    @Override
+    public String toString() {
+        return Objects.toStringHelper(getClass())
+                .add("responseCode", responseCode)
+                .toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ConfigKeySelfExtracting.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ConfigKeySelfExtracting.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ConfigKeySelfExtracting.java
new file mode 100644
index 0000000..a1d85ca
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ConfigKeySelfExtracting.java
@@ -0,0 +1,41 @@
+/*
+ * 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.util.internal;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.management.ExecutionContext;
+
+import brooklyn.config.ConfigKey;
+
+/** Interface for resolving key values; typically implemented by the config key,
+ * but discouraged for external usage.
+ */
+public interface ConfigKeySelfExtracting<T> extends ConfigKey<T> {
+
+    /**
+     * Extracts the value for this config key from the given map.
+     */
+    T extractValue(Map<?,?> configMap, ExecutionContext exec);
+
+    /**
+     * @return True if there is an entry in the configMap that could be extracted
+     */
+    boolean isSet(Map<?,?> configMap);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/Repeater.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/Repeater.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/Repeater.java
new file mode 100644
index 0000000..39e79da
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/Repeater.java
@@ -0,0 +1,370 @@
+/*
+ * 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.util.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.JavaGroovyEquivalents;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.internal.TimeExtras;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.Callables;
+
+/**
+ * Simple DSL to repeat a fragment of code periodically until a condition is satisfied.
+ *
+ * In its simplest case, it is passed two {@link groovy.lang.Closure}s / {@link Callable} - 
+ * the first is executed, then the second. If the second closure returns false, the loop
+ * is repeated; if true, it finishes. Further customization can be applied to set the period 
+ * between loops and place a maximum limit on how long the loop should run for.
+ * <p>
+ * It is configured in a <em>fluent</em> manner. For example, in Groovy:
+ * <pre>
+ * {@code
+ * Repeater.create("Wait until the Frobnitzer is ready")
+ *     .repeat {
+ *         status = frobnitzer.getStatus()
+ *     }
+ *     .until {
+ *         status == "Ready" || status == "Failed"
+ *     }
+ *     .limitIterationsTo(30)
+ *     .run()
+ * }
+ * </pre>
+ * 
+ * Or in Java:
+ * <pre>
+ * {@code
+ * Repeater.create("Wait until the Frobnitzer is ready")
+ *     .until(new Callable<Boolean>() {
+ *              public Boolean call() {
+ *                  String status = frobnitzer.getStatus()
+ *                  return "Ready".equals(status) || "Failed".equals(status);
+ *              }})
+ *     .limitIterationsTo(30)
+ *     .run()
+ * }
+ * </pre>
+ * 
+ * @deprecated since 0.7.0, use {@link brooklyn.util.repeat.Repeater} instead
+ */
+@Deprecated
+public class Repeater {
+    
+    // TODO Was converted to Java, from groovy. Needs thorough review and improvements
+    // to use idiomatic java
+    
+    private static final Logger log = LoggerFactory.getLogger(Repeater.class);
+
+    static { TimeExtras.init(); }
+
+    @SetFromFlag
+    private String description;
+    private Callable<?> body = Callables.returning(null);
+    private Callable<Boolean> exitCondition;
+    @SetFromFlag
+    private Long period = null;
+    @SetFromFlag("timeout")
+    private Long durationLimit = null;
+    private int iterationLimit = 0;
+    private boolean rethrowException = false;
+    private boolean rethrowExceptionImmediately = false;
+    private boolean warnOnUnRethrownException = true;
+
+    public Repeater() {
+        this(MutableMap.of(), null);
+    }
+
+    public Repeater(Map<?,?> flags) {
+        this(flags, null);
+    }
+
+    public Repeater(String description) {
+        this(MutableMap.of(), description);
+    }
+    
+    /**
+     * Construct a new instance of Repeater.
+     *
+     * @param flags       can include period, timeout, description
+     * @param description a description of the operation that will appear in debug logs.
+     */
+    public Repeater(Map<?,?> flags, String description) {
+        setFromFlags(flags);
+        this.description = JavaGroovyEquivalents.elvis(description, this.description, "Repeater");
+    }
+
+    public void setFromFlags(Map<?,?> flags) {
+        FlagUtils.setFieldsFromFlags(flags, this);
+    }
+    
+    public static Repeater create() {
+        return create(MutableMap.of());
+    }
+    public static Repeater create(Map<?,?> flags) {
+        return create(flags, null);
+    }
+    public static Repeater create(String description) {
+        return create(MutableMap.of(), description);
+    }
+    public static Repeater create(Map<?,?> flags, String description) {
+        return new Repeater(flags, description);
+    }
+
+    /**
+     * Sets the main body of the loop to be a no-op.
+     * 
+     * @return {@literal this} to aid coding in a fluent style.
+     */
+    public Repeater repeat() {
+        return repeat(Callables.returning(null));
+    }
+    
+    /**
+     * Sets the main body of the loop.
+     *
+     * @param body a closure or other Runnable that is executed in the main body of the loop.
+     * @return {@literal this} to aid coding in a fluent style.
+     */
+    public Repeater repeat(Runnable body) {
+        checkNotNull(body, "body must not be null");
+        this.body = (body instanceof Callable) ? (Callable<?>)body : Executors.callable(body);
+        return this;
+    }
+    
+    /**
+     * Sets the main body of the loop.
+     *
+     * @param body a closure or other Callable that is executed in the main body of the loop.
+     * @return {@literal this} to aid coding in a fluent style.
+     */
+    public Repeater repeat(Callable<?> body) {
+        checkNotNull(body, "body must not be null");
+        this.body = body;
+        return this;
+    }
+
+    /**
+     * Set how long to wait between loop iterations.
+     *
+     * @param period how long to wait between loop iterations.
+     * @param unit the unit of measurement of the period.
+     * @return {@literal this} to aid coding in a fluent style.
+     */
+    public Repeater every(long period, TimeUnit unit) {
+        Preconditions.checkArgument(period > 0, "period must be positive: %s", period);
+        checkNotNull(unit, "unit must not be null");
+        this.period = unit.toMillis(period);
+        return this;
+    }
+
+    /**
+     * @see #every(long, TimeUnit)
+     */
+    public Repeater every(Duration duration) {
+        Preconditions.checkNotNull(duration, "duration must not be null");
+        Preconditions.checkArgument(duration.toMilliseconds()>0, "period must be positive: %s", duration);
+        this.period = duration.toMilliseconds();
+        return this;
+    }
+    
+    public Repeater every(groovy.time.Duration duration) {
+        return every(Duration.of(duration));
+    }
+
+    /**
+     * @see #every(long, TimeUnit)
+     * @deprecated specify unit
+     */
+    public Repeater every(long duration) {
+        return every(duration, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Set code fragment that tests if the loop has completed.
+     *
+     * @param exitCondition a closure or other Callable that returns a boolean. If this code returns {@literal true} then the
+     * loop will stop executing.
+     * @return {@literal this} to aid coding in a fluent style.
+     */
+    public Repeater until(Callable<Boolean> exitCondition) {
+        Preconditions.checkNotNull(exitCondition, "exitCondition must not be null");
+        this.exitCondition = exitCondition;
+        return this;
+    }
+
+    /**
+     * If the exit condition check throws an exception, it will be recorded and the last exception will be thrown on failure.
+     *
+     * @return {@literal this} to aid coding in a fluent style.
+     */
+    public Repeater rethrowException() {
+        this.rethrowException = true;
+        return this;
+    }
+
+    /**
+     * If the repeated body or the exit condition check throws an exception, then propagate that exception immediately.
+     *
+     * @return {@literal this} to aid coding in a fluent style.
+     */
+    public Repeater rethrowExceptionImmediately() {
+        this.rethrowExceptionImmediately = true;
+        return this;
+    }
+
+    public Repeater suppressWarnings() {
+        this.warnOnUnRethrownException = false;
+        return this;
+    }
+
+    /**
+     * Set the maximum number of iterations.
+     *
+     * The loop will exit if the condition has not been satisfied after this number of iterations.
+     *
+     * @param iterationLimit the maximum number of iterations.
+     * @return {@literal this} to aid coding in a fluent style.
+     */
+    public Repeater limitIterationsTo(int iterationLimit) {
+        Preconditions.checkArgument(iterationLimit > 0, "iterationLimit must be positive: %s", iterationLimit);
+        this.iterationLimit = iterationLimit;
+        return this;
+    }
+
+    /**
+     * Set the amount of time to wait for the condition.
+     * The repeater will wait at least this long for the condition to be true,
+     * and will exit soon after even if the condition is false.
+     *
+     * @param deadline the time that the loop should wait.
+     * @param unit the unit of measurement of the period.
+     * @return {@literal this} to aid coding in a fluent style.
+     */
+    public Repeater limitTimeTo(long deadline, TimeUnit unit) {
+        Preconditions.checkArgument(deadline > 0, "deadline must be positive: %s", deadline);
+        Preconditions.checkNotNull(unit, "unit must not be null");
+        this.durationLimit = unit.toMillis(deadline);
+        return this;
+    }
+
+    /**
+     * @see #limitTimeTo(long, TimeUnit)
+     */
+    public Repeater limitTimeTo(Duration duration) {
+        Preconditions.checkNotNull(duration, "duration must not be null");
+        Preconditions.checkArgument(duration.toMilliseconds() > 0, "deadline must be positive: %s", duration);
+        this.durationLimit = duration.toMilliseconds();
+        return this;
+    }
+
+    /**
+     * Run the loop.
+     *
+     * @return true if the exit condition was satisfied; false if the loop terminated for any other reason.
+     */
+    public boolean run() {
+        Preconditions.checkState(body != null, "repeat() method has not been called to set the body");
+        Preconditions.checkState(exitCondition != null, "until() method has not been called to set the exit condition");
+        Preconditions.checkState(period != null, "every() method has not been called to set the loop period time units");
+
+        Throwable lastError = null;
+        int iterations = 0;
+        long endTime = -1;
+        if (durationLimit != null) {
+            endTime = System.currentTimeMillis() + durationLimit;
+        }
+
+        while (true) {
+            iterations++;
+
+            try {
+                body.call();
+            } catch (Exception e) {
+                log.warn(description, e);
+                if (rethrowExceptionImmediately) throw Exceptions.propagate(e);
+            }
+
+            boolean done = false;
+            try {
+                lastError = null;
+                done = exitCondition.call();
+            } catch (Exception e) {
+                if (log.isDebugEnabled()) log.debug(description, e);
+                lastError = e;
+                if (rethrowExceptionImmediately) throw Exceptions.propagate(e);
+            }
+            if (done) {
+                if (log.isDebugEnabled()) log.debug("{}: condition satisfied", description);
+                return true;
+            } else {
+                if (log.isDebugEnabled()) {
+                    String msg = String.format("%s: unsatisfied during iteration %s %s", description, iterations,
+                            (iterationLimit > 0 ? "(max "+iterationLimit+" attempts)" : "") + 
+                            (endTime > 0 ? "("+Time.makeTimeStringRounded(endTime - System.currentTimeMillis())+" remaining)" : ""));
+                    if (iterations == 1) {
+                        log.debug(msg);
+                    } else {
+                        log.trace(msg);
+                    }
+                }
+            }
+
+            if (iterationLimit > 0 && iterations == iterationLimit) {
+                if (log.isDebugEnabled()) log.debug("{}: condition not satisfied and exceeded iteration limit", description);
+                if (rethrowException && lastError != null) {
+                    log.warn("{}: error caught checking condition (rethrowing): {}", description, lastError.getMessage());
+                    throw Exceptions.propagate(lastError);
+                }
+                if (warnOnUnRethrownException && lastError != null)
+                    log.warn("{}: error caught checking condition: {}", description, lastError.getMessage());
+                return false;
+            }
+
+            if (endTime > 0) {
+                if (System.currentTimeMillis() > endTime) {
+                    if (log.isDebugEnabled()) log.debug("{}: condition not satisfied and deadline {} passed", 
+                            description, Time.makeTimeStringRounded(endTime - System.currentTimeMillis()));
+                    if (rethrowException && lastError != null) {
+                        log.error("{}: error caught checking condition: {}", description, lastError.getMessage());
+                        throw Exceptions.propagate(lastError);
+                    }
+                    return false;
+                }
+            }
+
+            Time.sleep(period);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/BackoffLimitedRetryHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/BackoffLimitedRetryHandler.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/BackoffLimitedRetryHandler.java
new file mode 100644
index 0000000..b8d6eac
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/BackoffLimitedRetryHandler.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.util.internal.ssh;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.exceptions.Exceptions;
+
+/**
+ * Allow replayable request to be retried a limited number of times, and impose an exponential back-off
+ * delay before returning.
+ * <p>
+ * Copied and modified from jclouds; original author was James Murty
+ */
+public class BackoffLimitedRetryHandler {
+
+    private static final Logger LOG = LoggerFactory.getLogger(BackoffLimitedRetryHandler.class);
+
+    private final int retryCountLimit;
+
+    private final long delayStart;
+
+    public BackoffLimitedRetryHandler() {
+        this(5, 50L);
+    }
+    
+    public BackoffLimitedRetryHandler(int retryCountLimit, long delayStart) {
+        this.retryCountLimit = retryCountLimit;
+        this.delayStart = delayStart;
+    }
+    
+    public void imposeBackoffExponentialDelay(int failureCount, String commandDescription) {
+        imposeBackoffExponentialDelay(delayStart, 2, failureCount, retryCountLimit, commandDescription);
+    }
+
+    public void imposeBackoffExponentialDelay(long period, int pow, int failureCount, int max, String commandDescription) {
+        imposeBackoffExponentialDelay(period, period * 10l, pow, failureCount, max, commandDescription);
+    }
+
+    public void imposeBackoffExponentialDelay(long period,
+            long maxPeriod,
+            int pow,
+            int failureCount,
+            int max,
+            String commandDescription) {
+        long delayMs = (long) (period * Math.pow(failureCount, pow));
+        delayMs = (delayMs > maxPeriod) ? maxPeriod : delayMs;
+        if (LOG.isDebugEnabled()) LOG.debug("Retry {}/{}: delaying for {} ms: {}", 
+                new Object[] {failureCount, max, delayMs, commandDescription});
+        try {
+            Thread.sleep(delayMs);
+        } catch (InterruptedException e) {
+            Exceptions.propagate(e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/ShellAbstractTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/ShellAbstractTool.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/ShellAbstractTool.java
new file mode 100644
index 0000000..90dcffa
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/ShellAbstractTool.java
@@ -0,0 +1,442 @@
+/*
+ * 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.util.internal.ssh;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.io.ByteArrayInputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.text.Identifiers;
+import brooklyn.util.text.StringEscapes.BashStringEscapes;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+
+public abstract class ShellAbstractTool implements ShellTool {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ShellAbstractTool.class);
+
+    protected final File localTempDir;
+
+    public ShellAbstractTool(String localTempDir) {
+        this(localTempDir == null ? null : new File(Os.tidyPath(localTempDir)));
+    }
+    
+    public ShellAbstractTool(File localTempDir) {
+        if (localTempDir == null) {
+            localTempDir = new File(Os.tmp(), "tmpssh-"+Os.user());
+            if (!localTempDir.exists()) localTempDir.mkdir();
+            Os.deleteOnExitEmptyParentsUpTo(localTempDir, new File(Os.tmp()));
+        }
+        this.localTempDir = localTempDir;
+    }
+    
+    public ShellAbstractTool() {
+        this((File)null);
+    }
+    
+    protected static void warnOnDeprecated(Map<String, ?> props, String deprecatedKey, String correctKey) {
+        if (props.containsKey(deprecatedKey)) {
+            if (correctKey != null && props.containsKey(correctKey)) {
+                Object dv = props.get(deprecatedKey);
+                Object cv = props.get(correctKey);
+                if (!Objects.equal(cv, dv)) {
+                    LOG.warn("SshTool detected deprecated key '"+deprecatedKey+"' with different value ("+dv+") "+
+                            "than new key '"+correctKey+"' ("+cv+"); ambiguous which will be used");
+                } else {
+                    // ignore, the deprecated key populated for legacy reasons
+                }
+            } else {
+                Object dv = props.get(deprecatedKey);
+                LOG.warn("SshTool detected deprecated key '"+deprecatedKey+"' used, with value ("+dv+")");     
+            }
+        }
+    }
+
+    protected static Boolean hasVal(Map<String,?> map, ConfigKey<?> keyC) {
+        String key = keyC.getName();
+        return map.containsKey(key);
+    }
+    
+    protected static <T> T getMandatoryVal(Map<String,?> map, ConfigKey<T> keyC) {
+        String key = keyC.getName();
+        checkArgument(map.containsKey(key), "must contain key '"+keyC+"'");
+        return TypeCoercions.coerce(map.get(key), keyC.getTypeToken());
+    }
+    
+    public static <T> T getOptionalVal(Map<String,?> map, ConfigKey<T> keyC) {
+        if (keyC==null) return null;
+        String key = keyC.getName();
+        if (map!=null && map.containsKey(key) && map.get(key) != null) {
+            return TypeCoercions.coerce(map.get(key), keyC.getTypeToken());
+        } else {
+            return keyC.getDefaultValue();
+        }
+    }
+
+    /** returns the value of the key if specified, otherwise defaultValue */
+    protected static <T> T getOptionalVal(Map<String,?> map, ConfigKey<T> keyC, T defaultValue) {
+        String key = keyC.getName();
+        if (map!=null && map.containsKey(key) && map.get(key) != null) {
+            return TypeCoercions.coerce(map.get(key), keyC.getTypeToken());
+        } else {
+            return defaultValue;
+        }
+    }
+
+    protected void closeWhispering(Closeable closeable, Object context) {
+        closeWhispering(closeable, this, context);
+    }
+    
+    /**
+     * Similar to Guava's Closeables.closeQuitely, except logs exception at debug with context in message.
+     */
+    protected static void closeWhispering(Closeable closeable, Object context1, Object context2) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (IOException e) {
+                if (LOG.isDebugEnabled()) {
+                    String msg = String.format("<< exception during close, for %s -> %s (%s); continuing.", 
+                            context1, context2, closeable);
+                    if (LOG.isTraceEnabled())
+                        LOG.debug(msg + ": " + e);
+                    else
+                        LOG.trace(msg, e);
+                }
+            }
+        }
+    }
+
+    protected File writeTempFile(InputStream contents) {
+        File tempFile = Os.writeToTempFile(contents, localTempDir, "sshcopy", "data");
+        tempFile.setReadable(false, false);
+        tempFile.setReadable(true, true);
+        tempFile.setWritable(false);
+        tempFile.setExecutable(false);
+        return tempFile;
+    }
+
+    protected File writeTempFile(String contents) {
+        return writeTempFile(contents.getBytes());
+    }
+
+    protected File writeTempFile(byte[] contents) {
+        return writeTempFile(new ByteArrayInputStream(contents));
+    }
+
+    protected String toScript(Map<String,?> props, List<String> commands, Map<String,?> env) {
+        List<String> allcmds = toCommandSequence(commands, env);
+        StringBuilder result = new StringBuilder();
+        result.append(getOptionalVal(props, PROP_SCRIPT_HEADER)).append('\n');
+        
+        for (String cmd : allcmds) {
+            result.append(cmd).append('\n');
+        }
+        
+        return result.toString();
+    }
+
+    /**
+     * Merges the commands and env, into a single set of commands. Also escapes the commands as required.
+     * 
+     * Not all ssh servers handle "env", so instead convert env into exported variables
+     */
+    protected List<String> toCommandSequence(List<String> commands, Map<String,?> env) {
+        List<String> result = new ArrayList<String>((env!=null ? env.size() : 0) + commands.size());
+        
+        if (env!=null) {
+            for (Entry<String,?> entry : env.entrySet()) {
+                if (entry.getKey() == null || entry.getValue() == null) {
+                    LOG.warn("env key-values must not be null; ignoring: key="+entry.getKey()+"; value="+entry.getValue());
+                    continue;
+                }
+                String escapedVal = BashStringEscapes.escapeLiteralForDoubleQuotedBash(entry.getValue().toString());
+                result.add("export "+entry.getKey()+"=\""+escapedVal+"\"");
+            }
+        }
+        for (CharSequence cmd : commands) { // objects in commands can be groovy GString so can't treat as String here
+            result.add(cmd.toString());
+        }
+
+        return result;
+    }
+
+    @Override
+    public int execScript(Map<String,?> props, List<String> commands) {
+        return execScript(props, commands, Collections.<String,Object>emptyMap());
+    }
+
+    @Override
+    public int execCommands(Map<String,?> props, List<String> commands) {
+        return execCommands(props, commands, Collections.<String,Object>emptyMap());
+    }
+
+    protected static int asInt(Integer input, int valueIfInputNull) {
+        return input != null ? input : valueIfInputNull;
+    }
+
+    protected abstract class ToolAbstractExecScript {
+        protected final Map<String, ?> props;
+        protected final String separator;
+        protected final OutputStream out;
+        protected final OutputStream err;
+        protected final String scriptDir;
+        protected final Boolean runAsRoot;
+        protected final Boolean noExtraOutput;
+        protected final Boolean noDeleteAfterExec;
+        protected final String scriptNameWithoutExtension;
+        protected final String scriptPath;
+        protected final Duration execTimeout;
+
+        public ToolAbstractExecScript(Map<String,?> props) {
+            this.props = props;
+            this.separator = getOptionalVal(props, PROP_SEPARATOR);
+            this.out = getOptionalVal(props, PROP_OUT_STREAM);
+            this.err = getOptionalVal(props, PROP_ERR_STREAM);
+            
+            this.scriptDir = getOptionalVal(props, PROP_SCRIPT_DIR);
+            this.runAsRoot = getOptionalVal(props, PROP_RUN_AS_ROOT);
+            this.noExtraOutput = getOptionalVal(props, PROP_NO_EXTRA_OUTPUT);
+            this.noDeleteAfterExec = getOptionalVal(props, PROP_NO_DELETE_SCRIPT);
+            this.execTimeout = getOptionalVal(props, PROP_EXEC_TIMEOUT);
+            
+            String summary = getOptionalVal(props, PROP_SUMMARY);
+            if (summary!=null) {
+                summary = Strings.makeValidFilename(summary);
+                if (summary.length()>30) 
+                    summary = summary.substring(0,30);
+            }
+            this.scriptNameWithoutExtension = "brooklyn-"+
+                    Time.makeDateStampString()+"-"+Identifiers.makeRandomId(4)+
+                    (Strings.isBlank(summary) ? "" : "-"+summary);
+            this.scriptPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension+".sh");
+        }
+
+        /** builds the command to run the given script;
+         * note that some modes require \$RESULT passed in order to access a variable, whereas most just need $ */
+        protected List<String> buildRunScriptCommand() {
+            MutableList.Builder<String> cmds = MutableList.<String>builder()
+                    .add((runAsRoot ? BashCommands.sudo(scriptPath) : scriptPath) + " < /dev/null")
+                    .add("RESULT=$?");
+            if (noExtraOutput==null || !noExtraOutput)
+                cmds.add("echo Executed "+scriptPath+", result $RESULT"); 
+            if (noDeleteAfterExec!=Boolean.TRUE) {
+                // use "-f" because some systems have "rm" aliased to "rm -i"
+                // use "< /dev/null" to guarantee doesn't hang
+                cmds.add("rm -f "+scriptPath+" < /dev/null");
+            }
+            cmds.add("exit $RESULT");
+            return cmds.build();
+        }
+
+        protected String getSummary() {
+            String summary = getOptionalVal(props, PROP_SUMMARY);
+            return (summary != null) ? summary : scriptPath; 
+        }
+
+        public abstract int run();
+    }
+    
+    protected abstract class ToolAbstractAsyncExecScript extends ToolAbstractExecScript {
+        protected final String stdoutPath;
+        protected final String stderrPath;
+        protected final String exitStatusPath;
+        protected final String pidPath;
+
+        public ToolAbstractAsyncExecScript(Map<String,?> props) {
+            super(props);
+
+            stdoutPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension + ".stdout");
+            stderrPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension + ".stderr");
+            exitStatusPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension + ".exitstatus");
+            pidPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension + ".pid");
+        }
+
+        /**
+         * Builds the command to run the given script, asynchronously.
+         * The executed command will return immediately, but the output from the script
+         * will continue to be written 
+         * note that some modes require \$RESULT passed in order to access a variable, whereas most just need $ */
+        @Override
+        protected List<String> buildRunScriptCommand() {
+            String touchCmd = String.format("touch %s %s %s %s", stdoutPath, stderrPath, exitStatusPath, pidPath);
+            String cmd = String.format("nohup sh -c \"( %s > %s 2> %s < /dev/null ) ; echo \\$? > %s \" > /dev/null 2>&1 < /dev/null &", scriptPath, stdoutPath, stderrPath, exitStatusPath);
+            MutableList.Builder<String> cmds = MutableList.<String>builder()
+                    .add(runAsRoot ? BashCommands.sudo(touchCmd) : touchCmd)
+                    .add(runAsRoot ? BashCommands.sudo(cmd) : cmd)
+                    .add("echo $! > "+pidPath)
+                    .add("RESULT=$?");
+            if (noExtraOutput==null || !noExtraOutput) {
+                cmds.add("echo Executing async "+scriptPath);
+            }
+            cmds.add("exit $RESULT");
+            return cmds.build();
+        }
+
+        /**
+         * Builds the command to retrieve the exit status of the command, written to stdout.
+         */
+        protected List<String> buildRetrieveStatusCommand() {
+            // Retrieve exit status from file (writtent to stdout), if populated;
+            // if not found and pid still running, then return empty string; else exit code 1.
+            List<String> cmdParts = ImmutableList.of(
+                    "# Retrieve status", // comment is to aid testing - see SshjToolAsyncStubIntegrationTest
+                    "if test -s "+exitStatusPath+"; then",
+                    "    cat "+exitStatusPath,
+                    "elif test -s "+pidPath+"; then",
+                    "    pid=`cat "+pidPath+"`",
+                    "    if ! ps -p $pid > /dev/null < /dev/null; then",
+                    "        # no exit status, and not executing; give a few seconds grace in case just about to write exit status",
+                    "        sleep 3",
+                    "        if test -s "+exitStatusPath+"; then",
+                    "            cat "+exitStatusPath+"",
+                    "        else",
+                    "            echo \"No exit status in "+exitStatusPath+", and pid in "+pidPath+" ($pid) not executing\"",
+                    "            exit 1",
+                    "        fi",
+                    "    fi",
+                    "else",
+                    "    echo \"No exit status in "+exitStatusPath+", and "+pidPath+" is empty\"",
+                    "    exit 1",
+                    "fi"+"\n");
+            String cmd = Joiner.on("\n").join(cmdParts);
+
+            MutableList.Builder<String> cmds = MutableList.<String>builder()
+                    .add((runAsRoot ? BashCommands.sudo(cmd) : cmd))
+                    .add("RESULT=$?");
+            cmds.add("exit $RESULT");
+            return cmds.build();
+        }
+
+        /**
+         * Builds the command to retrieve the stdout and stderr of the async command.
+         * An offset can be given, to only retrieve data starting at a particular character (indexed from 0).
+         */
+        protected List<String> buildRetrieveStdoutAndStderrCommand(int stdoutPosition, int stderrPosition) {
+            // Note that `tail -c +1` means start at the *first* character (i.e. start counting from 1, not 0)
+            String catStdoutCmd = "tail -c +"+(stdoutPosition+1)+" "+stdoutPath+" 2> /dev/null";
+            String catStderrCmd = "tail -c +"+(stderrPosition+1)+" "+stderrPath+" 2>&1 > /dev/null";
+            MutableList.Builder<String> cmds = MutableList.<String>builder()
+                    .add((runAsRoot ? BashCommands.sudo(catStdoutCmd) : catStdoutCmd))
+                    .add((runAsRoot ? BashCommands.sudo(catStderrCmd) : catStderrCmd))
+                    .add("RESULT=$?");
+            cmds.add("exit $RESULT");
+            return cmds.build();
+        }
+
+        /**
+         * Builds the command to retrieve the stdout and stderr of the async command.
+         * An offset can be given, to only retrieve data starting at a particular character (indexed from 0).
+         */
+        protected List<String> buildLongPollCommand(int stdoutPosition, int stderrPosition, Duration timeout) {
+            long maxTime = Math.max(1, timeout.toSeconds());
+            
+            // Note that `tail -c +1` means start at the *first* character (i.e. start counting from 1, not 0)
+            List<String> waitForExitStatusParts = ImmutableList.of(
+                    //Should be careful here because any output will be part of the stdout/stderr streams
+                    "# Long poll", // comment is to aid testing - see SshjToolAsyncStubIntegrationTest
+                    // disown to avoid Terminated message after killing the process
+                    // redirect error output to avoid "file truncated" messages
+                    "tail -c +"+(stdoutPosition+1)+" -f "+stdoutPath+" 2> /dev/null & export TAIL_STDOUT_PID=$!; disown",
+                    "tail -c +"+(stderrPosition+1)+" -f "+stderrPath+" 1>&2 2> /dev/null & export TAIL_STDERR_PID=$!; disown",
+                    "EXIT_STATUS_PATH="+exitStatusPath,
+                    "PID_PATH="+pidPath,
+                    "MAX_TIME="+maxTime,
+                    "COUNTER=0",
+                    "while [ \"$COUNTER\" -lt $MAX_TIME ]; do",
+                    "    if test -s $EXIT_STATUS_PATH; then",
+                    "        EXIT_STATUS=`cat $EXIT_STATUS_PATH`",
+                    "        kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID} 2> /dev/null",
+                    "        exit $EXIT_STATUS",
+                    "    elif test -s $PID_PATH; then",
+                    "        PID=`cat $PID_PATH`",
+                    "        if ! ps -p $PID > /dev/null 2>&1 < /dev/null; then",
+                    "            # no exit status, and not executing; give a few seconds grace in case just about to write exit status",
+                    "            sleep 3",
+                    "            if test -s $EXIT_STATUS_PATH; then",
+                    "                EXIT_STATUS=`cat $EXIT_STATUS_PATH`",
+                    "                kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID} 2> /dev/null",
+                    "                exit $EXIT_STATUS",
+                    "            else",
+                    "                echo \"No exit status in $EXIT_STATUS_PATH, and pid in $PID_PATH ($PID) not executing\"",
+                    "                kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID} 2> /dev/null",
+                    "                exit 126",
+                    "            fi",
+                    "        fi",
+                    "    fi",
+                    "    # No exit status in $EXIT_STATUS_PATH; keep waiting",
+                    "    sleep 1",
+                    "    COUNTER+=1",
+                    "done",
+                    "kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID} 2> /dev/null",
+                    "exit 125"+"\n");
+            String waitForExitStatus = Joiner.on("\n").join(waitForExitStatusParts);
+
+            return ImmutableList.of(runAsRoot ? BashCommands.sudo(waitForExitStatus) : waitForExitStatus);
+        }
+
+        protected List<String> deleteTemporaryFilesCommand() {
+            ImmutableList.Builder<String> cmdParts = ImmutableList.builder();
+            
+            if (!Boolean.TRUE.equals(noDeleteAfterExec)) {
+                // use "-f" because some systems have "rm" aliased to "rm -i"
+                // use "< /dev/null" to guarantee doesn't hang
+                cmdParts.add(
+                        "rm -f "+scriptPath+" "+stdoutPath+" "+stderrPath+" "+exitStatusPath+" "+pidPath+" < /dev/null");
+            }
+            
+            // If the buildLongPollCommand didn't complete properly then it might have left tail command running;
+            // ensure they are killed.
+            cmdParts.add(
+                    //ignore error output for the case where there are no running processes and kill is called without arguments
+                    "ps aux | grep \"tail -c\" | grep \""+stdoutPath+"\" | grep -v grep | awk '{ printf $2 }' | xargs kill 2> /dev/null",
+                    "ps aux | grep \"tail -c\" | grep \""+stderrPath+"\" | grep -v grep | awk '{ printf $2 }' | xargs kill 2> /dev/null");
+
+            String cmd = Joiner.on("\n").join(cmdParts.build());
+            
+            return ImmutableList.of(runAsRoot ? BashCommands.sudo(cmd) : cmd);
+        }
+
+        @Override
+        public abstract int run();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/ShellTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/ShellTool.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/ShellTool.java
new file mode 100644
index 0000000..13bfb62
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/ShellTool.java
@@ -0,0 +1,113 @@
+/*
+ * 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.util.internal.ssh;
+
+import static brooklyn.entity.basic.ConfigKeys.newConfigKey;
+import static brooklyn.entity.basic.ConfigKeys.newStringConfigKey;
+
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.util.os.Os;
+import brooklyn.util.time.Duration;
+
+/** Methods for executing things in an environment (localhost process, or ssh) */
+public interface ShellTool {
+
+    // config which applies to sessions
+    
+    public static final ConfigKey<String> PROP_LOCAL_TEMP_DIR = newStringConfigKey(
+            "localTempDir", 
+            "The directory on the local machine (i.e. running brooklyn) for writing temp files", 
+            Os.mergePaths(Os.tmp(), "brooklyn-"+Os.user()+"-ssh-tmp"));
+    
+    // config which applies to calls:
+    
+    public static final ConfigKey<Boolean> PROP_RUN_AS_ROOT = newConfigKey("runAsRoot", "When running a script, whether to run as root", Boolean.FALSE);
+    
+    public static final ConfigKey<OutputStream> PROP_OUT_STREAM = newConfigKey(OutputStream.class, "out", "Stream to which to capture stdout");
+    public static final ConfigKey<OutputStream> PROP_ERR_STREAM = newConfigKey(OutputStream.class, "err", "Stream to which to capture stderr");
+    
+    public static final ConfigKey<Boolean> PROP_NO_EXTRA_OUTPUT = newConfigKey("noExtraOutput", "Suppresses any decorative output such as result code which some tool commands insert", false);
+    
+    public static final ConfigKey<String> PROP_SEPARATOR = newConfigKey("separator", "string to insert between caller-supplied commands being executed as commands", " ; ");
+    
+    public static final ConfigKey<String> PROP_SCRIPT_DIR = newConfigKey("scriptDir", "directory where scripts should be copied", "/tmp");
+    public static final ConfigKey<String> PROP_SCRIPT_HEADER = newConfigKey("scriptHeader", "lines to insert at the start of scripts generated for caller-supplied commands for script execution", "#!/bin/bash -e\n");
+    public static final ConfigKey<String> PROP_DIRECT_HEADER = newConfigKey("directHeader", "commands to run at the target before any caller-supplied commands for direct execution", "exec bash -e");
+
+    ConfigKey<Boolean> PROP_NO_DELETE_SCRIPT = newConfigKey("noDeleteAfterExec", "Retains the generated script file after executing the commands instead of deleting it", false);
+
+    ConfigKey<String> PROP_SUMMARY = ConfigKeys.newStringConfigKey("summary", "Provides a human-readable summary, used in file generation etc");
+    
+    ConfigKey<Duration> PROP_EXEC_TIMEOUT = newConfigKey("execTimeout", "Timeout when executing a script", Duration.PRACTICALLY_FOREVER);
+
+    ConfigKey<Boolean> PROP_EXEC_ASYNC = newConfigKey("execAsync", "Executes the script asynchronously, and then polls for the result (and for stdout/stderr)", false);
+
+    ConfigKey<Duration> PROP_EXEC_ASYNC_POLLING_TIMEOUT = newConfigKey("execAsyncPollTimeout", "Timeout per poll when executing a script asynchronously", Duration.ONE_MINUTE);
+
+    /**
+     * Executes the set of commands in a shell script. Blocks until completion.
+     * <p>
+     * 
+     * Optional properties are the same common ones as for {@link #execCommands(Map, List, Map)} with the addition of:
+     * <ul>
+     * <li>{@link #PROP_RUN_AS_ROOT}
+     * <li>{@link #PROP_SCRIPT_DIR}
+     * </ul>
+     * 
+     * @return exit status of script
+     */
+    public int execScript(Map<String,?> props, List<String> commands, Map<String,?> env);
+
+    /**
+     * @see #execScript(Map, List, Map)
+     */
+    public int execScript(Map<String,?> props, List<String> commands);
+
+    /**
+     * Executes the set of commands using ssh exec.
+     * 
+     * This is generally more efficient than ssh shell mode (cf {@link #execScript(Map, List, Map)}), 
+     * but is not suitable if you need env values which are only set on a fully-fledged shell,
+     * or if you want the entire block executed with root permission.
+     *
+     * Common optional properties (which also apply to {@link #execScript(Map, List, Map)}) are:
+     * <ul>
+     * <li>{@link #PROP_OUT_STREAM}
+     * <li>{@link #PROP_ERR_STREAM}
+     * <li>{@link #PROP_SEPARATOR} (for some modes)
+     * <li>{@link #PROP_NO_EXTRA_OUTPUT} (often there is no extra output here)
+     * </ul>
+     * 
+     * Note that {@link #PROP_RUN_AS_ROOT} is <i>not</i> typically supported here. Prefer {@link #execScript(Map, List, Map)}).
+     * 
+     * @return exit status of commands
+     */
+    public int execCommands(Map<String,?> properties, List<String> commands, Map<String,?> env);
+
+    /**
+     * @see #execCommands(Map, List, Map)
+     */
+    public int execCommands(Map<String,?> properties, List<String> commands);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshAbstractTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshAbstractTool.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshAbstractTool.java
new file mode 100644
index 0000000..ea7a71e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshAbstractTool.java
@@ -0,0 +1,172 @@
+/*
+ * 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.util.internal.ssh;
+
+import static brooklyn.util.net.Networking.checkPortValid;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Set;
+
+import brooklyn.util.os.Os;
+
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+
+public abstract class SshAbstractTool extends ShellAbstractTool implements SshTool {
+
+    protected final String toString;
+
+    protected final String host;
+    protected final String user;
+    protected final String password;
+    protected final int port;
+    protected String privateKeyPassphrase;
+    protected String privateKeyData;
+    protected File privateKeyFile;
+    protected boolean strictHostKeyChecking;
+    protected boolean allocatePTY;
+
+    public static interface SshAction<T> {
+        void clear() throws Exception;
+        T create() throws Exception;
+    }
+
+    public static abstract class AbstractSshToolBuilder<T extends SshTool, B extends AbstractSshToolBuilder<T,B>> {
+        protected String host;
+        protected int port = 22;
+        protected String user = System.getProperty("user.name");
+        protected String password;
+        protected String privateKeyData;
+        protected String privateKeyPassphrase;
+        protected Set<String> privateKeyFiles = Sets.newLinkedHashSet();
+        protected boolean strictHostKeyChecking = false;
+        protected boolean allocatePTY = false;
+        protected File localTempDir = null;
+
+        @SuppressWarnings("unchecked")
+        protected B self() {
+           return (B) this;
+        }
+
+        public B from(Map<String,?> props) {
+            host = getMandatoryVal(props, PROP_HOST);
+            port = getOptionalVal(props, PROP_PORT);
+            user = getOptionalVal(props, PROP_USER);
+            
+            password = getOptionalVal(props, PROP_PASSWORD);
+            
+            warnOnDeprecated(props, "privateKey", "privateKeyData");
+            privateKeyData = getOptionalVal(props, PROP_PRIVATE_KEY_DATA);
+            privateKeyPassphrase = getOptionalVal(props, PROP_PRIVATE_KEY_PASSPHRASE);
+            
+            // for backwards compatibility accept keyFiles and privateKey
+            // but sshj accepts only a single privateKeyFile; leave blank to use defaults (i.e. ~/.ssh/id_rsa and id_dsa)
+            warnOnDeprecated(props, "keyFiles", null);
+            String privateKeyFile = getOptionalVal(props, PROP_PRIVATE_KEY_FILE);
+            if (privateKeyFile != null) privateKeyFiles.add(privateKeyFile);
+            
+            strictHostKeyChecking = getOptionalVal(props, PROP_STRICT_HOST_KEY_CHECKING);
+            allocatePTY = getOptionalVal(props, PROP_ALLOCATE_PTY);
+            
+            String localTempDirPath = getOptionalVal(props, PROP_LOCAL_TEMP_DIR);
+            localTempDir = (localTempDirPath == null) ? null : new File(Os.tidyPath(localTempDirPath));
+            
+            return self();
+        }
+        public B host(String val) {
+            this.host = val; return self();
+        }
+        public B user(String val) {
+            this.user = val; return self();
+        }
+        public B password(String val) {
+            this.password = val; return self();
+        }
+        public B port(int val) {
+            this.port = val; return self();
+        }
+        public B privateKeyPassphrase(String val) {
+            this.privateKeyPassphrase = val; return self();
+        }
+        /** @deprecated 1.4.0, use privateKeyData */
+        public B privateKey(String val) {
+            this.privateKeyData = val; return self();
+        }
+        public B privateKeyData(String val) {
+            this.privateKeyData = val; return self();
+        }
+        public B privateKeyFile(String val) {
+            this.privateKeyFiles.add(val); return self();
+        }
+        public B localTempDir(File val) {
+            this.localTempDir = val; return self();
+        }
+        public abstract T build();
+    }
+
+    protected SshAbstractTool(AbstractSshToolBuilder<?,?> builder) {
+        super(builder.localTempDir);
+        
+        host = checkNotNull(builder.host, "host");
+        port = builder.port;
+        user = builder.user;
+        password = builder.password;
+        strictHostKeyChecking = builder.strictHostKeyChecking;
+        allocatePTY = builder.allocatePTY;
+        privateKeyPassphrase = builder.privateKeyPassphrase;
+        privateKeyData = builder.privateKeyData;
+        
+        if (builder.privateKeyFiles.size() > 1) {
+            throw new IllegalArgumentException("sshj supports only a single private key-file; " +
+                    "for defaults of ~/.ssh/id_rsa and ~/.ssh/id_dsa leave blank");
+        } else if (builder.privateKeyFiles.size() == 1) {
+            String privateKeyFileStr = Iterables.get(builder.privateKeyFiles, 0);
+            String amendedKeyFile = privateKeyFileStr.startsWith("~") ? (System.getProperty("user.home")+privateKeyFileStr.substring(1)) : privateKeyFileStr;
+            privateKeyFile = new File(amendedKeyFile);
+        } else {
+            privateKeyFile = null;
+        }
+        
+        checkArgument(host.length() > 0, "host value must not be an empty string");
+        checkPortValid(port, "ssh port");
+        
+        toString = String.format("%s@%s:%d", user, host, port);
+    }
+
+    @Override
+    public String toString() {
+        return toString;
+    }
+
+    public String getHostAddress() {
+        return this.host;
+    }
+
+    public String getUsername() {
+        return this.user;
+    }
+
+    protected SshException propagate(Exception e, String message) throws SshException {
+        throw new SshException("(" + toString() + ") " + message + ": " + e.getMessage(), e);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshException.java b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshException.java
new file mode 100644
index 0000000..c13aa42
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/internal/ssh/SshException.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.util.internal.ssh;
+
+public class SshException extends RuntimeException {
+
+    private static final long serialVersionUID = -5690230838066860965L;
+
+    public SshException(String msg) {
+        super(msg);
+    }
+    
+    public SshException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}


[34/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/ShellAbstractTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/ShellAbstractTool.java b/core/src/main/java/brooklyn/util/internal/ssh/ShellAbstractTool.java
deleted file mode 100644
index 5c839a9..0000000
--- a/core/src/main/java/brooklyn/util/internal/ssh/ShellAbstractTool.java
+++ /dev/null
@@ -1,442 +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 brooklyn.util.internal.ssh;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-import java.io.ByteArrayInputStream;
-import java.io.Closeable;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.StringEscapes.BashStringEscapes;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableList;
-
-public abstract class ShellAbstractTool implements ShellTool {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ShellAbstractTool.class);
-
-    protected final File localTempDir;
-
-    public ShellAbstractTool(String localTempDir) {
-        this(localTempDir == null ? null : new File(Os.tidyPath(localTempDir)));
-    }
-    
-    public ShellAbstractTool(File localTempDir) {
-        if (localTempDir == null) {
-            localTempDir = new File(Os.tmp(), "tmpssh-"+Os.user());
-            if (!localTempDir.exists()) localTempDir.mkdir();
-            Os.deleteOnExitEmptyParentsUpTo(localTempDir, new File(Os.tmp()));
-        }
-        this.localTempDir = localTempDir;
-    }
-    
-    public ShellAbstractTool() {
-        this((File)null);
-    }
-    
-    protected static void warnOnDeprecated(Map<String, ?> props, String deprecatedKey, String correctKey) {
-        if (props.containsKey(deprecatedKey)) {
-            if (correctKey != null && props.containsKey(correctKey)) {
-                Object dv = props.get(deprecatedKey);
-                Object cv = props.get(correctKey);
-                if (!Objects.equal(cv, dv)) {
-                    LOG.warn("SshTool detected deprecated key '"+deprecatedKey+"' with different value ("+dv+") "+
-                            "than new key '"+correctKey+"' ("+cv+"); ambiguous which will be used");
-                } else {
-                    // ignore, the deprecated key populated for legacy reasons
-                }
-            } else {
-                Object dv = props.get(deprecatedKey);
-                LOG.warn("SshTool detected deprecated key '"+deprecatedKey+"' used, with value ("+dv+")");     
-            }
-        }
-    }
-
-    protected static Boolean hasVal(Map<String,?> map, ConfigKey<?> keyC) {
-        String key = keyC.getName();
-        return map.containsKey(key);
-    }
-    
-    protected static <T> T getMandatoryVal(Map<String,?> map, ConfigKey<T> keyC) {
-        String key = keyC.getName();
-        checkArgument(map.containsKey(key), "must contain key '"+keyC+"'");
-        return TypeCoercions.coerce(map.get(key), keyC.getTypeToken());
-    }
-    
-    public static <T> T getOptionalVal(Map<String,?> map, ConfigKey<T> keyC) {
-        if (keyC==null) return null;
-        String key = keyC.getName();
-        if (map!=null && map.containsKey(key) && map.get(key) != null) {
-            return TypeCoercions.coerce(map.get(key), keyC.getTypeToken());
-        } else {
-            return keyC.getDefaultValue();
-        }
-    }
-
-    /** returns the value of the key if specified, otherwise defaultValue */
-    protected static <T> T getOptionalVal(Map<String,?> map, ConfigKey<T> keyC, T defaultValue) {
-        String key = keyC.getName();
-        if (map!=null && map.containsKey(key) && map.get(key) != null) {
-            return TypeCoercions.coerce(map.get(key), keyC.getTypeToken());
-        } else {
-            return defaultValue;
-        }
-    }
-
-    protected void closeWhispering(Closeable closeable, Object context) {
-        closeWhispering(closeable, this, context);
-    }
-    
-    /**
-     * Similar to Guava's Closeables.closeQuitely, except logs exception at debug with context in message.
-     */
-    protected static void closeWhispering(Closeable closeable, Object context1, Object context2) {
-        if (closeable != null) {
-            try {
-                closeable.close();
-            } catch (IOException e) {
-                if (LOG.isDebugEnabled()) {
-                    String msg = String.format("<< exception during close, for %s -> %s (%s); continuing.", 
-                            context1, context2, closeable);
-                    if (LOG.isTraceEnabled())
-                        LOG.debug(msg + ": " + e);
-                    else
-                        LOG.trace(msg, e);
-                }
-            }
-        }
-    }
-
-    protected File writeTempFile(InputStream contents) {
-        File tempFile = Os.writeToTempFile(contents, localTempDir, "sshcopy", "data");
-        tempFile.setReadable(false, false);
-        tempFile.setReadable(true, true);
-        tempFile.setWritable(false);
-        tempFile.setExecutable(false);
-        return tempFile;
-    }
-
-    protected File writeTempFile(String contents) {
-        return writeTempFile(contents.getBytes());
-    }
-
-    protected File writeTempFile(byte[] contents) {
-        return writeTempFile(new ByteArrayInputStream(contents));
-    }
-
-    protected String toScript(Map<String,?> props, List<String> commands, Map<String,?> env) {
-        List<String> allcmds = toCommandSequence(commands, env);
-        StringBuilder result = new StringBuilder();
-        result.append(getOptionalVal(props, PROP_SCRIPT_HEADER)).append('\n');
-        
-        for (String cmd : allcmds) {
-            result.append(cmd).append('\n');
-        }
-        
-        return result.toString();
-    }
-
-    /**
-     * Merges the commands and env, into a single set of commands. Also escapes the commands as required.
-     * 
-     * Not all ssh servers handle "env", so instead convert env into exported variables
-     */
-    protected List<String> toCommandSequence(List<String> commands, Map<String,?> env) {
-        List<String> result = new ArrayList<String>((env!=null ? env.size() : 0) + commands.size());
-        
-        if (env!=null) {
-            for (Entry<String,?> entry : env.entrySet()) {
-                if (entry.getKey() == null || entry.getValue() == null) {
-                    LOG.warn("env key-values must not be null; ignoring: key="+entry.getKey()+"; value="+entry.getValue());
-                    continue;
-                }
-                String escapedVal = BashStringEscapes.escapeLiteralForDoubleQuotedBash(entry.getValue().toString());
-                result.add("export "+entry.getKey()+"=\""+escapedVal+"\"");
-            }
-        }
-        for (CharSequence cmd : commands) { // objects in commands can be groovy GString so can't treat as String here
-            result.add(cmd.toString());
-        }
-
-        return result;
-    }
-
-    @Override
-    public int execScript(Map<String,?> props, List<String> commands) {
-        return execScript(props, commands, Collections.<String,Object>emptyMap());
-    }
-
-    @Override
-    public int execCommands(Map<String,?> props, List<String> commands) {
-        return execCommands(props, commands, Collections.<String,Object>emptyMap());
-    }
-
-    protected static int asInt(Integer input, int valueIfInputNull) {
-        return input != null ? input : valueIfInputNull;
-    }
-
-    protected abstract class ToolAbstractExecScript {
-        protected final Map<String, ?> props;
-        protected final String separator;
-        protected final OutputStream out;
-        protected final OutputStream err;
-        protected final String scriptDir;
-        protected final Boolean runAsRoot;
-        protected final Boolean noExtraOutput;
-        protected final Boolean noDeleteAfterExec;
-        protected final String scriptNameWithoutExtension;
-        protected final String scriptPath;
-        protected final Duration execTimeout;
-
-        public ToolAbstractExecScript(Map<String,?> props) {
-            this.props = props;
-            this.separator = getOptionalVal(props, PROP_SEPARATOR);
-            this.out = getOptionalVal(props, PROP_OUT_STREAM);
-            this.err = getOptionalVal(props, PROP_ERR_STREAM);
-            
-            this.scriptDir = getOptionalVal(props, PROP_SCRIPT_DIR);
-            this.runAsRoot = getOptionalVal(props, PROP_RUN_AS_ROOT);
-            this.noExtraOutput = getOptionalVal(props, PROP_NO_EXTRA_OUTPUT);
-            this.noDeleteAfterExec = getOptionalVal(props, PROP_NO_DELETE_SCRIPT);
-            this.execTimeout = getOptionalVal(props, PROP_EXEC_TIMEOUT);
-            
-            String summary = getOptionalVal(props, PROP_SUMMARY);
-            if (summary!=null) {
-                summary = Strings.makeValidFilename(summary);
-                if (summary.length()>30) 
-                    summary = summary.substring(0,30);
-            }
-            this.scriptNameWithoutExtension = "brooklyn-"+
-                    Time.makeDateStampString()+"-"+Identifiers.makeRandomId(4)+
-                    (Strings.isBlank(summary) ? "" : "-"+summary);
-            this.scriptPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension+".sh");
-        }
-
-        /** builds the command to run the given script;
-         * note that some modes require \$RESULT passed in order to access a variable, whereas most just need $ */
-        protected List<String> buildRunScriptCommand() {
-            MutableList.Builder<String> cmds = MutableList.<String>builder()
-                    .add((runAsRoot ? BashCommands.sudo(scriptPath) : scriptPath) + " < /dev/null")
-                    .add("RESULT=$?");
-            if (noExtraOutput==null || !noExtraOutput)
-                cmds.add("echo Executed "+scriptPath+", result $RESULT"); 
-            if (noDeleteAfterExec!=Boolean.TRUE) {
-                // use "-f" because some systems have "rm" aliased to "rm -i"
-                // use "< /dev/null" to guarantee doesn't hang
-                cmds.add("rm -f "+scriptPath+" < /dev/null");
-            }
-            cmds.add("exit $RESULT");
-            return cmds.build();
-        }
-
-        protected String getSummary() {
-            String summary = getOptionalVal(props, PROP_SUMMARY);
-            return (summary != null) ? summary : scriptPath; 
-        }
-
-        public abstract int run();
-    }
-    
-    protected abstract class ToolAbstractAsyncExecScript extends ToolAbstractExecScript {
-        protected final String stdoutPath;
-        protected final String stderrPath;
-        protected final String exitStatusPath;
-        protected final String pidPath;
-
-        public ToolAbstractAsyncExecScript(Map<String,?> props) {
-            super(props);
-
-            stdoutPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension + ".stdout");
-            stderrPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension + ".stderr");
-            exitStatusPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension + ".exitstatus");
-            pidPath = Os.mergePathsUnix(scriptDir, scriptNameWithoutExtension + ".pid");
-        }
-
-        /**
-         * Builds the command to run the given script, asynchronously.
-         * The executed command will return immediately, but the output from the script
-         * will continue to be written 
-         * note that some modes require \$RESULT passed in order to access a variable, whereas most just need $ */
-        @Override
-        protected List<String> buildRunScriptCommand() {
-            String touchCmd = String.format("touch %s %s %s %s", stdoutPath, stderrPath, exitStatusPath, pidPath);
-            String cmd = String.format("nohup sh -c \"( %s > %s 2> %s < /dev/null ) ; echo \\$? > %s \" > /dev/null 2>&1 < /dev/null &", scriptPath, stdoutPath, stderrPath, exitStatusPath);
-            MutableList.Builder<String> cmds = MutableList.<String>builder()
-                    .add(runAsRoot ? BashCommands.sudo(touchCmd) : touchCmd)
-                    .add(runAsRoot ? BashCommands.sudo(cmd) : cmd)
-                    .add("echo $! > "+pidPath)
-                    .add("RESULT=$?");
-            if (noExtraOutput==null || !noExtraOutput) {
-                cmds.add("echo Executing async "+scriptPath);
-            }
-            cmds.add("exit $RESULT");
-            return cmds.build();
-        }
-
-        /**
-         * Builds the command to retrieve the exit status of the command, written to stdout.
-         */
-        protected List<String> buildRetrieveStatusCommand() {
-            // Retrieve exit status from file (writtent to stdout), if populated;
-            // if not found and pid still running, then return empty string; else exit code 1.
-            List<String> cmdParts = ImmutableList.of(
-                    "# Retrieve status", // comment is to aid testing - see SshjToolAsyncStubIntegrationTest
-                    "if test -s "+exitStatusPath+"; then",
-                    "    cat "+exitStatusPath,
-                    "elif test -s "+pidPath+"; then",
-                    "    pid=`cat "+pidPath+"`",
-                    "    if ! ps -p $pid > /dev/null < /dev/null; then",
-                    "        # no exit status, and not executing; give a few seconds grace in case just about to write exit status",
-                    "        sleep 3",
-                    "        if test -s "+exitStatusPath+"; then",
-                    "            cat "+exitStatusPath+"",
-                    "        else",
-                    "            echo \"No exit status in "+exitStatusPath+", and pid in "+pidPath+" ($pid) not executing\"",
-                    "            exit 1",
-                    "        fi",
-                    "    fi",
-                    "else",
-                    "    echo \"No exit status in "+exitStatusPath+", and "+pidPath+" is empty\"",
-                    "    exit 1",
-                    "fi"+"\n");
-            String cmd = Joiner.on("\n").join(cmdParts);
-
-            MutableList.Builder<String> cmds = MutableList.<String>builder()
-                    .add((runAsRoot ? BashCommands.sudo(cmd) : cmd))
-                    .add("RESULT=$?");
-            cmds.add("exit $RESULT");
-            return cmds.build();
-        }
-
-        /**
-         * Builds the command to retrieve the stdout and stderr of the async command.
-         * An offset can be given, to only retrieve data starting at a particular character (indexed from 0).
-         */
-        protected List<String> buildRetrieveStdoutAndStderrCommand(int stdoutPosition, int stderrPosition) {
-            // Note that `tail -c +1` means start at the *first* character (i.e. start counting from 1, not 0)
-            String catStdoutCmd = "tail -c +"+(stdoutPosition+1)+" "+stdoutPath+" 2> /dev/null";
-            String catStderrCmd = "tail -c +"+(stderrPosition+1)+" "+stderrPath+" 2>&1 > /dev/null";
-            MutableList.Builder<String> cmds = MutableList.<String>builder()
-                    .add((runAsRoot ? BashCommands.sudo(catStdoutCmd) : catStdoutCmd))
-                    .add((runAsRoot ? BashCommands.sudo(catStderrCmd) : catStderrCmd))
-                    .add("RESULT=$?");
-            cmds.add("exit $RESULT");
-            return cmds.build();
-        }
-
-        /**
-         * Builds the command to retrieve the stdout and stderr of the async command.
-         * An offset can be given, to only retrieve data starting at a particular character (indexed from 0).
-         */
-        protected List<String> buildLongPollCommand(int stdoutPosition, int stderrPosition, Duration timeout) {
-            long maxTime = Math.max(1, timeout.toSeconds());
-            
-            // Note that `tail -c +1` means start at the *first* character (i.e. start counting from 1, not 0)
-            List<String> waitForExitStatusParts = ImmutableList.of(
-                    //Should be careful here because any output will be part of the stdout/stderr streams
-                    "# Long poll", // comment is to aid testing - see SshjToolAsyncStubIntegrationTest
-                    // disown to avoid Terminated message after killing the process
-                    // redirect error output to avoid "file truncated" messages
-                    "tail -c +"+(stdoutPosition+1)+" -f "+stdoutPath+" 2> /dev/null & export TAIL_STDOUT_PID=$!; disown",
-                    "tail -c +"+(stderrPosition+1)+" -f "+stderrPath+" 1>&2 2> /dev/null & export TAIL_STDERR_PID=$!; disown",
-                    "EXIT_STATUS_PATH="+exitStatusPath,
-                    "PID_PATH="+pidPath,
-                    "MAX_TIME="+maxTime,
-                    "COUNTER=0",
-                    "while [ \"$COUNTER\" -lt $MAX_TIME ]; do",
-                    "    if test -s $EXIT_STATUS_PATH; then",
-                    "        EXIT_STATUS=`cat $EXIT_STATUS_PATH`",
-                    "        kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID} 2> /dev/null",
-                    "        exit $EXIT_STATUS",
-                    "    elif test -s $PID_PATH; then",
-                    "        PID=`cat $PID_PATH`",
-                    "        if ! ps -p $PID > /dev/null 2>&1 < /dev/null; then",
-                    "            # no exit status, and not executing; give a few seconds grace in case just about to write exit status",
-                    "            sleep 3",
-                    "            if test -s $EXIT_STATUS_PATH; then",
-                    "                EXIT_STATUS=`cat $EXIT_STATUS_PATH`",
-                    "                kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID} 2> /dev/null",
-                    "                exit $EXIT_STATUS",
-                    "            else",
-                    "                echo \"No exit status in $EXIT_STATUS_PATH, and pid in $PID_PATH ($PID) not executing\"",
-                    "                kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID} 2> /dev/null",
-                    "                exit 126",
-                    "            fi",
-                    "        fi",
-                    "    fi",
-                    "    # No exit status in $EXIT_STATUS_PATH; keep waiting",
-                    "    sleep 1",
-                    "    COUNTER+=1",
-                    "done",
-                    "kill ${TAIL_STDERR_PID} ${TAIL_STDOUT_PID} 2> /dev/null",
-                    "exit 125"+"\n");
-            String waitForExitStatus = Joiner.on("\n").join(waitForExitStatusParts);
-
-            return ImmutableList.of(runAsRoot ? BashCommands.sudo(waitForExitStatus) : waitForExitStatus);
-        }
-
-        protected List<String> deleteTemporaryFilesCommand() {
-            ImmutableList.Builder<String> cmdParts = ImmutableList.builder();
-            
-            if (!Boolean.TRUE.equals(noDeleteAfterExec)) {
-                // use "-f" because some systems have "rm" aliased to "rm -i"
-                // use "< /dev/null" to guarantee doesn't hang
-                cmdParts.add(
-                        "rm -f "+scriptPath+" "+stdoutPath+" "+stderrPath+" "+exitStatusPath+" "+pidPath+" < /dev/null");
-            }
-            
-            // If the buildLongPollCommand didn't complete properly then it might have left tail command running;
-            // ensure they are killed.
-            cmdParts.add(
-                    //ignore error output for the case where there are no running processes and kill is called without arguments
-                    "ps aux | grep \"tail -c\" | grep \""+stdoutPath+"\" | grep -v grep | awk '{ printf $2 }' | xargs kill 2> /dev/null",
-                    "ps aux | grep \"tail -c\" | grep \""+stderrPath+"\" | grep -v grep | awk '{ printf $2 }' | xargs kill 2> /dev/null");
-
-            String cmd = Joiner.on("\n").join(cmdParts.build());
-            
-            return ImmutableList.of(runAsRoot ? BashCommands.sudo(cmd) : cmd);
-        }
-
-        @Override
-        public abstract int run();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/ShellTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/ShellTool.java b/core/src/main/java/brooklyn/util/internal/ssh/ShellTool.java
deleted file mode 100644
index 0555039..0000000
--- a/core/src/main/java/brooklyn/util/internal/ssh/ShellTool.java
+++ /dev/null
@@ -1,113 +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 brooklyn.util.internal.ssh;
-
-import static brooklyn.entity.basic.ConfigKeys.newConfigKey;
-import static brooklyn.entity.basic.ConfigKeys.newStringConfigKey;
-
-import java.io.OutputStream;
-import java.util.List;
-import java.util.Map;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.os.Os;
-import brooklyn.util.time.Duration;
-
-/** Methods for executing things in an environment (localhost process, or ssh) */
-public interface ShellTool {
-
-    // config which applies to sessions
-    
-    public static final ConfigKey<String> PROP_LOCAL_TEMP_DIR = newStringConfigKey(
-            "localTempDir", 
-            "The directory on the local machine (i.e. running brooklyn) for writing temp files", 
-            Os.mergePaths(Os.tmp(), "brooklyn-"+Os.user()+"-ssh-tmp"));
-    
-    // config which applies to calls:
-    
-    public static final ConfigKey<Boolean> PROP_RUN_AS_ROOT = newConfigKey("runAsRoot", "When running a script, whether to run as root", Boolean.FALSE);
-    
-    public static final ConfigKey<OutputStream> PROP_OUT_STREAM = newConfigKey(OutputStream.class, "out", "Stream to which to capture stdout");
-    public static final ConfigKey<OutputStream> PROP_ERR_STREAM = newConfigKey(OutputStream.class, "err", "Stream to which to capture stderr");
-    
-    public static final ConfigKey<Boolean> PROP_NO_EXTRA_OUTPUT = newConfigKey("noExtraOutput", "Suppresses any decorative output such as result code which some tool commands insert", false);
-    
-    public static final ConfigKey<String> PROP_SEPARATOR = newConfigKey("separator", "string to insert between caller-supplied commands being executed as commands", " ; ");
-    
-    public static final ConfigKey<String> PROP_SCRIPT_DIR = newConfigKey("scriptDir", "directory where scripts should be copied", "/tmp");
-    public static final ConfigKey<String> PROP_SCRIPT_HEADER = newConfigKey("scriptHeader", "lines to insert at the start of scripts generated for caller-supplied commands for script execution", "#!/bin/bash -e\n");
-    public static final ConfigKey<String> PROP_DIRECT_HEADER = newConfigKey("directHeader", "commands to run at the target before any caller-supplied commands for direct execution", "exec bash -e");
-
-    ConfigKey<Boolean> PROP_NO_DELETE_SCRIPT = newConfigKey("noDeleteAfterExec", "Retains the generated script file after executing the commands instead of deleting it", false);
-
-    ConfigKey<String> PROP_SUMMARY = ConfigKeys.newStringConfigKey("summary", "Provides a human-readable summary, used in file generation etc");
-    
-    ConfigKey<Duration> PROP_EXEC_TIMEOUT = newConfigKey("execTimeout", "Timeout when executing a script", Duration.PRACTICALLY_FOREVER);
-
-    ConfigKey<Boolean> PROP_EXEC_ASYNC = newConfigKey("execAsync", "Executes the script asynchronously, and then polls for the result (and for stdout/stderr)", false);
-
-    ConfigKey<Duration> PROP_EXEC_ASYNC_POLLING_TIMEOUT = newConfigKey("execAsyncPollTimeout", "Timeout per poll when executing a script asynchronously", Duration.ONE_MINUTE);
-
-    /**
-     * Executes the set of commands in a shell script. Blocks until completion.
-     * <p>
-     * 
-     * Optional properties are the same common ones as for {@link #execCommands(Map, List, Map)} with the addition of:
-     * <ul>
-     * <li>{@link #PROP_RUN_AS_ROOT}
-     * <li>{@link #PROP_SCRIPT_DIR}
-     * </ul>
-     * 
-     * @return exit status of script
-     */
-    public int execScript(Map<String,?> props, List<String> commands, Map<String,?> env);
-
-    /**
-     * @see #execScript(Map, List, Map)
-     */
-    public int execScript(Map<String,?> props, List<String> commands);
-
-    /**
-     * Executes the set of commands using ssh exec.
-     * 
-     * This is generally more efficient than ssh shell mode (cf {@link #execScript(Map, List, Map)}), 
-     * but is not suitable if you need env values which are only set on a fully-fledged shell,
-     * or if you want the entire block executed with root permission.
-     *
-     * Common optional properties (which also apply to {@link #execScript(Map, List, Map)}) are:
-     * <ul>
-     * <li>{@link #PROP_OUT_STREAM}
-     * <li>{@link #PROP_ERR_STREAM}
-     * <li>{@link #PROP_SEPARATOR} (for some modes)
-     * <li>{@link #PROP_NO_EXTRA_OUTPUT} (often there is no extra output here)
-     * </ul>
-     * 
-     * Note that {@link #PROP_RUN_AS_ROOT} is <i>not</i> typically supported here. Prefer {@link #execScript(Map, List, Map)}).
-     * 
-     * @return exit status of commands
-     */
-    public int execCommands(Map<String,?> properties, List<String> commands, Map<String,?> env);
-
-    /**
-     * @see #execCommands(Map, List, Map)
-     */
-    public int execCommands(Map<String,?> properties, List<String> commands);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/SshAbstractTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/SshAbstractTool.java b/core/src/main/java/brooklyn/util/internal/ssh/SshAbstractTool.java
deleted file mode 100644
index eb0222a..0000000
--- a/core/src/main/java/brooklyn/util/internal/ssh/SshAbstractTool.java
+++ /dev/null
@@ -1,172 +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 brooklyn.util.internal.ssh;
-
-import static brooklyn.util.net.Networking.checkPortValid;
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.File;
-import java.util.Map;
-import java.util.Set;
-
-import brooklyn.util.os.Os;
-
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
-
-public abstract class SshAbstractTool extends ShellAbstractTool implements SshTool {
-
-    protected final String toString;
-
-    protected final String host;
-    protected final String user;
-    protected final String password;
-    protected final int port;
-    protected String privateKeyPassphrase;
-    protected String privateKeyData;
-    protected File privateKeyFile;
-    protected boolean strictHostKeyChecking;
-    protected boolean allocatePTY;
-
-    public static interface SshAction<T> {
-        void clear() throws Exception;
-        T create() throws Exception;
-    }
-
-    public static abstract class AbstractSshToolBuilder<T extends SshTool, B extends AbstractSshToolBuilder<T,B>> {
-        protected String host;
-        protected int port = 22;
-        protected String user = System.getProperty("user.name");
-        protected String password;
-        protected String privateKeyData;
-        protected String privateKeyPassphrase;
-        protected Set<String> privateKeyFiles = Sets.newLinkedHashSet();
-        protected boolean strictHostKeyChecking = false;
-        protected boolean allocatePTY = false;
-        protected File localTempDir = null;
-
-        @SuppressWarnings("unchecked")
-        protected B self() {
-           return (B) this;
-        }
-
-        public B from(Map<String,?> props) {
-            host = getMandatoryVal(props, PROP_HOST);
-            port = getOptionalVal(props, PROP_PORT);
-            user = getOptionalVal(props, PROP_USER);
-            
-            password = getOptionalVal(props, PROP_PASSWORD);
-            
-            warnOnDeprecated(props, "privateKey", "privateKeyData");
-            privateKeyData = getOptionalVal(props, PROP_PRIVATE_KEY_DATA);
-            privateKeyPassphrase = getOptionalVal(props, PROP_PRIVATE_KEY_PASSPHRASE);
-            
-            // for backwards compatibility accept keyFiles and privateKey
-            // but sshj accepts only a single privateKeyFile; leave blank to use defaults (i.e. ~/.ssh/id_rsa and id_dsa)
-            warnOnDeprecated(props, "keyFiles", null);
-            String privateKeyFile = getOptionalVal(props, PROP_PRIVATE_KEY_FILE);
-            if (privateKeyFile != null) privateKeyFiles.add(privateKeyFile);
-            
-            strictHostKeyChecking = getOptionalVal(props, PROP_STRICT_HOST_KEY_CHECKING);
-            allocatePTY = getOptionalVal(props, PROP_ALLOCATE_PTY);
-            
-            String localTempDirPath = getOptionalVal(props, PROP_LOCAL_TEMP_DIR);
-            localTempDir = (localTempDirPath == null) ? null : new File(Os.tidyPath(localTempDirPath));
-            
-            return self();
-        }
-        public B host(String val) {
-            this.host = val; return self();
-        }
-        public B user(String val) {
-            this.user = val; return self();
-        }
-        public B password(String val) {
-            this.password = val; return self();
-        }
-        public B port(int val) {
-            this.port = val; return self();
-        }
-        public B privateKeyPassphrase(String val) {
-            this.privateKeyPassphrase = val; return self();
-        }
-        /** @deprecated 1.4.0, use privateKeyData */
-        public B privateKey(String val) {
-            this.privateKeyData = val; return self();
-        }
-        public B privateKeyData(String val) {
-            this.privateKeyData = val; return self();
-        }
-        public B privateKeyFile(String val) {
-            this.privateKeyFiles.add(val); return self();
-        }
-        public B localTempDir(File val) {
-            this.localTempDir = val; return self();
-        }
-        public abstract T build();
-    }
-
-    protected SshAbstractTool(AbstractSshToolBuilder<?,?> builder) {
-        super(builder.localTempDir);
-        
-        host = checkNotNull(builder.host, "host");
-        port = builder.port;
-        user = builder.user;
-        password = builder.password;
-        strictHostKeyChecking = builder.strictHostKeyChecking;
-        allocatePTY = builder.allocatePTY;
-        privateKeyPassphrase = builder.privateKeyPassphrase;
-        privateKeyData = builder.privateKeyData;
-        
-        if (builder.privateKeyFiles.size() > 1) {
-            throw new IllegalArgumentException("sshj supports only a single private key-file; " +
-                    "for defaults of ~/.ssh/id_rsa and ~/.ssh/id_dsa leave blank");
-        } else if (builder.privateKeyFiles.size() == 1) {
-            String privateKeyFileStr = Iterables.get(builder.privateKeyFiles, 0);
-            String amendedKeyFile = privateKeyFileStr.startsWith("~") ? (System.getProperty("user.home")+privateKeyFileStr.substring(1)) : privateKeyFileStr;
-            privateKeyFile = new File(amendedKeyFile);
-        } else {
-            privateKeyFile = null;
-        }
-        
-        checkArgument(host.length() > 0, "host value must not be an empty string");
-        checkPortValid(port, "ssh port");
-        
-        toString = String.format("%s@%s:%d", user, host, port);
-    }
-
-    @Override
-    public String toString() {
-        return toString;
-    }
-
-    public String getHostAddress() {
-        return this.host;
-    }
-
-    public String getUsername() {
-        return this.user;
-    }
-
-    protected SshException propagate(Exception e, String message) throws SshException {
-        throw new SshException("(" + toString() + ") " + message + ": " + e.getMessage(), e);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/SshException.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/SshException.java b/core/src/main/java/brooklyn/util/internal/ssh/SshException.java
deleted file mode 100644
index 20653bb..0000000
--- a/core/src/main/java/brooklyn/util/internal/ssh/SshException.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 brooklyn.util.internal.ssh;
-
-public class SshException extends RuntimeException {
-
-    private static final long serialVersionUID = -5690230838066860965L;
-
-    public SshException(String msg) {
-        super(msg);
-    }
-    
-    public SshException(String msg, Throwable cause) {
-        super(msg, cause);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/SshTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/SshTool.java b/core/src/main/java/brooklyn/util/internal/ssh/SshTool.java
deleted file mode 100644
index a676599..0000000
--- a/core/src/main/java/brooklyn/util/internal/ssh/SshTool.java
+++ /dev/null
@@ -1,174 +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 brooklyn.util.internal.ssh;
-
-import static brooklyn.entity.basic.ConfigKeys.newConfigKey;
-import static brooklyn.entity.basic.ConfigKeys.newStringConfigKey;
-
-import java.io.File;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Map;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.stream.KnownSizeInputStream;
-import brooklyn.util.time.Duration;
-
-/**
- * Defines the methods available on the various different implementations of SSH,
- * and configuration options which are also generally available.
- * <p>
- * The config keys in this class can be supplied (or their string equivalents, where the flags/props take {@code Map<String,?>})
- * to influence configuration, either for the tool/session itself or for individual commands.
- * <p>
- * To specify some of these properties on a global basis, use the variants of the keys here
- * contained in {@link ConfigKeys}
- * (which are generally {@value #BROOKLYN_CONFIG_KEY_PREFIX} prefixed to the names of keys here).
- */
-public interface SshTool extends ShellTool {
-    
-    /** Public-facing global config keys for Brooklyn are defined in ConfigKeys, 
-     * and have this prefix pre-prended to the config keys in this class. 
-     * These keys are detected from entity/global config and automatically applied to ssh executions. */
-    public static final String BROOKLYN_CONFIG_KEY_PREFIX = "brooklyn.ssh.config.";
-    
-    public static final ConfigKey<String> PROP_TOOL_CLASS = newStringConfigKey("tool.class", "SshTool implementation to use", null);
-    
-    public static final ConfigKey<String> PROP_HOST = newStringConfigKey("host", "Host to connect to (required)", null);
-    public static final ConfigKey<Integer> PROP_PORT = newConfigKey("port", "Port on host to connect to", 22);
-    public static final ConfigKey<String> PROP_USER = newConfigKey("user", "User to connect as", System.getProperty("user.name"));
-    public static final ConfigKey<String> PROP_PASSWORD = newStringConfigKey("password", "Password to use to connect", null);
-    
-    public static final ConfigKey<String> PROP_PRIVATE_KEY_FILE = newStringConfigKey("privateKeyFile", "the path of an ssh private key file; leave blank to use defaults (i.e. ~/.ssh/id_rsa and id_dsa)", null);
-    public static final ConfigKey<String> PROP_PRIVATE_KEY_DATA = newStringConfigKey("privateKeyData", "the private ssh key (e.g. contents of an id_rsa or id_dsa file)", null);
-    public static final ConfigKey<String> PROP_PRIVATE_KEY_PASSPHRASE = newStringConfigKey("privateKeyPassphrase", "the passphrase for the ssh private key", null);
-    public static final ConfigKey<Boolean> PROP_STRICT_HOST_KEY_CHECKING = newConfigKey("strictHostKeyChecking", "whether to check the remote host's identification; defaults to false", false);
-    public static final ConfigKey<Boolean> PROP_ALLOCATE_PTY = newConfigKey("allocatePTY", "whether to allocate PTY (vt100); if true then stderr is sent to stdout, but sometimes required for sudo'ing due to requiretty", false);
-
-    public static final ConfigKey<Long> PROP_CONNECT_TIMEOUT = newConfigKey("connectTimeout", "Timeout in millis when establishing an SSH connection; if 0 then uses default (usually 30s)", 0L);
-    public static final ConfigKey<Long> PROP_SESSION_TIMEOUT = newConfigKey("sessionTimeout", "Timeout in millis for an ssh session; if 0 then uses default", 0L);
-    public static final ConfigKey<Integer> PROP_SSH_TRIES = newConfigKey("sshTries", "Max number of times to attempt ssh operations", 4);
-    public static final ConfigKey<Long> PROP_SSH_TRIES_TIMEOUT = newConfigKey("sshTriesTimeout", "Time limit for attempting retries; will not interrupt tasks, but stops retrying after a total amount of elapsed time", Duration.TWO_MINUTES.toMilliseconds());
-    public static final ConfigKey<Long> PROP_SSH_RETRY_DELAY = newConfigKey("sshRetryDelay", "Time (in milliseconds) before first ssh-retry, after which it will do exponential backoff", 50L);
-
-    // NB -- items above apply for _session_ (a tool), below apply for a _call_
-    // TODO would be nice to track which arguments are used, so we can indicate whether extras are supplied
-
-    public static final ConfigKey<String> PROP_PERMISSIONS = newConfigKey("permissions", "Default permissions for files copied/created on remote machine; must be four-digit octal string, default '0644'", "0644");
-    public static final ConfigKey<Long> PROP_LAST_MODIFICATION_DATE = newConfigKey("lastModificationDate", "Last-modification-date to be set on files copied/created (should be UTC/1000, ie seconds since 1970; default 0 usually means current)", 0L);
-    public static final ConfigKey<Long> PROP_LAST_ACCESS_DATE = newConfigKey("lastAccessDate", "Last-access-date to be set on files copied/created (should be UTC/1000, ie seconds since 1970; default 0 usually means lastModificationDate)", 0L);
-    public static final ConfigKey<Integer> PROP_OWNER_UID = newConfigKey("ownerUid", "Default owner UID (not username) for files created on remote machine; default is unset", -1);
-    
-    // TODO remove unnecessary "public static final" modifiers
-    
-    // TODO Could define the following in SshMachineLocation, or some such?
-    //public static ConfigKey<String> PROP_LOG_PREFIX = newStringKey("logPrefix", "???", ???);
-    //public static ConfigKey<Boolean> PROP_NO_STDOUT_LOGGING = newStringKey("noStdoutLogging", "???", ???);
-    //public static ConfigKey<Boolean> PROP_NO_STDOUT_LOGGING = newStringKey("noStdoutLogging", "???", ???);
-
-    /**
-     * @throws SshException
-     */
-    public void connect();
-
-    /**
-     * @deprecated since 0.7.0; (since much earlier) this ignores the argument in favour of {@link #PROP_SSH_TRIES}
-     * 
-     * @param maxAttempts
-     * @throws SshException
-     */
-    public void connect(int maxAttempts);
-
-    public void disconnect();
-
-    public boolean isConnected();
-
-    /**
-     * @see super{@link #execScript(Map, List, Map)}
-     * @throws SshException If failed to connect
-     */
-    @Override
-    public int execScript(Map<String,?> props, List<String> commands, Map<String,?> env);
-
-    /**
-     * @see #execScript(Map, List, Map)
-     */
-    @Override
-    public int execScript(Map<String,?> props, List<String> commands);
-
-    /**
-     * @see super{@link #execCommands(Map, List, Map)}
-     * @throws SshException If failed to connect
-     */
-    @Override
-    public int execCommands(Map<String,?> properties, List<String> commands, Map<String,?> env);
-
-    /**
-     * @see #execCommands(Map, List, Map)
-     */
-    @Override
-    public int execCommands(Map<String,?> properties, List<String> commands);
-
-    /**
-     * Copies the file to the server at the given path.
-     * If path is null, empty, '.', '..', or ends with '/' then file name is used.
-     * <p>
-     * The file will not preserve the permission of last _access_ date.
-     * 
-     * Optional properties are:
-     * <ul>
-     *   <li>'permissions' (e.g. "0644") - see {@link #PROP_PERMISSIONS}
-     *   <li>'lastModificationDate' see {@link #PROP_LAST_MODIFICATION_DATE}; not supported by all SshTool implementations
-     *   <li>'lastAccessDate' see {@link #PROP_LAST_ACCESS_DATE}; not supported by all SshTool implementations
-     * </ul>
-     * 
-     * @return exit code (not supported by all SshTool implementations, usually throwing on error;
-     * sometimes possibly returning 0 even on error (?) )
-     */
-    public int copyToServer(Map<String,?> props, File localFile, String pathAndFileOnRemoteServer);
-
-    /**
-     * Closes the given input stream before returning.
-     * Consider using {@link KnownSizeInputStream} for efficiency when the size of the stream is known.
-     * 
-     * @see #copyToServer(Map, File, String)
-     */
-    public int copyToServer(Map<String,?> props, InputStream contents, String pathAndFileOnRemoteServer);
-
-    /**
-     * @see #copyToServer(Map, File, String)
-     */
-    public int copyToServer(Map<String,?> props, byte[] contents, String pathAndFileOnRemoteServer);
-
-    /**
-     * Copies the file from the server at the given path.
-     *
-     * @return exit code (not supported by all SshTool implementations, usually throwing on error;
-     * sometimes possibly returning 0 even on error (?) )
-     */
-    public int copyFromServer(Map<String,?> props, String pathAndFileOnRemoteServer, File local);
-
-    // TODO might be more efficicent than copyFrom by way of temp file
-//    /**
-//     * Reads from the file at the given path on the remote server.
-//     */
-//    public InputStream streamFromServer(Map<String,?> props, String pathAndFileOnRemoteServer);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/cli/SshCliTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/cli/SshCliTool.java b/core/src/main/java/brooklyn/util/internal/ssh/cli/SshCliTool.java
deleted file mode 100644
index 91b5d91..0000000
--- a/core/src/main/java/brooklyn/util/internal/ssh/cli/SshCliTool.java
+++ /dev/null
@@ -1,316 +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 brooklyn.util.internal.ssh.cli;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.File;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.internal.ssh.SshAbstractTool;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.internal.ssh.process.ProcessTool;
-import brooklyn.util.text.StringEscapes.BashStringEscapes;
-import brooklyn.util.text.Strings;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-/**
- * For ssh and scp commands, delegating to system calls.
- */
-public class SshCliTool extends SshAbstractTool implements SshTool {
-
-    // TODO No retry support, with backoffLimitedRetryHandler
-    
-    private static final Logger LOG = LoggerFactory.getLogger(SshCliTool.class);
-
-    public static final ConfigKey<String> PROP_SSH_EXECUTABLE = ConfigKeys.newStringConfigKey("sshExecutable", "command to execute for ssh (defaults to \"ssh\", but could be overridden to sshg3 for Tectia for example)", "ssh");
-    public static final ConfigKey<String> PROP_SSH_FLAGS = ConfigKeys.newStringConfigKey("sshFlags", "flags to pass to ssh, as a space separated list", "");
-    public static final ConfigKey<String> PROP_SCP_EXECUTABLE = ConfigKeys.newStringConfigKey("scpExecutable", "command to execute for scp (defaults to \"scp\", but could be overridden to scpg3 for Tectia for example)", "scp");
-
-    public static Builder<SshCliTool,?> builder() {
-        return new ConcreteBuilder();
-    }
-    
-    private static class ConcreteBuilder extends Builder<SshCliTool, ConcreteBuilder> {
-    }
-    
-    public static class Builder<T extends SshCliTool, B extends Builder<T,B>> extends AbstractSshToolBuilder<T,B> {
-        private String sshExecutable;
-        private String sshFlags;
-        private String scpExecutable;
-
-        @Override
-        public B from(Map<String,?> props) {
-            super.from(props);
-            sshExecutable = getOptionalVal(props, PROP_SSH_EXECUTABLE);
-            sshFlags = getOptionalVal(props, PROP_SSH_FLAGS);
-            scpExecutable = getOptionalVal(props, PROP_SCP_EXECUTABLE);
-            return self();
-        }
-        public B sshExecutable(String val) {
-            this.sshExecutable = val; return self();
-        }
-        public B scpExecutable(String val) {
-            this.scpExecutable = val; return self();
-        }
-        @SuppressWarnings("unchecked")
-        public T build() {
-            return (T) new SshCliTool(this);
-        }
-    }
-
-    private final String sshExecutable;
-    private final String sshFlags;
-    private final String scpExecutable;
-
-    public SshCliTool(Map<String,?> map) {
-        this(builder().from(map));
-    }
-    
-    private SshCliTool(Builder<?,?> builder) {
-        super(builder);
-        sshExecutable = checkNotNull(builder.sshExecutable);
-        sshFlags = checkNotNull(builder.sshFlags);
-        scpExecutable = checkNotNull(builder.scpExecutable);
-        if (LOG.isTraceEnabled()) LOG.trace("Created SshCliTool {} ({})", this, System.identityHashCode(this));
-    }
-    
-    @Override
-    public void connect() {
-        // no-op
-    }
-
-    @Override
-    public void connect(int maxAttempts) {
-        // no-op
-    }
-
-    @Override
-    public void disconnect() {
-        if (LOG.isTraceEnabled()) LOG.trace("Disconnecting SshCliTool {} ({}) - no-op", this, System.identityHashCode(this));
-        // no-op
-    }
-
-    @Override
-    public boolean isConnected() {
-        // TODO Always pretends to be connected
-        return true;
-    }
-
-    @Override
-    public int copyToServer(java.util.Map<String,?> props, byte[] contents, String pathAndFileOnRemoteServer) {
-        return copyTempFileToServer(props, writeTempFile(contents), pathAndFileOnRemoteServer);
-    }
-    
-    @Override
-    public int copyToServer(java.util.Map<String,?> props, InputStream contents, String pathAndFileOnRemoteServer) {
-        return copyTempFileToServer(props, writeTempFile(contents), pathAndFileOnRemoteServer);
-    }
-    
-    @Override
-    public int copyToServer(Map<String,?> props, File f, String pathAndFileOnRemoteServer) {
-        if (hasVal(props, PROP_LAST_MODIFICATION_DATE)) {
-            LOG.warn("Unsupported ssh feature, setting lastModificationDate for {}:{}", this, pathAndFileOnRemoteServer);
-        }
-        if (hasVal(props, PROP_LAST_ACCESS_DATE)) {
-            LOG.warn("Unsupported ssh feature, setting lastAccessDate for {}:{}", this, pathAndFileOnRemoteServer);
-        }
-        String permissions = getOptionalVal(props, PROP_PERMISSIONS);
-        
-        int uid = getOptionalVal(props, PROP_OWNER_UID);
-        
-        int result = scpToServer(props, f, pathAndFileOnRemoteServer);
-        if (result == 0) {
-            result = chmodOnServer(props, permissions, pathAndFileOnRemoteServer);
-            if (result == 0) {
-                if (uid != -1) {
-                    result = chownOnServer(props, uid, pathAndFileOnRemoteServer);
-                    if (result != 0) {
-                        LOG.warn("Error setting file owner to {}, after copying file {} to {}:{}; exit code {}", new Object[] { uid, pathAndFileOnRemoteServer, this, f, result });
-                    }
-                }
-            } else {
-                LOG.warn("Error setting file permissions to {}, after copying file {} to {}:{}; exit code {}", new Object[] { permissions, pathAndFileOnRemoteServer, this, f, result });
-            }
-        } else {
-            LOG.warn("Error copying file {} to {}:{}; exit code {}", new Object[] {pathAndFileOnRemoteServer, this, f, result});
-        }
-        return result;
-    }
-
-    private int chownOnServer(Map<String,?> props, int uid, String remote) {
-        return sshExec(props, "chown "+uid+" "+remote);
-    }
-    
-    private int copyTempFileToServer(Map<String,?> props, File f, String pathAndFileOnRemoteServer) {
-        try {
-            return copyToServer(props, f, pathAndFileOnRemoteServer);
-        } finally {
-            f.delete();
-        }
-    }
-
-    @Override
-    public int copyFromServer(Map<String,?> props, String pathAndFileOnRemoteServer, File localFile) {
-        return scpFromServer(props, pathAndFileOnRemoteServer, localFile);
-    }
-
-    @Override
-    public int execScript(final Map<String,?> props, final List<String> commands, final Map<String,?> env) {
-        return new ToolAbstractExecScript(props) {
-            public int run() {
-                String scriptContents = toScript(props, commands, env);
-                if (LOG.isTraceEnabled()) LOG.trace("Running shell command at {} as script: {}", host, scriptContents);
-                copyTempFileToServer(ImmutableMap.of("permissions", "0700"), writeTempFile(scriptContents), scriptPath);
-
-                String cmd = Strings.join(buildRunScriptCommand(), separator);
-                return asInt(sshExec(props, cmd), -1);
-            }
-        }.run();
-    }
-
-    @Override
-    public int execCommands(Map<String,?> props, List<String> commands, Map<String,?> env) {
-        Map<String,Object> props2 = new MutableMap<String,Object>();
-        if (props!=null) props2.putAll(props);
-        props2.put(SshTool.PROP_NO_EXTRA_OUTPUT.getName(), true);
-        return execScript(props2, commands, env);
-    }
-    
-    private int scpToServer(Map<String,?> props, File local, String remote) {
-        String to = (Strings.isEmpty(getUsername()) ? "" : getUsername()+"@")+getHostAddress()+":"+remote;
-        return scpExec(props, local.getAbsolutePath(), to);
-    }
-
-    private int scpFromServer(Map<String,?> props, String remote, File local) {
-        String from = (Strings.isEmpty(getUsername()) ? "" : getUsername()+"@")+getHostAddress()+":"+remote;
-        return scpExec(props, from, local.getAbsolutePath());
-    }
-    
-    private int chmodOnServer(Map<String,?> props, String permissions, String remote) {
-        return sshExec(props, "chmod "+permissions+" "+remote);
-    }
-
-    private int scpExec(Map<String,?> props, String from, String to) {
-        File tempFile = null;
-        try {
-            List<String> cmd = Lists.newArrayList();
-            cmd.add(getOptionalVal(props, PROP_SCP_EXECUTABLE, scpExecutable));
-            if (privateKeyFile != null) {
-                cmd.add("-i");
-                cmd.add(privateKeyFile.getAbsolutePath());
-            } else if (privateKeyData != null) {
-                tempFile = writeTempFile(privateKeyData);
-                cmd.add("-i");
-                cmd.add(tempFile.getAbsolutePath());
-            }
-            if (!strictHostKeyChecking) {
-                cmd.add("-o");
-                cmd.add("StrictHostKeyChecking=no");
-            }
-            if (port != 22) {
-                cmd.add("-P");
-                cmd.add(""+port);
-            }
-            cmd.add(from);
-            cmd.add(to);
-            
-            if (LOG.isTraceEnabled()) LOG.trace("Executing with command: {}", cmd);
-            int result = execProcess(props, cmd);
-            
-            if (LOG.isTraceEnabled()) LOG.trace("Executed command: {}; exit code {}", cmd, result);
-            return result;
-
-        } finally {
-            if (tempFile != null) tempFile.delete();
-        }
-    }
-    
-    private int sshExec(Map<String,?> props, String command) {
-        File tempKeyFile = null;
-        try {
-            List<String> cmd = Lists.newArrayList();
-            cmd.add(getOptionalVal(props, PROP_SSH_EXECUTABLE, sshExecutable));
-            String propsFlags = getOptionalVal(props, PROP_SSH_FLAGS, sshFlags);
-            if (propsFlags!=null && propsFlags.trim().length()>0)
-                cmd.addAll(Arrays.asList(propsFlags.trim().split(" ")));
-            if (privateKeyFile != null) {
-                cmd.add("-i");
-                cmd.add(privateKeyFile.getAbsolutePath());
-            } else if (privateKeyData != null) {
-                tempKeyFile = writeTempFile(privateKeyData);
-                cmd.add("-i");
-                cmd.add(tempKeyFile.getAbsolutePath());
-            }
-            if (!strictHostKeyChecking) {
-                cmd.add("-o");
-                cmd.add("StrictHostKeyChecking=no");
-            }
-            if (port != 22) {
-                cmd.add("-P");
-                cmd.add(""+port);
-            }
-            if (allocatePTY) {
-                // have to be careful with double -tt as it can leave a shell session active
-                // when done from bash (ie  ssh -tt localhost < /tmp/myscript.sh);
-                // hover that doesn't seem to be a problem the way we use it from brooklyn
-                // (and note single -t doesn't work _programmatically_ since the input isn't a terminal)
-                cmd.add("-tt");
-            }
-            cmd.add((Strings.isEmpty(getUsername()) ? "" : getUsername()+"@")+getHostAddress());
-            
-            cmd.add("bash -c "+BashStringEscapes.wrapBash(command));
-            // previously we tried these approaches:
-            //cmd.add("$(<"+tempCmdFile.getAbsolutePath()+")");
-            // only pays attention to the first word; the "; echo Executing ..." get treated as arguments
-            // to the script in the first word, when invoked from java (when invoked from prompt the behaviour is as desired)
-            //cmd.add("\""+command+"\"");
-            // only works if command is a single word
-            //cmd.add(tempCmdFile.getAbsolutePath());
-            // above of course only works if the metafile is copied across
-            
-            if (LOG.isTraceEnabled()) LOG.trace("Executing ssh with command: {} (with {})", command, cmd);
-            int result = execProcess(props, cmd);
-            
-            if (LOG.isTraceEnabled()) LOG.trace("Executed command: {}; exit code {}", cmd, result);
-            return result;
-            
-        } finally {
-            if (tempKeyFile != null) tempKeyFile.delete();
-        }
-    }
-
-    private int execProcess(Map<String,?> props, List<String> cmdWords) {
-        OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
-        OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
-        return ProcessTool.execSingleProcess(cmdWords, null, (File)null, out, err, this);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/process/ProcessTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/process/ProcessTool.java b/core/src/main/java/brooklyn/util/internal/ssh/process/ProcessTool.java
deleted file mode 100644
index 90de9f2..0000000
--- a/core/src/main/java/brooklyn/util/internal/ssh/process/ProcessTool.java
+++ /dev/null
@@ -1,214 +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 brooklyn.util.internal.ssh.process;
-
-import static brooklyn.entity.basic.ConfigKeys.newConfigKey;
-import static brooklyn.entity.basic.ConfigKeys.newStringConfigKey;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.internal.ssh.ShellAbstractTool;
-import brooklyn.util.internal.ssh.ShellTool;
-import brooklyn.util.internal.ssh.SshException;
-import brooklyn.util.os.Os;
-import brooklyn.util.stream.StreamGobbler;
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Joiner;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Throwables;
-import com.google.common.io.ByteSource;
-import com.google.common.io.ByteStreams;
-import com.google.common.io.Files;
-
-/** Implementation of {@link ShellTool} which runs locally. */
-public class ProcessTool extends ShellAbstractTool implements ShellTool {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ProcessTool.class);
-
-    // applies to calls
-    
-    public static final ConfigKey<Boolean> PROP_LOGIN_SHELL = newConfigKey("loginShell", "Causes the commands to be invoked with bash arguments to forcea  login shell", Boolean.FALSE);
-
-    public static final ConfigKey<String> PROP_DIRECTORY = newStringConfigKey("directory", "the working directory, for executing commands", null);
-    
-    public ProcessTool() {
-        this(null);
-    }
-    
-    public ProcessTool(Map<String,?> flags) {
-        super(getOptionalVal(flags, PROP_LOCAL_TEMP_DIR));
-        if (flags!=null) {
-            MutableMap<String, Object> flags2 = MutableMap.copyOf(flags);
-            // TODO should remember other flags here?  (e.g. NO_EXTRA_OUTPUT, RUN_AS_ROOT, etc)
-            flags2.remove(PROP_LOCAL_TEMP_DIR.getName());
-            if (!flags2.isEmpty())
-                LOG.warn(""+this+" ignoring unsupported constructor flags: "+flags);
-        }
-    }
-
-    @Override
-    public int execScript(final Map<String,?> props, final List<String> commands, final Map<String,?> env) {
-        return new ToolAbstractExecScript(props) {
-            public int run() {
-                try {
-                    String directory = getOptionalVal(props, PROP_DIRECTORY);
-                    File directoryDir = (directory != null) ? new File(Os.tidyPath(directory)) : null;
-                    
-                    String scriptContents = toScript(props, commands, env);
-
-                    if (LOG.isTraceEnabled()) LOG.trace("Running shell process (process) as script:\n{}", scriptContents);
-                    File to = new File(scriptPath);
-                    Files.createParentDirs(to);
-                    ByteSource.wrap(scriptContents.getBytes()).copyTo(Files.asByteSink(to));
-
-                    List<String> cmds = buildRunScriptCommand();
-                    cmds.add(0, "chmod +x "+scriptPath);
-                    return asInt(execProcesses(cmds, null, directoryDir, out, err, separator, getOptionalVal(props, PROP_LOGIN_SHELL), this), -1);
-                } catch (IOException e) {
-                    throw Throwables.propagate(e);
-                }
-            }
-        }.run();
-    }
-
-    @Override
-    public int execCommands(Map<String,?> props, List<String> commands, Map<String,?> env) {
-        if (Boolean.FALSE.equals(props.get("blocks"))) {
-            throw new IllegalArgumentException("Cannot exec non-blocking: command="+commands);
-        }
-        OutputStream out = getOptionalVal(props, PROP_OUT_STREAM);
-        OutputStream err = getOptionalVal(props, PROP_ERR_STREAM);
-        String separator = getOptionalVal(props, PROP_SEPARATOR);
-        String directory = getOptionalVal(props, PROP_DIRECTORY);
-        File directoryDir = (directory != null) ? new File(Os.tidyPath(directory)) : null;
-
-        List<String> allcmds = toCommandSequence(commands, null);
-
-        String singlecmd = Joiner.on(separator).join(allcmds);
-        if (Boolean.TRUE.equals(getOptionalVal(props, PROP_RUN_AS_ROOT))) {
-            LOG.warn("Cannot run as root when executing as command; run as a script instead (will run as normal user): "+singlecmd);
-        }
-        if (LOG.isTraceEnabled()) LOG.trace("Running shell command (process): {}", singlecmd);
-        
-        return asInt(execProcesses(allcmds, env, directoryDir, out, err, separator, getOptionalVal(props, PROP_LOGIN_SHELL), this), -1);
-    }
-
-    /**
-     * as {@link #execProcesses(List, Map, OutputStream, OutputStream, String, boolean, Object)} but not using a login shell
-     * @deprecated since 0.7; use {@link #execProcesses(List, Map, File, OutputStream, OutputStream, String, boolean, Object)}
-     */
-    @Deprecated
-    public static int execProcesses(List<String> cmds, Map<String,?> env, OutputStream out, OutputStream err, String separator, Object contextForLogging) {
-        return execProcesses(cmds, env, (File)null, out, err, separator, false, contextForLogging);
-    }
-
-    /**
-     * @deprecated since 0.7; use {@link #execProcesses(List, Map, File, OutputStream, OutputStream, String, boolean, Object)}
-     */
-    @Deprecated
-    public static int execProcesses(List<String> cmds, Map<String,?> env, OutputStream out, OutputStream err, String separator, boolean asLoginShell, Object contextForLogging) {
-        return execProcesses(cmds, env, (File)null, out, err, separator, asLoginShell, contextForLogging);
-    }
-    
-    /** executes a set of commands by sending them as a single process to `bash -c` 
-     * (single command argument of all the commands, joined with separator)
-     * <p>
-     * consequence of this is that you should not normally need to escape things oddly in your commands, 
-     * type them just as you would into a bash shell (if you find exceptions please note them here!)
-     */
-    public static int execProcesses(List<String> cmds, Map<String,?> env, File directory, OutputStream out, OutputStream err, String separator, boolean asLoginShell, Object contextForLogging) {
-        MutableList<String> commands = new MutableList<String>().append("bash");
-        if (asLoginShell) commands.append("-l");
-        commands.append("-c", Strings.join(cmds, Preconditions.checkNotNull(separator, "separator")));
-        return execSingleProcess(commands, env, directory, out, err, contextForLogging);
-    }
-    
-    /**
-     * @deprecated since 0.7; use {@link #execSingleProcess(List, Map, File, OutputStream, OutputStream, Object)}
-     */
-    @Deprecated
-    public static int execSingleProcess(List<String> cmdWords, Map<String,?> env, OutputStream out, OutputStream err, Object contextForLogging) {
-        return execSingleProcess(cmdWords, env, (File)null, out, err, contextForLogging);
-    }
-    
-    /** executes a single process made up of the given command words (*not* bash escaped);
-     * should be portable across OS's */
-    public static int execSingleProcess(List<String> cmdWords, Map<String,?> env, File directory, OutputStream out, OutputStream err, Object contextForLogging) {
-        StreamGobbler errgobbler = null;
-        StreamGobbler outgobbler = null;
-        
-        ProcessBuilder pb = new ProcessBuilder(cmdWords);
-        if (env!=null) {
-            for (Map.Entry<String,?> kv: env.entrySet()) pb.environment().put(kv.getKey(), String.valueOf(kv.getValue())); 
-        }
-        if (directory != null) {
-            pb.directory(directory);
-        }
-        
-        try {
-            Process p = pb.start();
-            
-            if (out != null) {
-                InputStream outstream = p.getInputStream();
-                outgobbler = new StreamGobbler(outstream, out, (Logger) null);
-                outgobbler.start();
-            }
-            if (err != null) {
-                InputStream errstream = p.getErrorStream();
-                errgobbler = new StreamGobbler(errstream, err, (Logger) null);
-                errgobbler.start();
-            }
-            
-            int result = p.waitFor();
-            
-            if (outgobbler != null) outgobbler.blockUntilFinished();
-            if (errgobbler != null) errgobbler.blockUntilFinished();
-            
-            if (result==255)
-                // this is not definitive, but tests (and code?) expects throw exception if can't connect;
-                // only return exit code when it is exit code from underlying process;
-                // we have no way to distinguish 255 from ssh failure from 255 from the command run through ssh ...
-                // but probably 255 is from CLI ssh
-                throw new SshException("exit code 255 from CLI ssh; probably failed to connect");
-            
-            return result;
-        } catch (InterruptedException e) {
-            throw Exceptions.propagate(e);
-        } catch (IOException e) {
-            throw Exceptions.propagate(e);
-        } finally {
-            closeWhispering(outgobbler, contextForLogging, "execProcess");
-            closeWhispering(errgobbler, contextForLogging, "execProcess");
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjClientConnection.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjClientConnection.java b/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjClientConnection.java
deleted file mode 100644
index 982022a..0000000
--- a/core/src/main/java/brooklyn/util/internal/ssh/sshj/SshjClientConnection.java
+++ /dev/null
@@ -1,282 +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 brooklyn.util.internal.ssh.sshj;
-
-import static com.google.common.base.Objects.equal;
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.File;
-import java.io.IOException;
-
-import net.schmizz.sshj.SSHClient;
-import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
-import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
-import net.schmizz.sshj.userauth.password.PasswordUtils;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.GroovyJavaMethods;
-import brooklyn.util.internal.ssh.SshAbstractTool.SshAction;
-
-import com.google.common.base.Objects;
-import com.google.common.net.HostAndPort;
-
-/** based on code from jclouds */
-public class SshjClientConnection implements SshAction<SSHClient> {
-
-    private static final Logger LOG = LoggerFactory.getLogger(SshjClientConnection.class);
-
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    public static class Builder {
-
-        protected HostAndPort hostAndPort;
-        protected String username;
-        protected String password;
-        protected String privateKeyPassphrase;
-        protected String privateKeyData;
-        protected File privateKeyFile;
-        protected long connectTimeout;
-        protected long sessionTimeout;
-        protected boolean strictHostKeyChecking;
-
-        public Builder hostAndPort(HostAndPort hostAndPort) {
-            this.hostAndPort = hostAndPort;
-            return this;
-        }
-
-        public Builder username(String username) {
-            this.username = username;
-            return this;
-        }
-
-        public Builder password(String val) {
-            this.password = val;
-            return this;
-        }
-
-        /** @deprecated use privateKeyData */
-        public Builder privateKey(String val) {
-            this.privateKeyData = val;
-            return this;
-        }
-
-        public Builder privateKeyPassphrase(String val) {
-            this.privateKeyPassphrase = val;
-            return this;
-        }
-        
-        public Builder privateKeyData(String val) {
-            this.privateKeyData = val;
-            return this;
-        }
-        
-        public Builder privateKeyFile(File val) {
-            this.privateKeyFile = val;
-            return this;
-        }
-        
-        public Builder strictHostKeyChecking(boolean val) {
-            this.strictHostKeyChecking = val;
-            return this;
-        }
-
-        public Builder connectTimeout(long connectTimeout) {
-            this.connectTimeout = connectTimeout;
-            return this;
-        }
-
-        public Builder sessionTimeout(long sessionTimeout) {
-            this.sessionTimeout = sessionTimeout;
-            return this;
-        }
-
-        public SshjClientConnection build() {
-            return new SshjClientConnection(this);
-        }
-
-        protected static Builder fromSSHClientConnection(SshjClientConnection in) {
-            return new Builder().hostAndPort(in.getHostAndPort()).connectTimeout(in.getConnectTimeout()).sessionTimeout(
-                    in.getSessionTimeout()).username(in.username).password(in.password).privateKey(in.privateKeyData).privateKeyFile(in.privateKeyFile);
-        }
-    }
-
-    private final HostAndPort hostAndPort;
-    private final String username;
-    private final String password;
-    private final String privateKeyPassphrase;
-    private final String privateKeyData;
-    private final File privateKeyFile;
-    private final boolean strictHostKeyChecking;
-    private final int connectTimeout;
-    private final int sessionTimeout;
-    
-    SSHClient ssh;
-
-    private SshjClientConnection(Builder builder) {
-        this.hostAndPort = checkNotNull(builder.hostAndPort);
-        this.username = builder.username;
-        this.password = builder.password;
-        this.privateKeyPassphrase = builder.privateKeyPassphrase;
-        this.privateKeyData = builder.privateKeyData;
-        this.privateKeyFile = builder.privateKeyFile;
-        this.strictHostKeyChecking = builder.strictHostKeyChecking;
-        this.connectTimeout = checkInt("connectTimeout", builder.connectTimeout, Integer.MAX_VALUE);
-        this.sessionTimeout = checkInt("sessionTimeout", builder.sessionTimeout, Integer.MAX_VALUE);
-    }
-
-    static Integer checkInt(String context, long value, Integer ifTooLarge) {
-        if (value > Integer.MAX_VALUE) {
-            LOG.warn("Value '"+value+"' for "+context+" too large in SshjClientConnection; using "+value);
-            return ifTooLarge;
-        }
-        return (int)value;
-    }
-
-    public boolean isConnected() {
-        return ssh != null && ssh.isConnected();
-    }
-
-    public boolean isAuthenticated() {
-        return ssh != null && ssh.isAuthenticated();
-    }
-
-    @Override
-    public void clear() {
-        if (ssh != null && ssh.isConnected()) {
-            try {
-                if (LOG.isTraceEnabled()) LOG.trace("Disconnecting SshjClientConnection {} ({})", this, System.identityHashCode(this));
-                ssh.disconnect();
-            } catch (IOException e) {
-                if (LOG.isDebugEnabled()) LOG.debug("<< exception disconnecting from {}: {}", e, e.getMessage());
-            }
-        }
-        ssh = null;
-    }
-
-    @Override
-    public SSHClient create() throws Exception {
-        if (LOG.isTraceEnabled()) LOG.trace("Connecting SshjClientConnection {} ({})", this, System.identityHashCode(this));
-        ssh = new net.schmizz.sshj.SSHClient();
-        if (!strictHostKeyChecking) {
-            ssh.addHostKeyVerifier(new PromiscuousVerifier());
-        }
-        if (connectTimeout != 0) {
-            ssh.setConnectTimeout(connectTimeout);
-        }
-        if (sessionTimeout != 0) {
-            ssh.setTimeout(sessionTimeout);
-        }
-        ssh.connect(hostAndPort.getHostText(), hostAndPort.getPortOrDefault(22));
-        
-        if (password != null) {
-            ssh.authPassword(username, password);
-        } else if (privateKeyData != null) {
-            OpenSSHKeyFile key = new OpenSSHKeyFile();
-            key.init(privateKeyData, null, 
-                    GroovyJavaMethods.truth(privateKeyPassphrase) ? 
-                            PasswordUtils.createOneOff(privateKeyPassphrase.toCharArray())
-                            : null);
-            ssh.authPublickey(username, key);
-        } else if (privateKeyFile != null) {
-            OpenSSHKeyFile key = new OpenSSHKeyFile();
-            key.init(privateKeyFile, 
-                    GroovyJavaMethods.truth(privateKeyPassphrase) ? 
-                            PasswordUtils.createOneOff(privateKeyPassphrase.toCharArray())
-                            : null);
-            ssh.authPublickey(username, key);
-        } else {
-            // Accept defaults (in ~/.ssh)
-            ssh.authPublickey(username);
-        }
-        
-        return ssh;
-    }
-
-    /**
-     * @return host and port, where port if not present defaults to {@code 22}
-     */
-    public HostAndPort getHostAndPort() {
-        return hostAndPort;
-    }
-
-    /**
-     * @return username used in this ssh
-     */
-    public String getUsername() {
-        return username;
-    }
-
-    /**
-     * 
-     * @return how long to wait for the initial connection to be made
-     */
-    public int getConnectTimeout() {
-        return connectTimeout;
-    }
-
-    /**
-     * 
-     * @return how long to keep the ssh open, or {@code 0} for indefinitely
-     */
-    public int getSessionTimeout() {
-        return sessionTimeout;
-    }
-
-    /**
-     * 
-     * @return the current ssh or {@code null} if not connected
-     */
-    public SSHClient getSSHClient() {
-        return ssh;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o)
-            return true;
-        if (o == null || getClass() != o.getClass())
-            return false;
-        SshjClientConnection that = SshjClientConnection.class.cast(o);
-        return equal(this.hostAndPort, that.hostAndPort) && equal(this.username, that.username) 
-                && equal(this.password, that.password) && equal(this.privateKeyData, that.privateKeyData)
-                && equal(this.privateKeyFile, that.privateKeyFile) && equal(this.ssh, that.ssh);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(hostAndPort, username, password, privateKeyData, ssh);
-    }
-
-    @Override
-    public String toString() {
-        return Objects.toStringHelper("")
-                .add("hostAndPort", hostAndPort)
-                .add("user", username)
-                .add("ssh", ssh != null ? ssh.hashCode() : null)
-                .add("password", (password != null ? "xxxxxx" : null))
-                .add("privateKeyFile", privateKeyFile)
-                .add("privateKey", (privateKeyData != null ? "xxxxxx" : null))
-                .add("connectTimeout", connectTimeout)
-                .add("sessionTimeout", sessionTimeout).toString();
-    }
-}


[21/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/osgi/Osgis.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/osgi/Osgis.java b/core/src/main/java/org/apache/brooklyn/core/util/osgi/Osgis.java
new file mode 100644
index 0000000..849a33b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/osgi/Osgis.java
@@ -0,0 +1,720 @@
+/*
+ * 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.util.osgi;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarInputStream;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import javax.annotation.Nullable;
+
+import org.apache.felix.framework.FrameworkFactory;
+import org.apache.felix.framework.util.StringMap;
+import org.apache.felix.framework.util.manifestparser.ManifestParser;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.framework.launch.Framework;
+import org.osgi.framework.namespace.PackageNamespace;
+import org.osgi.framework.wiring.BundleCapability;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.api.catalog.CatalogItem.CatalogBundle;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.osgi.Osgis;
+
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.exceptions.ReferenceWithError;
+import brooklyn.util.guava.Maybe;
+import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Strings;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Joiner;
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.base.Stopwatch;
+
+/** 
+ * utilities for working with osgi.
+ * osgi support is in early days (June 2014) so this class is beta, subject to change,
+ * particularly in how framework is started and bundles installed.
+ * 
+ * @since 0.7.0  */
+@Beta
+public class Osgis {
+    private static final Logger LOG = LoggerFactory.getLogger(Osgis.class);
+
+    private static final String EXTENSION_PROTOCOL = "system";
+    private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF";
+    private static final Set<String> SYSTEM_BUNDLES = MutableSet.of();
+
+    public static class VersionedName {
+        private final String symbolicName;
+        private final Version version;
+        public VersionedName(Bundle b) {
+            this.symbolicName = b.getSymbolicName();
+            this.version = b.getVersion();
+        }
+        public VersionedName(String symbolicName, Version version) {
+            this.symbolicName = symbolicName;
+            this.version = version;
+        }
+        @Override public String toString() {
+            return symbolicName + ":" + Strings.toString(version);
+        }
+        public boolean equals(String sn, String v) {
+            return symbolicName.equals(sn) && (version == null && v == null || version != null && version.toString().equals(v));
+        }
+        public boolean equals(String sn, Version v) {
+            return symbolicName.equals(sn) && (version == null && v == null || version != null && version.equals(v));
+        }
+        public String getSymbolicName() {
+            return symbolicName;
+        }
+        public Version getVersion() {
+            return version;
+        }
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(symbolicName, version);
+        }
+        @Override
+        public boolean equals(Object other) {
+            if (!(other instanceof VersionedName)) return false;
+            VersionedName o = (VersionedName) other;
+            return Objects.equal(symbolicName, o.symbolicName) && Objects.equal(version, o.version);
+        }
+    }
+    
+    public static class BundleFinder {
+        protected final Framework framework;
+        protected String symbolicName;
+        protected String version;
+        protected String url;
+        protected boolean urlMandatory = false;
+        protected final List<Predicate<? super Bundle>> predicates = MutableList.of();
+        
+        protected BundleFinder(Framework framework) {
+            this.framework = framework;
+        }
+
+        public BundleFinder symbolicName(String symbolicName) {
+            this.symbolicName = symbolicName;
+            return this;
+        }
+
+        public BundleFinder version(String version) {
+            this.version = version;
+            return this;
+        }
+        
+        public BundleFinder id(String symbolicNameOptionallyWithVersion) {
+            if (Strings.isBlank(symbolicNameOptionallyWithVersion))
+                return this;
+            
+            Maybe<VersionedName> nv = parseOsgiIdentifier(symbolicNameOptionallyWithVersion);
+            if (nv.isAbsent())
+                throw new IllegalArgumentException("Cannot parse symbolic-name:version string '"+symbolicNameOptionallyWithVersion+"'");
+
+            return id(nv.get());
+        }
+
+        private BundleFinder id(VersionedName nv) {
+            symbolicName(nv.getSymbolicName());
+            if (nv.getVersion() != null) {
+                version(nv.getVersion().toString());
+            }
+            return this;
+        }
+
+        public BundleFinder bundle(CatalogBundle bundle) {
+            if (bundle.isNamed()) {
+                symbolicName(bundle.getSymbolicName());
+                version(bundle.getVersion());
+            }
+            if (bundle.getUrl() != null) {
+                requiringFromUrl(bundle.getUrl());
+            }
+            return this;
+        }
+
+        /** Looks for a bundle matching the given URL;
+         * unlike {@link #requiringFromUrl(String)} however, if the URL does not match any bundles
+         * it will return other matching bundles <i>if</if> a {@link #symbolicName(String)} is specified.
+         */
+        public BundleFinder preferringFromUrl(String url) {
+            this.url = url;
+            urlMandatory = false;
+            return this;
+        }
+
+        /** Requires the bundle to have the given URL set as its location. */
+        public BundleFinder requiringFromUrl(String url) {
+            this.url = url;
+            urlMandatory = true;
+            return this;
+        }
+
+        /** Finds the best matching bundle. */
+        public Maybe<Bundle> find() {
+            return findOne(false);
+        }
+        
+        /** Finds the matching bundle, requiring it to be unique. */
+        public Maybe<Bundle> findUnique() {
+            return findOne(true);
+        }
+
+        protected Maybe<Bundle> findOne(boolean requireExactlyOne) {
+            if (symbolicName==null && url==null)
+                throw new IllegalStateException(this+" must be given either a symbolic name or a URL");
+            
+            List<Bundle> result = findAll();
+            if (result.isEmpty())
+                return Maybe.absent("No bundle matching "+getConstraintsDescription());
+            if (requireExactlyOne && result.size()>1)
+                return Maybe.absent("Multiple bundles ("+result.size()+") matching "+getConstraintsDescription());
+            
+            return Maybe.of(result.get(0));
+        }
+        
+        /** Finds all matching bundles, in decreasing version order. */
+        public List<Bundle> findAll() {
+            boolean urlMatched = false;
+            List<Bundle> result = MutableList.of();
+            for (Bundle b: framework.getBundleContext().getBundles()) {
+                if (symbolicName!=null && !symbolicName.equals(b.getSymbolicName())) continue;
+                if (version!=null && !Version.parseVersion(version).equals(b.getVersion())) continue;
+                for (Predicate<? super Bundle> predicate: predicates) {
+                    if (!predicate.apply(b)) continue;
+                }
+
+                // check url last, because if it isn't mandatory we should only clear if we find a url
+                // for which the other items also match
+                if (url!=null) {
+                    boolean matches = url.equals(b.getLocation());
+                    if (urlMandatory) {
+                        if (!matches) continue;
+                        else urlMatched = true;
+                    } else {
+                        if (matches) {
+                            if (!urlMatched) {
+                                result.clear();
+                                urlMatched = true;
+                            }
+                        } else {
+                            if (urlMatched) {
+                                // can't use this bundle as we have previously found a preferred bundle, with a matching url
+                                continue;
+                            }
+                        }
+                    }
+                }
+                                
+                result.add(b);
+            }
+            
+            if (symbolicName==null && url!=null && !urlMatched) {
+                // if we only "preferred" the url, and we did not match it, and we did not have a symbolic name,
+                // then clear the results list!
+                result.clear();
+            }
+
+            Collections.sort(result, new Comparator<Bundle>() {
+                @Override
+                public int compare(Bundle o1, Bundle o2) {
+                    return o2.getVersion().compareTo(o1.getVersion());
+                }
+            });
+            
+            return result;
+        }
+        
+        public String getConstraintsDescription() {
+            List<String> parts = MutableList.of();
+            if (symbolicName!=null) parts.add("symbolicName="+symbolicName);
+            if (version!=null) parts.add("version="+version);
+            if (url!=null)
+                parts.add("url["+(urlMandatory ? "required" : "preferred")+"]="+url);
+            if (!predicates.isEmpty())
+                parts.add("predicates="+predicates);
+            return Joiner.on(";").join(parts);
+        }
+        
+        public String toString() {
+            return getClass().getCanonicalName()+"["+getConstraintsDescription()+"]";
+        }
+
+        public BundleFinder version(final Predicate<Version> versionPredicate) {
+            return satisfying(new Predicate<Bundle>() {
+                @Override
+                public boolean apply(Bundle input) {
+                    return versionPredicate.apply(input.getVersion());
+                }
+            });
+        }
+        
+        public BundleFinder satisfying(Predicate<? super Bundle> predicate) {
+            predicates.add(predicate);
+            return this;
+        }
+    }
+    
+    public static BundleFinder bundleFinder(Framework framework) {
+        return new BundleFinder(framework);
+    }
+
+    /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
+    public static List<Bundle> getBundlesByName(Framework framework, String symbolicName, Predicate<Version> versionMatcher) {
+        return bundleFinder(framework).symbolicName(symbolicName).version(versionMatcher).findAll();
+    }
+
+    /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
+    public static List<Bundle> getBundlesByName(Framework framework, String symbolicName) {
+        return bundleFinder(framework).symbolicName(symbolicName).findAll();
+    }
+
+    /**
+     * Tries to find a bundle in the given framework with name matching either `name' or `name:version'.
+     * @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
+    public static Maybe<Bundle> getBundle(Framework framework, String symbolicNameOptionallyWithVersion) {
+        return bundleFinder(framework).id(symbolicNameOptionallyWithVersion).find();
+    }
+    
+    /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
+    public static Maybe<Bundle> getBundle(Framework framework, String symbolicName, String version) {
+        return bundleFinder(framework).symbolicName(symbolicName).version(version).find();
+    }
+
+    /** @deprecated since 0.7.0 use {@link #bundleFinder(Framework)} */ @Deprecated
+    public static Maybe<Bundle> getBundle(Framework framework, String symbolicName, Version version) {
+        return bundleFinder(framework).symbolicName(symbolicName).version(Predicates.equalTo(version)).findUnique();
+    }
+
+    // -------- creating
+    
+    /*
+     * loading framework factory and starting framework based on:
+     * http://felix.apache.org/documentation/subprojects/apache-felix-framework/apache-felix-framework-launching-and-embedding.html
+     */
+    
+    public static FrameworkFactory newFrameworkFactory() {
+        URL url = Osgis.class.getClassLoader().getResource(
+                "META-INF/services/org.osgi.framework.launch.FrameworkFactory");
+        if (url != null) {
+            try {
+                BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
+                try {
+                    for (String s = br.readLine(); s != null; s = br.readLine()) {
+                        s = s.trim();
+                        // load the first non-empty, non-commented line
+                        if ((s.length() > 0) && (s.charAt(0) != '#')) {
+                            return (FrameworkFactory) Class.forName(s).newInstance();
+                        }
+                    }
+                } finally {
+                    if (br != null) br.close();
+                }
+            } catch (Exception e) {
+                // class creation exceptions are not interesting to caller...
+                throw Exceptions.propagate(e);
+            }
+        }
+        throw new IllegalStateException("Could not find framework factory.");
+    }
+    
+    public static Framework newFrameworkStarted(String felixCacheDir, boolean clean, Map<?,?> extraStartupConfig) {
+        Map<Object,Object> cfg = MutableMap.copyOf(extraStartupConfig);
+        if (clean) cfg.put(Constants.FRAMEWORK_STORAGE_CLEAN, "onFirstInit");
+        if (felixCacheDir!=null) cfg.put(Constants.FRAMEWORK_STORAGE, felixCacheDir);
+        cfg.put(Constants.FRAMEWORK_BSNVERSION, Constants.FRAMEWORK_BSNVERSION_MULTIPLE);
+        FrameworkFactory factory = newFrameworkFactory();
+
+        Stopwatch timer = Stopwatch.createStarted();
+        Framework framework = factory.newFramework(cfg);
+        try {
+            framework.init();
+            installBootBundles(framework);
+            framework.start();
+        } catch (Exception e) {
+            // framework bundle start exceptions are not interesting to caller...
+            throw Exceptions.propagate(e);
+        }
+        LOG.debug("System bundles are: "+SYSTEM_BUNDLES);
+        LOG.debug("OSGi framework started in " + Duration.of(timer));
+        return framework;
+    }
+
+    private static void installBootBundles(Framework framework) {
+        Stopwatch timer = Stopwatch.createStarted();
+        LOG.debug("Installing OSGi boot bundles from "+Osgis.class.getClassLoader()+"...");
+        Enumeration<URL> resources;
+        try {
+            resources = Osgis.class.getClassLoader().getResources(MANIFEST_PATH);
+        } catch (IOException e) {
+            throw Exceptions.propagate(e);
+        }
+        BundleContext bundleContext = framework.getBundleContext();
+        Map<String, Bundle> installedBundles = getInstalledBundlesById(bundleContext);
+        while(resources.hasMoreElements()) {
+            URL url = resources.nextElement();
+            ReferenceWithError<?> installResult = installExtensionBundle(bundleContext, url, installedBundles, getVersionedId(framework));
+            if (installResult.hasError() && !installResult.masksErrorIfPresent()) {
+                // it's reported as a critical error, so warn here
+                LOG.warn("Unable to install manifest from "+url+": "+installResult.getError(), installResult.getError());
+            } else {
+                Object result = installResult.getWithoutError();
+                if (result instanceof Bundle) {
+                    String v = getVersionedId( (Bundle)result );
+                    SYSTEM_BUNDLES.add(v);
+                    if (installResult.hasError()) {
+                        LOG.debug(installResult.getError().getMessage()+(result!=null ? " ("+result+"/"+v+")" : ""));
+                    } else {
+                        LOG.debug("Installed "+v+" from "+url);
+                    }
+                } else if (installResult.hasError()) {
+                    LOG.debug(installResult.getError().getMessage());
+                }
+            }
+        }
+        LOG.debug("Installed OSGi boot bundles in "+Time.makeTimeStringRounded(timer)+": "+Arrays.asList(framework.getBundleContext().getBundles()));
+    }
+
+    private static Map<String, Bundle> getInstalledBundlesById(BundleContext bundleContext) {
+        Map<String, Bundle> installedBundles = new HashMap<String, Bundle>();
+        Bundle[] bundles = bundleContext.getBundles();
+        for (Bundle b : bundles) {
+            installedBundles.put(getVersionedId(b), b);
+        }
+        return installedBundles;
+    }
+
+    /** Wraps the bundle if successful or already installed, wraps TRUE if it's the system entry,
+     * wraps null if the bundle is already installed from somewhere else;
+     * in all these cases <i>masking</i> an explanatory error if already installed or it's the system entry.
+     * <p>
+     * Returns an instance wrapping null and <i>throwing</i> an error if the bundle could not be installed.
+     */
+    private static ReferenceWithError<?> installExtensionBundle(BundleContext bundleContext, URL manifestUrl, Map<String, Bundle> installedBundles, String frameworkVersionedId) {
+        //ignore http://felix.extensions:9/ system entry
+        if("felix.extensions".equals(manifestUrl.getHost())) 
+            return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Skipping install of internal extension bundle from "+manifestUrl));
+
+        try {
+            Manifest manifest = readManifest(manifestUrl);
+            if (!isValidBundle(manifest)) 
+                return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Resource at "+manifestUrl+" is not an OSGi bundle: no valid manifest"));
+            
+            String versionedId = getVersionedId(manifest);
+            URL bundleUrl = ResourceUtils.getContainerUrl(manifestUrl, MANIFEST_PATH);
+
+            Bundle existingBundle = installedBundles.get(versionedId);
+            if (existingBundle != null) {
+                if (!bundleUrl.equals(existingBundle.getLocation()) &&
+                        //the framework bundle is always pre-installed, don't display duplicate info
+                        !versionedId.equals(frameworkVersionedId)) {
+                    return ReferenceWithError.newInstanceMaskingError(null, new IllegalArgumentException("Bundle "+versionedId+" (from manifest " + manifestUrl + ") is already installed, from " + existingBundle.getLocation()));
+                }
+                return ReferenceWithError.newInstanceMaskingError(existingBundle, new IllegalArgumentException("Bundle "+versionedId+" from manifest " + manifestUrl + " is already installed"));
+            }
+            
+            byte[] jar = buildExtensionBundle(manifest);
+            LOG.debug("Installing boot bundle " + bundleUrl);
+            //mark the bundle as extension so we can detect it later using the "system:" protocol
+            //(since we cannot access BundleImpl.isExtension)
+            Bundle newBundle = bundleContext.installBundle(EXTENSION_PROTOCOL + ":" + bundleUrl.toString(), new ByteArrayInputStream(jar));
+            installedBundles.put(versionedId, newBundle);
+            return ReferenceWithError.newInstanceWithoutError(newBundle);
+        } catch (Exception e) {
+            Exceptions.propagateIfFatal(e);
+            return ReferenceWithError.newInstanceThrowingError(null, 
+                new IllegalStateException("Problem installing extension bundle " + manifestUrl + ": "+e, e));
+        }
+    }
+
+    private static Manifest readManifest(URL manifestUrl) throws IOException {
+        Manifest manifest;
+        InputStream in = null;
+        try {
+            in = manifestUrl.openStream();
+            manifest = new Manifest(in);
+        } finally {
+            if (in != null) {
+                try {in.close();} 
+                catch (Exception e) {};
+            }
+        }
+        return manifest;
+    }
+
+    private static byte[] buildExtensionBundle(Manifest manifest) throws IOException {
+        Attributes atts = manifest.getMainAttributes();
+
+        //the following properties are invalid in extension bundles
+        atts.remove(new Attributes.Name(Constants.IMPORT_PACKAGE));
+        atts.remove(new Attributes.Name(Constants.REQUIRE_BUNDLE));
+        atts.remove(new Attributes.Name(Constants.BUNDLE_NATIVECODE));
+        atts.remove(new Attributes.Name(Constants.DYNAMICIMPORT_PACKAGE));
+        atts.remove(new Attributes.Name(Constants.BUNDLE_ACTIVATOR));
+        
+        //mark as extension bundle
+        atts.putValue(Constants.FRAGMENT_HOST, "system.bundle; extension:=framework");
+
+        //create the jar containing the manifest
+        ByteArrayOutputStream jar = new ByteArrayOutputStream();
+        JarOutputStream out = new JarOutputStream(jar, manifest);
+        out.close();
+        return jar.toByteArray();
+    }
+
+    private static boolean isValidBundle(Manifest manifest) {
+        Attributes atts = manifest.getMainAttributes();
+        return atts.containsKey(new Attributes.Name(Constants.BUNDLE_MANIFESTVERSION));
+    }
+
+    private static String getVersionedId(Bundle b) {
+        return b.getSymbolicName() + ":" + b.getVersion();
+    }
+
+    private static String getVersionedId(Manifest manifest) {
+        Attributes atts = manifest.getMainAttributes();
+        return atts.getValue(Constants.BUNDLE_SYMBOLICNAME) + ":" +
+            atts.getValue(Constants.BUNDLE_VERSION);
+    }
+
+    /**
+     * Installs a bundle from the given URL, doing a check if already installed, and
+     * using the {@link ResourceUtils} loader for this project (brooklyn core)
+     */
+    public static Bundle install(Framework framework, String url) throws BundleException {
+        boolean isLocal = isLocalUrl(url);
+        String localUrl = url;
+        if (!isLocal) {
+            localUrl = cacheFile(url);
+        }
+
+        try {
+            Bundle bundle = getInstalledBundle(framework, localUrl);
+            if (bundle != null) {
+                return bundle;
+            }
+    
+            // use our URL resolution so we get classpath items
+            LOG.debug("Installing bundle into {} from url: {}", framework, url);
+            InputStream stream = getUrlStream(localUrl);
+            Bundle installedBundle = framework.getBundleContext().installBundle(url, stream);
+            
+            return installedBundle;
+        } finally {
+            if (!isLocal) {
+                try {
+                    new File(new URI(localUrl)).delete();
+                } catch (URISyntaxException e) {
+                    throw Exceptions.propagate(e);
+                }
+            }
+        }
+    }
+
+    private static String cacheFile(String url) {
+        InputStream in = getUrlStream(url);
+        File cache = Os.writeToTempFile(in, "bundle-cache", "jar");
+        return cache.toURI().toString();
+    }
+
+    private static boolean isLocalUrl(String url) {
+        String protocol = Urls.getProtocol(url);
+        return "file".equals(protocol) ||
+                "classpath".equals(protocol) ||
+                "jar".equals(protocol);
+    }
+
+    private static Bundle getInstalledBundle(Framework framework, String url) {
+        Bundle bundle = framework.getBundleContext().getBundle(url);
+        if (bundle != null) {
+            return bundle;
+        }
+
+        // We now support same version installed multiple times (avail since OSGi 4.3+).
+        // However we do not support overriding *system* bundles, ie anything already on the classpath.
+        // If we wanted to disable multiple versions, see comments below, and reference to FRAMEWORK_BSNVERSION_MULTIPLE above.
+        
+        // Felix already assumes the stream is pointing to a JAR
+        JarInputStream stream;
+        try {
+            stream = new JarInputStream(getUrlStream(url));
+        } catch (IOException e) {
+            throw Exceptions.propagate(e);
+        }
+        Manifest manifest = stream.getManifest();
+        Streams.closeQuietly(stream);
+        if (manifest == null) {
+            throw new IllegalStateException("Missing manifest file in bundle or not a jar file.");
+        }
+        String versionedId = getVersionedId(manifest);
+        for (Bundle installedBundle : framework.getBundleContext().getBundles()) {
+            if (versionedId.equals(getVersionedId(installedBundle))) {
+                if (SYSTEM_BUNDLES.contains(versionedId)) {
+                    LOG.debug("Already have system bundle "+versionedId+" from "+installedBundle+"/"+installedBundle.getLocation()+" when requested "+url+"; not installing");
+                    // "System bundles" (ie things on the classpath) cannot be overridden
+                    return installedBundle;
+                } else {
+                    LOG.debug("Already have bundle "+versionedId+" from "+installedBundle+"/"+installedBundle.getLocation()+" when requested "+url+"; but it is not a system bundle so proceeding");
+                    // Other bundles can be installed multiple times. To ignore multiples and continue to use the old one, 
+                    // just return the installedBundle as done just above for system bundles.
+                }
+            }
+        }
+        return null;
+    }
+
+    private static InputStream getUrlStream(String url) {
+        return ResourceUtils.create(Osgis.class).getResourceFromUrl(url);
+    }
+    
+    public static boolean isExtensionBundle(Bundle bundle) {
+        String location = bundle.getLocation();
+        return location != null && 
+                EXTENSION_PROTOCOL.equals(Urls.getProtocol(location));
+    }
+
+    /** Takes a string which might be of the form "symbolic-name" or "symbolic-name:version" (or something else entirely)
+     * and returns a VersionedName. The versionedName.getVersion() will be null if if there was no version in the input
+     * (or returning {@link Maybe#absent()} if not valid, with a suitable error message). */
+    public static Maybe<VersionedName> parseOsgiIdentifier(String symbolicNameOptionalWithVersion) {
+        if (Strings.isBlank(symbolicNameOptionalWithVersion))
+            return Maybe.absent("OSGi identifier is blank");
+        
+        String[] parts = symbolicNameOptionalWithVersion.split(":");
+        if (parts.length>2)
+            return Maybe.absent("OSGi identifier has too many parts; max one ':' symbol");
+        
+        Version v = null;
+        if (parts.length == 2) {
+            try {
+                v = Version.parseVersion(parts[1]);
+            } catch (IllegalArgumentException e) {
+                return Maybe.absent("OSGi identifier has invalid version string ("+e.getMessage()+")");
+            }
+        }
+        
+        return Maybe.of(new VersionedName(parts[0], v));
+    }
+
+    /**
+     * The class is not used, staying for future reference.
+     * Remove after OSGi transition is completed.
+     */
+    public static class ManifestHelper {
+        
+        private static ManifestParser parse;
+        private Manifest manifest;
+        private String source;
+
+        private static final String WIRING_PACKAGE = PackageNamespace.PACKAGE_NAMESPACE;
+        
+        public static ManifestHelper forManifestContents(String contents) throws IOException, BundleException {
+            ManifestHelper result = forManifest(Streams.newInputStreamWithContents(contents));
+            result.source = contents;
+            return result;
+        }
+        
+        public static ManifestHelper forManifest(URL url) throws IOException, BundleException {
+            InputStream in = null;
+            try {
+                in = url.openStream();
+                return forManifest(in);
+            } finally {
+                if (in != null) in.close();
+            }
+        }
+        
+        public static ManifestHelper forManifest(InputStream in) throws IOException, BundleException {
+            return forManifest(new Manifest(in));
+        }
+
+        public static ManifestHelper forManifest(Manifest manifest) throws BundleException {
+            ManifestHelper result = new ManifestHelper();
+            result.manifest = manifest;
+            parse = new ManifestParser(null, null, null, new StringMap(manifest.getMainAttributes()));
+            return result;
+        }
+        
+        public String getSymbolicName() {
+            return parse.getSymbolicName();
+        }
+
+        public Version getVersion() {
+            return parse.getBundleVersion();
+        }
+
+        public String getSymbolicNameVersion() {
+            return getSymbolicName()+":"+getVersion();
+        }
+
+        public List<String> getExportedPackages() {
+            MutableList<String> result = MutableList.of();
+            for (BundleCapability c: parse.getCapabilities()) {
+                if (WIRING_PACKAGE.equals(c.getNamespace())) {
+                    result.add((String)c.getAttributes().get(WIRING_PACKAGE));
+                }
+            }
+            return result;
+        }
+        
+        @Nullable public String getSource() {
+            return source;
+        }
+        
+        public Manifest getManifest() {
+            return manifest;
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/AbstractExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/AbstractExecutionContext.java b/core/src/main/java/org/apache/brooklyn/core/util/task/AbstractExecutionContext.java
new file mode 100644
index 0000000..3eea5d9
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/AbstractExecutionContext.java
@@ -0,0 +1,75 @@
+/*
+ * 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.util.task;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.api.management.ExecutionManager;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskAdaptable;
+
+import com.google.common.collect.Maps;
+
+public abstract class AbstractExecutionContext implements ExecutionContext {
+
+    /**
+     * Submits the given runnable/callable/task for execution (in a separate thread);
+     * supported keys in the map include: tags (add'l tags to put on the resulting task), 
+     * description (string), and others as described in the reference below
+     *   
+     * @see ExecutionManager#submit(Map, Task) 
+     */
+    @Override
+    public Task<?> submit(Map<?,?> properties, Runnable runnable) { return submitInternal(properties, runnable); }
+    
+    /** @see #submit(Map, Runnable) */
+    @Override
+    public Task<?> submit(Runnable runnable) { return submitInternal(Maps.newLinkedHashMap(), runnable); }
+ 
+    /** @see #submit(Map, Runnable) */
+    @Override
+    public <T> Task<T> submit(Callable<T> callable) { return submitInternal(Maps.newLinkedHashMap(), callable); }
+    
+    /** @see #submit(Map, Runnable) */
+    @Override
+    public <T> Task<T> submit(Map<?,?> properties, Callable<T> callable) { return submitInternal(properties, callable); }
+ 
+    /** @see #submit(Map, Runnable) */
+    @Override
+    public <T> Task<T> submit(TaskAdaptable<T> task) { return submitInternal(Maps.newLinkedHashMap(), task.asTask()); }
+
+    /** @see #submit(Map, Runnable) */
+    @Override
+    public <T> Task<T> submit(Map<?,?> properties, TaskAdaptable<T> task) { return submitInternal(properties, task.asTask()); }
+
+    /**
+     * Provided for compatibility
+     * 
+     * Submit is preferred if a handle on the resulting Task is desired (although a task can be passed in so this is not always necessary) 
+     *
+     * @see #submit(Map, Runnable) 
+     */
+    public void execute(Runnable r) { submit(r); }
+
+    /** does the work internally of submitting the task; note that the return value may be a wrapper task even if a task is passed in,
+     * if the execution context where the target should run is different (e.g. submitting an effector task cross-context) */
+    protected abstract <T> Task<T> submitInternal(Map<?,?> properties, Object task);
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/BasicExecutionContext.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/BasicExecutionContext.java b/core/src/main/java/org/apache/brooklyn/core/util/task/BasicExecutionContext.java
new file mode 100644
index 0000000..1d28b4e
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/BasicExecutionContext.java
@@ -0,0 +1,221 @@
+/*
+ * 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.util.task;
+
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.management.ExecutionContext;
+import org.apache.brooklyn.api.management.ExecutionManager;
+import org.apache.brooklyn.api.management.HasTaskChildren;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.api.management.entitlement.EntitlementContext;
+import org.apache.brooklyn.core.management.entitlement.Entitlements;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.BrooklynTaskTags;
+import brooklyn.entity.basic.BrooklynTaskTags.WrappedEntity;
+import brooklyn.entity.basic.EntityInternal;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+
+/**
+ * A means of executing tasks against an ExecutionManager with a given bucket/set of tags pre-defined
+ * (so that it can look like an {@link Executor} and also supply {@link ExecutorService#submit(Callable)}
+ */
+public class BasicExecutionContext extends AbstractExecutionContext {
+    
+    private static final Logger log = LoggerFactory.getLogger(BasicExecutionContext.class);
+    
+    static final ThreadLocal<BasicExecutionContext> perThreadExecutionContext = new ThreadLocal<BasicExecutionContext>();
+    
+    public static BasicExecutionContext getCurrentExecutionContext() { return perThreadExecutionContext.get(); }
+
+    final ExecutionManager executionManager;
+    final Set<Object> tags = new LinkedHashSet<Object>();
+
+    public BasicExecutionContext(ExecutionManager executionManager) {
+        this(Collections.emptyMap(), executionManager);
+    }
+    
+    /**
+     * Supported flags are {@code tag} and {@code tags}
+     * 
+     * @see ExecutionManager#submit(Map, Task)
+     */
+    public BasicExecutionContext(Map<?, ?> flags, ExecutionManager executionManager) {
+        this.executionManager = executionManager;
+
+        if (flags.get("tag") != null) tags.add(flags.remove("tag"));
+        if (flags.containsKey("tags")) tags.addAll((Collection<?>)flags.remove("tags"));
+
+        // FIXME brooklyn-specific check, just for sanity
+        // the context tag should always be a non-proxy entity, because that is what is passed to effector tasks
+        // which may require access to internal methods
+        for (Object tag: tags) {
+            if (tag instanceof BrooklynTaskTags.WrappedEntity) {
+                if (Proxy.isProxyClass(((WrappedEntity)tag).entity.getClass())) {
+                    log.warn(""+this+" has entity proxy in "+tag);
+                }
+            }
+        }
+    }
+
+    public ExecutionManager getExecutionManager() {
+        return executionManager;
+    }
+    
+    /** returns tasks started by this context (or tasks which have all the tags on this object) */
+    public Set<Task<?>> getTasks() { return executionManager.getTasksWithAllTags((Set<?>)tags); }
+     
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    @Override
+    protected <T> Task<T> submitInternal(Map<?,?> propertiesQ, final Object task) {
+        if (task instanceof TaskAdaptable<?> && !(task instanceof Task<?>)) 
+            return submitInternal(propertiesQ, ((TaskAdaptable<?>)task).asTask());
+        
+        Map properties = propertiesQ;
+        if (properties.get("tags")==null) properties.put("tags", new ArrayList()); 
+        Collection taskTags = (Collection)properties.get("tags");
+        
+        // FIXME some of this is brooklyn-specific logic, should be moved to a BrooklynExecContext subclass;
+        // the issue is that we want to ensure that cross-entity calls switch execution contexts;
+        // previously it was all very messy how that was handled (and it didn't really handle it in many cases)
+        if (task instanceof Task<?>) taskTags.addAll( ((Task<?>)task).getTags() ); 
+        Entity target = BrooklynTaskTags.getWrappedEntityOfType(taskTags, BrooklynTaskTags.TARGET_ENTITY);
+        
+        if (target!=null && !tags.contains(BrooklynTaskTags.tagForContextEntity(target))) {
+            // task is switching execution context boundaries
+            /* 
+             * longer notes:
+             * you fall in to this block if the caller requests a target entity different to the current context 
+             * (e.g. where entity X is invoking an effector on Y, it will start in X's context, 
+             * but the effector should run in Y's context).
+             * 
+             * if X is invoking an effector on himself in his own context, or a sensor or other task, it will not come in to this block.
+             */
+            final ExecutionContext tc = ((EntityInternal)target).getExecutionContext();
+            if (log.isDebugEnabled())
+                log.debug("Switching task context on execution of "+task+": from "+this+" to "+target+" (in "+Tasks.current()+")");
+            
+            if (task instanceof Task<?>) {
+                final Task<T> t = (Task<T>)task;
+                if (!Tasks.isQueuedOrSubmitted(t) && (!(Tasks.current() instanceof HasTaskChildren) || 
+                        !Iterables.contains( ((HasTaskChildren)Tasks.current()).getChildren(), t ))) {
+                    // this task is switching execution context boundaries _and_ it is not a child and not yet queued,
+                    // so wrap it in a task running in this context to keep a reference to the child
+                    // (this matters when we are navigating in the GUI; without it we lose the reference to the child 
+                    // when browsing in the context of the parent)
+                    return submit(Tasks.<T>builder().name("Cross-context execution: "+t.getDescription()).dynamic(true).body(new Callable<T>() {
+                        public T call() { 
+                            return DynamicTasks.get(t); 
+                        }
+                    }).build());
+                } else {
+                    // if we are already tracked by parent, just submit it 
+                    return tc.submit(t);
+                }
+            } else {
+                // as above, but here we are definitely not a child (what we are submitting isn't even a task)
+                // (will only come here if properties defines tags including a target entity, which probably never happens) 
+                submit(Tasks.<T>builder().name("Cross-context execution").dynamic(true).body(new Callable<T>() {
+                    public T call() {
+                        if (task instanceof Callable) {
+                            return DynamicTasks.queue( Tasks.<T>builder().dynamic(false).body((Callable<T>)task).build() ).getUnchecked();
+                        } else if (task instanceof Runnable) {
+                            return DynamicTasks.queue( Tasks.<T>builder().dynamic(false).body((Runnable)task).build() ).getUnchecked();
+                        } else {
+                            throw new IllegalArgumentException("Unhandled task type: "+task+"; type="+(task!=null ? task.getClass() : "null"));
+                        }
+                    }
+                }).build());
+            }
+        }
+        
+        EntitlementContext entitlementContext = BrooklynTaskTags.getEntitlement(taskTags);
+        if (entitlementContext==null)
+        entitlementContext = Entitlements.getEntitlementContext();
+        if (entitlementContext!=null) {
+            taskTags.add(BrooklynTaskTags.tagForEntitlement(entitlementContext));
+        }
+
+        taskTags.addAll(tags);
+        
+        if (Tasks.current()!=null && BrooklynTaskTags.isTransient(Tasks.current()) 
+                && !taskTags.contains(BrooklynTaskTags.NON_TRANSIENT_TASK_TAG) && !taskTags.contains(BrooklynTaskTags.TRANSIENT_TASK_TAG)) {
+            // tag as transient if submitter is transient, unless explicitly tagged as non-transient
+            taskTags.add(BrooklynTaskTags.TRANSIENT_TASK_TAG);
+        }
+        
+        final Object startCallback = properties.get("newTaskStartCallback");
+        properties.put("newTaskStartCallback", new Function<Object,Void>() {
+            public Void apply(Object it) {
+                registerPerThreadExecutionContext();
+                if (startCallback!=null) ExecutionUtils.invoke(startCallback, it);
+                return null;
+            }});
+        
+        final Object endCallback = properties.get("newTaskEndCallback");
+        properties.put("newTaskEndCallback", new Function<Object,Void>() {
+            public Void apply(Object it) {
+                try {
+                    if (endCallback!=null) ExecutionUtils.invoke(endCallback, it);
+                } finally {
+                    clearPerThreadExecutionContext();
+                }
+                return null;
+            }});
+        
+        if (task instanceof Task) {
+            return executionManager.submit(properties, (Task)task);
+        } else if (task instanceof Callable) {
+            return executionManager.submit(properties, (Callable)task);
+        } else if (task instanceof Runnable) {
+            return (Task<T>) executionManager.submit(properties, (Runnable)task);
+        } else {
+            throw new IllegalArgumentException("Unhandled task type: task="+task+"; type="+(task!=null ? task.getClass() : "null"));
+        }
+    }
+    
+    private void registerPerThreadExecutionContext() { perThreadExecutionContext.set(this); }
+
+    private void clearPerThreadExecutionContext() { perThreadExecutionContext.remove(); }
+
+    @Override
+    public boolean isShutdown() {
+        return getExecutionManager().isShutdown();
+    }
+
+    @Override
+    public String toString() {
+        return super.toString()+"("+tags+")";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/BasicExecutionManager.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/BasicExecutionManager.java b/core/src/main/java/org/apache/brooklyn/core/util/task/BasicExecutionManager.java
new file mode 100644
index 0000000..f93abe1
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/BasicExecutionManager.java
@@ -0,0 +1,755 @@
+/*
+ * 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.util.task;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.brooklyn.api.management.ExecutionManager;
+import org.apache.brooklyn.api.management.HasTaskChildren;
+import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.text.Identifiers;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
+import com.google.common.util.concurrent.ExecutionList;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+/**
+ * Manages the execution of atomic tasks and scheduled (recurring) tasks,
+ * including setting tags and invoking callbacks.
+ */
+public class BasicExecutionManager implements ExecutionManager {
+    private static final Logger log = LoggerFactory.getLogger(BasicExecutionManager.class);
+
+    private static final boolean RENAME_THREADS = BrooklynFeatureEnablement.isEnabled(BrooklynFeatureEnablement.FEATURE_RENAME_THREADS);
+    
+    private static class PerThreadCurrentTaskHolder {
+        public static final ThreadLocal<Task<?>> perThreadCurrentTask = new ThreadLocal<Task<?>>();
+    }
+
+    public static ThreadLocal<Task<?>> getPerThreadCurrentTask() {
+        return PerThreadCurrentTaskHolder.perThreadCurrentTask;
+    }
+
+    private final ThreadFactory threadFactory;
+    
+    private final ThreadFactory daemonThreadFactory;
+    
+    private final ExecutorService runner;
+        
+    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...
+
+    //access to this field AND to members in this field is synchronized, 
+    //to allow us to preserve order while guaranteeing thread-safe
+    //(but more testing is needed before we are completely sure it is thread-safe!)
+    //synch blocks are as finely grained as possible for efficiency;
+    //NB CopyOnWriteArraySet is a perf bottleneck, and the simple map makes it easier to remove when a tag is empty
+    private Map<Object,Set<Task<?>>> tasksByTag = new HashMap<Object,Set<Task<?>>>();
+    
+    private ConcurrentMap<String,Task<?>> tasksById = new ConcurrentHashMap<String,Task<?>>();
+
+    private ConcurrentMap<Object, TaskScheduler> schedulerByTag = new ConcurrentHashMap<Object, TaskScheduler>();
+
+    /** count of all tasks submitted, including finished */
+    private final AtomicLong totalTaskCount = new AtomicLong();
+    
+    /** tasks submitted but not yet done (or in cases of interruption/cancelled not yet GC'd) */
+    private Map<String,String> incompleteTaskIds = new ConcurrentHashMap<String,String>();
+    
+    /** tasks started but not yet finished */
+    private final AtomicInteger activeTaskCount = new AtomicInteger();
+    
+    private final List<ExecutionListener> listeners = new CopyOnWriteArrayList<ExecutionListener>();
+    
+    private final static ThreadLocal<String> threadOriginalName = new ThreadLocal<String>() {
+        protected String initialValue() {
+            // should not happen, as only access is in _afterEnd with a check that _beforeStart was invoked 
+            log.warn("No original name recorded for thread "+Thread.currentThread().getName()+"; task "+Tasks.current());
+            return "brooklyn-thread-pool-"+Identifiers.makeRandomId(8);
+        }
+    };
+    
+    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, 10L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), 
+                daemonThreadFactory);
+            
+        delayedRunner = new ScheduledThreadPoolExecutor(1, daemonThreadFactory);
+    }
+    
+    private final static class UncaughtExceptionHandlerImplementation implements Thread.UncaughtExceptionHandler {
+        @Override
+        public void uncaughtException(Thread t, Throwable e) {
+            log.error("Uncaught exception in thread "+t.getName(), e);
+        }
+    }
+    
+    /** 
+     * 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 UncaughtExceptionHandlerImplementation())
+                .build();
+    }
+    
+    public void shutdownNow() {
+        runner.shutdownNow();
+        delayedRunner.shutdownNow();
+    }
+    
+    public void addListener(ExecutionListener listener) {
+        listeners.add(listener);
+    }
+    
+    public void removeListener(ExecutionListener listener) {
+        listeners.remove(listener);
+    }
+    
+    /**
+     * Deletes the given tag, including all tasks using this tag.
+     * 
+     * Useful, for example, if an entity is being expunged so that we don't keep holding
+     * a reference to it as a tag.
+     */
+    public void deleteTag(Object tag) {
+        Set<Task<?>> tasks;
+        synchronized (tasksByTag) {
+            tasks = tasksByTag.remove(tag);
+        }
+        if (tasks != null) {
+            for (Task<?> task : tasks) {
+                deleteTask(task);
+            }
+        }
+    }
+
+    public void deleteTask(Task<?> task) {
+        boolean removed = deleteTaskNonRecursive(task);
+        if (!removed) return;
+        
+        if (task instanceof HasTaskChildren) {
+            List<Task<?>> children = ImmutableList.copyOf(((HasTaskChildren)task).getChildren());
+            for (Task<?> child : children) {
+                deleteTask(child);
+            }
+        }
+    }
+
+    protected boolean deleteTaskNonRecursive(Task<?> task) {
+        Set<?> tags = checkNotNull(task, "task").getTags();
+        for (Object tag : tags) {
+            synchronized (tasksByTag) {
+                Set<Task<?>> tasks = tasksWithTagLiveOrNull(tag);
+                if (tasks != null) {
+                    tasks.remove(task);
+                    if (tasks.isEmpty()) {
+                        tasksByTag.remove(tag);
+                    }
+                }
+            }
+        }
+        Task<?> removed = tasksById.remove(task.getId());
+        incompleteTaskIds.remove(task.getId());
+        if (removed!=null && removed.isSubmitted() && !removed.isDone()) {
+            log.warn("Deleting submitted task before completion: "+removed+"; this task will continue to run in the background outwith "+this+", but perhaps it should have been cancelled?");
+        }
+        return removed != null;
+    }
+
+    public boolean isShutdown() {
+        return runner.isShutdown();
+    }
+    
+    /** count of all tasks submitted */
+    public long getTotalTasksSubmitted() {
+        return totalTaskCount.get();
+    }
+    
+    /** count of tasks submitted but not ended */
+    public long getNumIncompleteTasks() {
+        return incompleteTaskIds.size();
+    }
+    
+    /** count of tasks started but not ended */
+    public long getNumActiveTasks() {
+        return activeTaskCount.get();
+    }
+
+    /** count of tasks kept in memory, often including ended tasks */
+    public long getNumInMemoryTasks() {
+        return tasksById.size();
+    }
+
+    private Set<Task<?>> tasksWithTagCreating(Object tag) {
+        Preconditions.checkNotNull(tag);
+        synchronized (tasksByTag) {
+            Set<Task<?>> result = tasksWithTagLiveOrNull(tag);
+            if (result==null) {
+                result = Collections.synchronizedSet(new LinkedHashSet<Task<?>>());
+                tasksByTag.put(tag, result);
+            }
+            return result;
+        }
+    }
+
+    /** exposes live view, for internal use only */
+    @Beta
+    public Set<Task<?>> tasksWithTagLiveOrNull(Object tag) {
+        synchronized (tasksByTag) {
+            return tasksByTag.get(tag);
+        }
+    }
+
+    @Override
+    public Task<?> getTask(String id) {
+        return tasksById.get(id);
+    }
+    
+    /** not on interface because potentially expensive */
+    public List<Task<?>> getAllTasks() {
+        // not sure if synching makes any difference; have not observed CME's yet
+        // (and so far this is only called when a CME was caught on a previous operation)
+        synchronized (tasksById) {
+            return MutableList.copyOf(tasksById.values());
+        }
+    }
+    
+    @Override
+    public Set<Task<?>> getTasksWithTag(Object tag) {
+        Set<Task<?>> result = tasksWithTagLiveOrNull(tag);
+        if (result==null) return Collections.emptySet();
+        synchronized (result) {
+            return (Set<Task<?>>)Collections.unmodifiableSet(new LinkedHashSet<Task<?>>(result));
+        }
+    }
+    
+    @Override
+    public Set<Task<?>> getTasksWithAnyTag(Iterable<?> tags) {
+        Set<Task<?>> result = new LinkedHashSet<Task<?>>();
+        Iterator<?> ti = tags.iterator();
+        while (ti.hasNext()) {
+            Set<Task<?>> tasksForTag = tasksWithTagLiveOrNull(ti.next());
+            if (tasksForTag!=null) {
+                synchronized (tasksForTag) {
+                    result.addAll(tasksForTag);
+                }
+            }
+        }
+        return Collections.unmodifiableSet(result);
+    }
+
+    /** only works with at least one tag; returns empty if no tags */
+    @Override
+    public Set<Task<?>> getTasksWithAllTags(Iterable<?> tags) {
+        //NB: for this method retrieval for multiple tags could be made (much) more efficient (if/when it is used with multiple tags!)
+        //by first looking for the least-used tag, getting those tasks, and then for each of those tasks
+        //checking whether it contains the other tags (looking for second-least used, then third-least used, etc)
+        Set<Task<?>> result = new LinkedHashSet<Task<?>>();
+        boolean first = true;
+        Iterator<?> ti = tags.iterator();
+        while (ti.hasNext()) {
+            Object tag = ti.next();
+            if (first) { 
+                first = false;
+                result.addAll(getTasksWithTag(tag));
+            } else {
+                result.retainAll(getTasksWithTag(tag));
+            }
+        }
+        return Collections.unmodifiableSet(result);
+    }
+
+    /** live view of all tasks, for internal use only */
+    @Beta
+    public Collection<Task<?>> allTasksLive() { return tasksById.values(); }
+    
+    public Set<Object> getTaskTags() { 
+        synchronized (tasksByTag) {
+            return Collections.unmodifiableSet(Sets.newLinkedHashSet(tasksByTag.keySet())); 
+        }
+    }
+
+    public Task<?> submit(Runnable r) { return submit(new LinkedHashMap<Object,Object>(1), r); }
+    public Task<?> submit(Map<?,?> flags, Runnable r) { return submit(flags, new BasicTask<Void>(flags, r)); }
+
+    public <T> Task<T> submit(Callable<T> c) { return submit(new LinkedHashMap<Object,Object>(1), c); }
+    public <T> Task<T> submit(Map<?,?> flags, Callable<T> c) { return submit(flags, new BasicTask<T>(flags, c)); }
+
+    public <T> Task<T> submit(TaskAdaptable<T> t) { return submit(new LinkedHashMap<Object,Object>(1), t); }
+    public <T> Task<T> submit(Map<?,?> flags, TaskAdaptable<T> task) {
+        if (!(task instanceof Task))
+            task = task.asTask();
+        synchronized (task) {
+            if (((TaskInternal<?>)task).getInternalFuture()!=null) return (Task<T>)task;
+            return submitNewTask(flags, (Task<T>) task);
+        }
+    }
+
+    public <T> Task<T> scheduleWith(Task<T> task) { return scheduleWith(Collections.emptyMap(), task); }
+    public <T> Task<T> scheduleWith(Map<?,?> flags, Task<T> task) {
+        synchronized (task) {
+            if (((TaskInternal<?>)task).getInternalFuture()!=null) return task;
+            return submitNewTask(flags, task);
+        }
+    }
+
+    protected Task<?> submitNewScheduledTask(final Map<?,?> flags, final ScheduledTask task) {
+        tasksById.put(task.getId(), task);
+        totalTaskCount.incrementAndGet();
+        
+        beforeSubmitScheduledTaskAllIterations(flags, task);
+        
+        return submitSubsequentScheduledTask(flags, task);
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected Task<?> submitSubsequentScheduledTask(final Map<?,?> flags, final ScheduledTask task) {
+        if (!task.isDone()) {
+            task.internalFuture = delayedRunner.schedule(new ScheduledTaskCallable(task, flags),
+                task.delay.toNanoseconds(), TimeUnit.NANOSECONDS);
+        } else {
+            afterEndScheduledTaskAllIterations(flags, task);
+        }
+        return task;
+    }
+
+    protected class ScheduledTaskCallable implements Callable<Object> {
+        public ScheduledTask task;
+        public Map<?,?> flags;
+
+        public ScheduledTaskCallable(ScheduledTask task, Map<?, ?> flags) {
+            this.task = task;
+            this.flags = flags;
+        }
+
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        public Object call() {
+            if (task.startTimeUtc==-1) task.startTimeUtc = System.currentTimeMillis();
+            TaskInternal<?> taskScheduled = null;
+            try {
+                beforeStartScheduledTaskSubmissionIteration(flags, task);
+                taskScheduled = (TaskInternal<?>) task.newTask();
+                taskScheduled.setSubmittedByTask(task);
+                final Callable<?> oldJob = taskScheduled.getJob();
+                final TaskInternal<?> taskScheduledF = taskScheduled;
+                taskScheduled.setJob(new Callable() { public Object call() {
+                    boolean resubmitted = false;
+                    task.recentRun = taskScheduledF;
+                    try {
+                        synchronized (task) {
+                            task.notifyAll();
+                        }
+                        Object result;
+                        try {
+                            result = oldJob.call();
+                        } catch (Exception e) {
+                            if (!Tasks.isInterrupted()) {
+                                log.warn("Error executing "+oldJob+" (scheduled job of "+task+" - "+task.getDescription()+"); cancelling scheduled execution", e);
+                            } else {
+                                log.debug("Interrupted executing "+oldJob+" (scheduled job of "+task+" - "+task.getDescription()+"); cancelling scheduled execution: "+e);
+                            }
+                            throw Exceptions.propagate(e);
+                        }
+                        task.runCount++;
+                        if (task.period!=null && !task.isCancelled()) {
+                            task.delay = task.period;
+                            submitSubsequentScheduledTask(flags, task);
+                            resubmitted = true;
+                        }
+                        return result;
+                    } finally {
+                        // do in finally block in case we were interrupted
+                        if (!resubmitted)
+                            afterEndScheduledTaskAllIterations(flags, task);
+                    }
+                }});
+                task.nextRun = taskScheduled;
+                BasicExecutionContext ec = BasicExecutionContext.getCurrentExecutionContext();
+                if (ec!=null) return ec.submit(taskScheduled);
+                else return submit(taskScheduled);
+            } finally {
+                afterEndScheduledTaskSubmissionIteration(flags, task, taskScheduled);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "ScheduledTaskCallable["+task+","+flags+"]";
+        }
+    }
+
+    private final class SubmissionCallable<T> implements Callable<T> {
+        private final Map<?, ?> flags;
+        private final Task<T> task;
+
+        private SubmissionCallable(Map<?, ?> flags, Task<T> task) {
+            this.flags = flags;
+            this.task = task;
+        }
+
+        public T call() {
+            try {
+                T result = null;
+                Throwable error = null;
+                String oldThreadName = Thread.currentThread().getName();
+                try {
+                    if (RENAME_THREADS) {
+                        String newThreadName = oldThreadName+"-"+task.getDisplayName()+
+                            "["+task.getId().substring(0, 8)+"]";
+                        Thread.currentThread().setName(newThreadName);
+                    }
+                    beforeStartAtomicTask(flags, task);
+                    if (!task.isCancelled()) {
+                        result = ((TaskInternal<T>)task).getJob().call();
+                    } else throw new CancellationException();
+                } catch(Throwable e) {
+                    error = e;
+                } finally {
+                    if (RENAME_THREADS) {
+                        Thread.currentThread().setName(oldThreadName);
+                    }
+                    afterEndAtomicTask(flags, task);
+                }
+                if (error!=null) {
+                    /* we throw, after logging debug.
+                     * the throw means the error is available for task submitters to monitor.
+                     * however it is possible no one is monitoring it, in which case we will have debug logging only for errors.
+                     * (the alternative, of warn-level logging in lots of places where we don't want it, seems worse!) 
+                     */
+                    if (log.isDebugEnabled()) {
+                        // debug only here, because most submitters will handle failures
+                        log.debug("Exception running task "+task+" (rethrowing): "+error.getMessage(), error);
+                        if (log.isTraceEnabled())
+                            log.trace("Trace for exception running task "+task+" (rethrowing): "+error.getMessage(), error);
+                    }
+                    throw Exceptions.propagate(error);
+                }
+                return result;
+            } finally {
+                ((TaskInternal<?>)task).runListeners();
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "BEM.call("+task+","+flags+")";
+        }
+    }
+
+    private final static class ListenableForwardingFutureForTask<T> extends ListenableForwardingFuture<T> {
+        private final Task<T> task;
+
+        private ListenableForwardingFutureForTask(Future<T> delegate, ExecutionList list, Task<T> task) {
+            super(delegate, list);
+            this.task = task;
+        }
+
+        @Override
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            boolean result = false;
+            if (!task.isCancelled()) result |= task.cancel(mayInterruptIfRunning);
+            result |= super.cancel(mayInterruptIfRunning);
+            ((TaskInternal<?>)task).runListeners();
+            return result;
+        }
+    }
+
+    private final class SubmissionListenerToCallOtherListeners<T> implements Runnable {
+        private final Task<T> task;
+
+        private SubmissionListenerToCallOtherListeners(Task<T> task) {
+            this.task = task;
+        }
+
+        @Override
+        public void run() {
+            try {
+                ((TaskInternal<?>)task).runListeners();
+            } catch (Exception e) {
+                log.warn("Error running task listeners for task "+task+" done", e);
+            }
+            
+            for (ExecutionListener listener : listeners) {
+                try {
+                    listener.onTaskDone(task);
+                } catch (Exception e) {
+                    log.warn("Error running execution listener "+listener+" of task "+task+" done", e);
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> Task<T> submitNewTask(final Map<?,?> flags, final Task<T> task) {
+        if (task instanceof ScheduledTask)
+            return (Task<T>) submitNewScheduledTask(flags, (ScheduledTask)task);
+        
+        tasksById.put(task.getId(), task);
+        totalTaskCount.incrementAndGet();
+        
+        beforeSubmitAtomicTask(flags, task);
+        
+        if (((TaskInternal<T>)task).getJob() == null) 
+            throw new NullPointerException("Task "+task+" submitted with with null job: job must be supplied.");
+        
+        Callable<T> job = new SubmissionCallable<T>(flags, task);
+        
+        // If there's a scheduler then use that; otherwise execute it directly
+        Set<TaskScheduler> schedulers = null;
+        for (Object tago: task.getTags()) {
+            TaskScheduler scheduler = getTaskSchedulerForTag(tago);
+            if (scheduler!=null) {
+                if (schedulers==null) schedulers = new LinkedHashSet<TaskScheduler>(2);
+                schedulers.add(scheduler);
+            }
+        }
+        Future<T> future;
+        if (schedulers!=null && !schedulers.isEmpty()) {
+            if (schedulers.size()>1) log.warn("multiple schedulers detected, using only the first, for "+task+": "+schedulers);
+            future = schedulers.iterator().next().submit(job);
+        } else {
+            future = runner.submit(job);
+        }
+        // on completion, listeners get triggered above; here, below we ensure they get triggered on cancel
+        // (and we make sure the same ExecutionList is used in the future as in the task)
+        ListenableFuture<T> listenableFuture = new ListenableForwardingFutureForTask<T>(future, ((TaskInternal<T>)task).getListeners(), task);
+        // doesn't matter whether the listener is added to the listenableFuture or the task,
+        // except that for the task we can more easily wrap it so that it only logs debug if the executor is shutdown
+        // (avoid a bunch of ugly warnings in tests which start and stop things a lot!)
+        // [probably even nicer to run this in the same thread, it doesn't do much; but that is messier to implement]
+        ((TaskInternal<T>)task).addListener(new SubmissionListenerToCallOtherListeners<T>(task), runner);
+        
+        ((TaskInternal<T>)task).initInternalFuture(listenableFuture);
+        
+        return task;
+    }
+    
+    protected void beforeSubmitScheduledTaskAllIterations(Map<?,?> flags, Task<?> task) {
+        internalBeforeSubmit(flags, task);
+    }
+    protected void beforeSubmitAtomicTask(Map<?,?> flags, Task<?> task) {
+        internalBeforeSubmit(flags, task);
+    }
+    /** invoked when a task is submitted */
+    protected void internalBeforeSubmit(Map<?,?> flags, Task<?> task) {
+        incompleteTaskIds.put(task.getId(), task.getId());
+        
+        Task<?> currentTask = Tasks.current();
+        if (currentTask!=null) ((TaskInternal<?>)task).setSubmittedByTask(currentTask);
+        ((TaskInternal<?>)task).setSubmitTimeUtc(System.currentTimeMillis());
+        
+        if (flags.get("tag")!=null) ((TaskInternal<?>)task).getMutableTags().add(flags.remove("tag"));
+        if (flags.get("tags")!=null) ((TaskInternal<?>)task).getMutableTags().addAll((Collection<?>)flags.remove("tags"));
+
+        for (Object tag: ((TaskInternal<?>)task).getTags()) {
+            tasksWithTagCreating(tag).add(task);
+        }
+    }
+
+    protected void beforeStartScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> task) {
+        internalBeforeStart(flags, task);
+    }
+    protected void beforeStartAtomicTask(Map<?,?> flags, Task<?> task) {
+        internalBeforeStart(flags, task);
+    }
+    
+    /** invoked in a task's thread when a task is starting to run (may be some time after submitted), 
+     * but before doing any of the task's work, so that we can update bookkeeping and notify callbacks */
+    protected void internalBeforeStart(Map<?,?> flags, Task<?> task) {
+        activeTaskCount.incrementAndGet();
+        
+        //set thread _before_ start time, so we won't get a null thread when there is a start-time
+        if (log.isTraceEnabled()) log.trace(""+this+" beforeStart, task: "+task);
+        if (!task.isCancelled()) {
+            Thread thread = Thread.currentThread();
+            ((TaskInternal<?>)task).setThread(thread);
+            if (RENAME_THREADS) {
+                threadOriginalName.set(thread.getName());
+                String newThreadName = "brooklyn-" + CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, task.getDisplayName().replace(" ", "")) + "-" + task.getId().substring(0, 8);
+                thread.setName(newThreadName);
+            }
+            PerThreadCurrentTaskHolder.perThreadCurrentTask.set(task);
+            ((TaskInternal<?>)task).setStartTimeUtc(System.currentTimeMillis());
+        }
+        ExecutionUtils.invoke(flags.get("newTaskStartCallback"), task);
+    }
+
+    /** normally (if not interrupted) called once for each call to {@link #beforeSubmitScheduledTaskAllIterations(Map, Task)} */
+    protected void afterEndScheduledTaskAllIterations(Map<?,?> flags, Task<?> task) {
+        internalAfterEnd(flags, task, false, true);
+    }
+    /** called once for each call to {@link #beforeStartScheduledTaskSubmissionIteration(Map, Task)},
+     * with a per-iteration task generated by the surrounding scheduled task */
+    protected void afterEndScheduledTaskSubmissionIteration(Map<?,?> flags, Task<?> scheduledTask, Task<?> taskIteration) {
+        internalAfterEnd(flags, scheduledTask, true, false);
+    }
+    /** called once for each task on which {@link #beforeStartAtomicTask(Map, Task)} is invoked,
+     * and normally (if not interrupted prior to start) 
+     * called once for each task on which {@link #beforeSubmitAtomicTask(Map, Task)} */
+    protected void afterEndAtomicTask(Map<?,?> flags, Task<?> task) {
+        internalAfterEnd(flags, task, true, true);
+    }
+    /** normally (if not interrupted) called once for each call to {@link #internalBeforeSubmit(Map, Task)},
+     * and, for atomic tasks and scheduled-task submission iterations where 
+     * always called once if {@link #internalBeforeStart(Map, Task)} is invoked and in the same thread as that method */
+    protected void internalAfterEnd(Map<?,?> flags, Task<?> task, boolean startedInThisThread, boolean isEndingAllIterations) {
+        if (log.isTraceEnabled()) log.trace(this+" afterEnd, task: "+task);
+        if (startedInThisThread) {
+            activeTaskCount.decrementAndGet();
+        }
+        if (isEndingAllIterations) {
+            incompleteTaskIds.remove(task.getId());
+            ExecutionUtils.invoke(flags.get("newTaskEndCallback"), task);
+            ((TaskInternal<?>)task).setEndTimeUtc(System.currentTimeMillis());
+        }
+
+        if (startedInThisThread) {
+            PerThreadCurrentTaskHolder.perThreadCurrentTask.remove();
+            //clear thread _after_ endTime set, so we won't get a null thread when there is no end-time
+            if (RENAME_THREADS && startedInThisThread) {
+                Thread thread = task.getThread();
+                if (thread==null) {
+                    log.warn("BasicTask.afterEnd invoked without corresponding beforeStart");
+                } else {
+                    thread.setName(threadOriginalName.get());
+                    threadOriginalName.remove();
+                }
+            }
+            ((TaskInternal<?>)task).setThread(null);
+        }
+        synchronized (task) { task.notifyAll(); }
+    }
+
+    public TaskScheduler getTaskSchedulerForTag(Object tag) {
+        return schedulerByTag.get(tag);
+    }
+    
+    public void setTaskSchedulerForTag(Object tag, Class<? extends TaskScheduler> scheduler) {
+        synchronized (schedulerByTag) {
+            TaskScheduler old = getTaskSchedulerForTag(tag);
+            if (old!=null) {
+                if (scheduler.isAssignableFrom(old.getClass())) {
+                    /* already have such an instance */
+                    return;
+                }
+                //might support multiple in future...
+                throw new IllegalStateException("Not allowed to set multiple TaskSchedulers on ExecutionManager tag (tag "+tag+", has "+old+", setting new "+scheduler+")");
+            }
+            try {
+                TaskScheduler schedulerI = scheduler.newInstance();
+                // allow scheduler to have a nice name, for logging etc
+                if (schedulerI instanceof CanSetName) ((CanSetName)schedulerI).setName(""+tag);
+                setTaskSchedulerForTag(tag, schedulerI);
+            } catch (InstantiationException e) {
+                throw Exceptions.propagate(e);
+            } catch (IllegalAccessException e) {
+                throw Exceptions.propagate(e);
+            }
+        }
+    }
+    
+    /**
+     * Defines a {@link TaskScheduler} to run on all subsequently submitted jobs with the given tag.
+     *
+     * Maximum of one allowed currently. Resubmissions of the same scheduler (or scheduler class)
+     * allowed. If changing, you must call {@link #clearTaskSchedulerForTag(Object)} between the two.
+     *
+     * @see #setTaskSchedulerForTag(Object, Class)
+     */
+    public void setTaskSchedulerForTag(Object tag, TaskScheduler scheduler) {
+        synchronized (schedulerByTag) {
+            scheduler.injectExecutor(runner);
+
+            Object old = schedulerByTag.put(tag, scheduler);
+            if (old!=null && old!=scheduler) {
+                //might support multiple in future...
+                throw new IllegalStateException("Not allowed to set multiple TaskSchedulers on ExecutionManager tag (tag "+tag+")");
+            }
+        }
+    }
+
+    /**
+     * Forgets that any scheduler was associated with a tag.
+     *
+     * @see #setTaskSchedulerForTag(Object, TaskScheduler)
+     * @see #setTaskSchedulerForTag(Object, Class)
+     */
+    public boolean clearTaskSchedulerForTag(Object tag) {
+        synchronized (schedulerByTag) {
+            Object old = schedulerByTag.remove(tag);
+            return (old!=null);
+        }
+    }
+    
+    @VisibleForTesting
+    public ConcurrentMap<Object, TaskScheduler> getSchedulerByTag() {
+        return schedulerByTag;
+    }
+
+}


[02/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppSshDriver.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppSshDriver.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppSshDriver.java
index f7c3e04..b7cae85 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppSshDriver.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/JavaWebAppSshDriver.java
@@ -26,10 +26,12 @@ import java.util.Set;
 
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
+
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshTasks;
+
 import brooklyn.util.text.Strings;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 4320c9b..693b4c4 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
@@ -21,6 +21,7 @@ package org.apache.brooklyn.entity.webapp;
 import java.util.Set;
 
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableSet;
 
@@ -29,7 +30,6 @@ import brooklyn.entity.basic.Attributes;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 public interface WebAppServiceConstants extends WebAppServiceMetrics {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 6a558e7..0935690 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
@@ -20,6 +20,7 @@ package org.apache.brooklyn.entity.webapp.jboss;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
 
 import brooklyn.config.ConfigKey;
@@ -27,7 +28,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.java.UsesJmx;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 @Catalog(name="JBoss Application Server 6", description="AS6: an open source Java application server from JBoss", iconUrl="classpath:///jboss-logo.png")
 @ImplementedBy(JBoss6ServerImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 4872b68..dd5f2bd 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
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.entity.trait.HasShortName;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
 
 import brooklyn.config.ConfigKey;
@@ -31,7 +32,6 @@ import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.javalang.JavaClassNames;
 
 @Catalog(name="JBoss Application Server 7", description="AS7: an open source Java application server from JBoss", iconUrl="classpath:///jboss-logo.png")

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 bd5cfce..70baeee 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
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.entity.trait.HasShortName;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
 
 import brooklyn.config.ConfigKey;
@@ -30,7 +31,6 @@ import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.java.UsesJmx;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java
index 166d2ad..9e34c57 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppService.java
@@ -23,6 +23,7 @@ import java.util.List;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.webapp.WebAppService;
 
 import brooklyn.config.ConfigKey;
@@ -32,8 +33,6 @@ import brooklyn.entity.basic.SoftwareProcess;
 
 import org.apache.brooklyn.location.basic.PortRanges;
 
-import brooklyn.util.flags.SetFromFlag;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
index e336a93..1735cb8 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/webapp/nodejs/NodeJsWebAppSshDriver.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.brooklyn.core.util.file.ArchiveUtils;
 import org.apache.brooklyn.entity.webapp.WebAppService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -30,10 +31,11 @@ import org.slf4j.LoggerFactory;
 import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.SoftwareProcess;
+
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.file.ArchiveUtils;
 import brooklyn.util.net.Networking;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 766c7a0..aef6ffd 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
@@ -20,12 +20,12 @@ package org.apache.brooklyn.entity.webapp.tomcat;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.javalang.JavaClassNames;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 d9327cd..95a8c31 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
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.entity.trait.HasShortName;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
 
 import brooklyn.config.ConfigKey;
@@ -31,8 +32,9 @@ import brooklyn.entity.java.UsesJmx;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.flags.SetFromFlag;
+
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/test/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingScriptGeneratorTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingScriptGeneratorTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingScriptGeneratorTest.java
index f5c3f41..dc8dd41 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingScriptGeneratorTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingScriptGeneratorTest.java
@@ -26,9 +26,8 @@ import java.util.LinkedHashSet;
 import java.util.Set;
 
 import org.testng.annotations.Test;
-
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.location.geo.HostGeoInfo;
-import brooklyn.util.ResourceUtils;
 
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/test/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingWebClientTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingWebClientTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingWebClientTest.java
index 4602840..d068b48 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingWebClientTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingWebClientTest.java
@@ -26,6 +26,7 @@ import static org.apache.brooklyn.entity.dns.geoscaling.GeoscalingWebClient.PROV
 import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 
+import org.apache.brooklyn.core.util.http.HttpTool;
 import org.apache.brooklyn.entity.dns.geoscaling.GeoscalingWebClient;
 import org.apache.brooklyn.entity.dns.geoscaling.GeoscalingWebClient.Domain;
 import org.apache.brooklyn.entity.dns.geoscaling.GeoscalingWebClient.SmartSubdomain;
@@ -34,7 +35,6 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
-import brooklyn.util.http.HttpTool;
 import brooklyn.util.text.Strings;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/AbstractControllerTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/AbstractControllerTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/AbstractControllerTest.java
index facde8d..f3af752 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/AbstractControllerTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/AbstractControllerTest.java
@@ -38,6 +38,7 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
 import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.apache.brooklyn.test.entity.TestEntityImpl;
 import org.slf4j.Logger;
@@ -60,7 +61,6 @@ import brooklyn.test.Asserts;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/ProxySslConfigTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/ProxySslConfigTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/ProxySslConfigTest.java
index 218debf..37a8061 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/ProxySslConfigTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/ProxySslConfigTest.java
@@ -18,12 +18,12 @@
  */
 package org.apache.brooklyn.entity.proxy;
 
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.TypeCoercions;
 
 @Test
 public class ProxySslConfigTest {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/nginx/NginxRebindWithHaIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/nginx/NginxRebindWithHaIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/nginx/NginxRebindWithHaIntegrationTest.java
index 57ea76d..9318fc9 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/nginx/NginxRebindWithHaIntegrationTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/proxy/nginx/NginxRebindWithHaIntegrationTest.java
@@ -32,6 +32,8 @@ import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.ha.HighAvailabilityMode;
 import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
+import org.apache.brooklyn.core.util.task.BasicExecutionManager;
 import org.apache.brooklyn.entity.proxy.nginx.NginxController;
 import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer;
 import org.apache.brooklyn.test.EntityTestUtils;
@@ -56,10 +58,8 @@ import brooklyn.entity.rebind.RebindTestUtils;
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.basic.SshMachineLocationReuseIntegrationTest.RecordingSshjTool;
 
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.net.Networking;
 import brooklyn.util.repeat.Repeater;
-import brooklyn.util.task.BasicExecutionManager;
 import brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/AbstractWebAppFixtureIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/AbstractWebAppFixtureIntegrationTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/AbstractWebAppFixtureIntegrationTest.java
index cf42c5e..b21cd38 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/AbstractWebAppFixtureIntegrationTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/AbstractWebAppFixtureIntegrationTest.java
@@ -68,6 +68,8 @@ import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.SubscriptionContext;
 import org.apache.brooklyn.api.management.SubscriptionHandle;
+import org.apache.brooklyn.core.util.crypto.FluentKeySigner;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
 import org.apache.brooklyn.entity.webapp.WebAppService;
@@ -79,8 +81,6 @@ import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.apache.brooklyn.test.entity.TestApplication;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.crypto.FluentKeySigner;
-import brooklyn.util.crypto.SecureKeys;
 import brooklyn.util.net.Urls;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/HttpsSslConfigTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/HttpsSslConfigTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/HttpsSslConfigTest.java
index d21c0d9..830775c 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/HttpsSslConfigTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/HttpsSslConfigTest.java
@@ -18,12 +18,12 @@
  */
 package org.apache.brooklyn.entity.webapp;
 
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.entity.webapp.HttpsSslConfig;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.TypeCoercions;
 
 public class HttpsSslConfigTest {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppConcurrentDeployTest.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppConcurrentDeployTest.java b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppConcurrentDeployTest.java
index 9d0e1eb..28f331d 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppConcurrentDeployTest.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/entity/webapp/WebAppConcurrentDeployTest.java
@@ -40,6 +40,8 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationSpec;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcess;
 import org.apache.brooklyn.entity.webapp.jboss.JBoss7Server;
 import org.apache.brooklyn.entity.webapp.tomcat.TomcatServer;
@@ -48,8 +50,6 @@ import org.apache.brooklyn.test.TestResourceUnavailableException;
 
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/test/java/org/apache/brooklyn/test/entity/TestJavaWebAppEntity.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/test/entity/TestJavaWebAppEntity.java b/software/webapp/src/test/java/org/apache/brooklyn/test/entity/TestJavaWebAppEntity.java
index c5967d0..b9d57ca 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/test/entity/TestJavaWebAppEntity.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/test/entity/TestJavaWebAppEntity.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.test.entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.entity.webapp.WebAppService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,7 +34,6 @@ import brooklyn.entity.basic.ServiceStateLogic;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.basic.SoftwareProcessDriverLifecycleEffectorTasks;
 import brooklyn.entity.java.VanillaJavaApp;
-import brooklyn.util.config.ConfigBag;
 
 /**
  * Mock web application server entity for testing.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/test/java/org/apache/brooklyn/test/entity/TestJavaWebAppEntityImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/test/java/org/apache/brooklyn/test/entity/TestJavaWebAppEntityImpl.java b/software/webapp/src/test/java/org/apache/brooklyn/test/entity/TestJavaWebAppEntityImpl.java
index 7e909ab..04b8bd0 100644
--- a/software/webapp/src/test/java/org/apache/brooklyn/test/entity/TestJavaWebAppEntityImpl.java
+++ b/software/webapp/src/test/java/org/apache/brooklyn/test/entity/TestJavaWebAppEntityImpl.java
@@ -21,10 +21,10 @@ package org.apache.brooklyn.test.entity;
 import java.util.Map;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
 
 import brooklyn.entity.java.VanillaJavaAppImpl;
-import brooklyn.util.flags.SetFromFlag;
 
 public class TestJavaWebAppEntityImpl extends VanillaJavaAppImpl implements TestJavaWebAppEntity {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/archetypes/quickstart/src/brooklyn-sample/src/test/java/com/acme/sample/brooklyn/sample/app/SampleLocalhostIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/archetypes/quickstart/src/brooklyn-sample/src/test/java/com/acme/sample/brooklyn/sample/app/SampleLocalhostIntegrationTest.java b/usage/archetypes/quickstart/src/brooklyn-sample/src/test/java/com/acme/sample/brooklyn/sample/app/SampleLocalhostIntegrationTest.java
index 471d5e3..f679425 100644
--- a/usage/archetypes/quickstart/src/brooklyn-sample/src/test/java/com/acme/sample/brooklyn/sample/app/SampleLocalhostIntegrationTest.java
+++ b/usage/archetypes/quickstart/src/brooklyn-sample/src/test/java/com/acme/sample/brooklyn/sample/app/SampleLocalhostIntegrationTest.java
@@ -17,7 +17,7 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
-import brooklyn.util.ResourceUtils;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import brooklyn.util.text.Strings;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/YamlLauncherAbstract.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/YamlLauncherAbstract.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/YamlLauncherAbstract.java
index 1ad7868..6296339 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/YamlLauncherAbstract.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/YamlLauncherAbstract.java
@@ -28,13 +28,13 @@ import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.basic.BrooklynShutdownHooks;
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.stream.Streams;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
index 9241a73..3931a82 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynAssemblyTemplateInstantiator.java
@@ -51,12 +51,12 @@ import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog.BrooklynLoaderTracker;
 import org.apache.brooklyn.core.management.internal.EntityManagementUtils;
 import org.apache.brooklyn.core.management.internal.EntityManagementUtils.CreationResult;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import brooklyn.config.BrooklynServerConfig;
 import brooklyn.entity.basic.BasicApplicationImpl;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.net.Urls;
 
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
index 33bb6a1..03e3920 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynComponentTemplateResolver.java
@@ -50,6 +50,11 @@ import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.ManagementContextInjectable;
 import org.apache.brooklyn.core.management.classloading.JavaBrooklynClassLoadingContext;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.FlagUtils.FlagConfigKeyAndValueRecord;
+import org.apache.brooklyn.core.util.task.Tasks;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.AbstractEntity;
@@ -57,15 +62,10 @@ import brooklyn.entity.basic.BrooklynTags;
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.proxying.InternalEntityFactory;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.FlagUtils.FlagConfigKeyAndValueRecord;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.Reflections;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityDecorationResolver.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityDecorationResolver.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityDecorationResolver.java
index 527a44c..35c8b4c 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityDecorationResolver.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynEntityDecorationResolver.java
@@ -33,9 +33,9 @@ import org.apache.brooklyn.api.policy.PolicySpec;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynYamlTypeInstantiator.InstantiatorFromKey;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.util.collections.MutableList;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.annotations.Beta;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlTypeInstantiator.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlTypeInstantiator.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlTypeInstantiator.java
index 2954ee7..87b1f01 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlTypeInstantiator.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/BrooklynYamlTypeInstantiator.java
@@ -25,11 +25,11 @@ import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.management.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.Reflections;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 3babd31..f8d03c9 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,6 +27,7 @@ import io.brooklyn.camp.spi.resolve.interpret.PlanInterpretationNode;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.TaskFactory;
+import org.apache.brooklyn.core.util.task.DeferredSupplier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,7 +36,6 @@ import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.effector.EffectorTasks;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.DeferredSupplier;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslUtils.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslUtils.java b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslUtils.java
index e5194bf..4eaf37d 100644
--- a/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslUtils.java
+++ b/usage/camp/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslUtils.java
@@ -18,7 +18,7 @@
  */
 package org.apache.brooklyn.camp.brooklyn.spi.dsl;
 
-import brooklyn.util.task.DeferredSupplier;
+import org.apache.brooklyn.core.util.task.DeferredSupplier;
 
 import com.google.common.collect.Iterables;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 71a72a5..5b1b1e8 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
@@ -34,18 +34,18 @@ import org.apache.brooklyn.camp.brooklyn.spi.creation.EntitySpecConfiguration;
 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.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.ClassCoercionException;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.DeferredSupplier;
 import org.apache.commons.beanutils.BeanUtils;
 
 import brooklyn.entity.basic.EntityDynamicType;
 import brooklyn.event.basic.DependentConfiguration;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.ClassCoercionException;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.javalang.Reflections;
-import brooklyn.util.task.DeferredSupplier;
 import brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 601a46a..791c79f 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
@@ -29,6 +29,8 @@ import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
 import org.apache.brooklyn.camp.brooklyn.spi.dsl.BrooklynDslDeferredSupplier;
 import org.apache.brooklyn.core.management.internal.EntityManagerInternal;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
 
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.ConfigKeys;
@@ -38,8 +40,6 @@ import brooklyn.entity.basic.EntityPredicates;
 import brooklyn.event.basic.DependentConfiguration;
 import brooklyn.event.basic.Sensors;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.StringEscapes.JavaStringEscapes;
 
 import com.google.common.base.Optional;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
index c0b77f4..8922059 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
@@ -32,6 +32,8 @@ import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatform;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterMethod;
@@ -42,8 +44,6 @@ import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.StartableApplication;
 import brooklyn.entity.rebind.RebindOptions;
 import brooklyn.entity.rebind.RebindTestFixture;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
index d96b132..0396009 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java
@@ -32,6 +32,8 @@ import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatform;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,8 +42,6 @@ import org.testng.annotations.BeforeMethod;
 
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 87d014b..110851a 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
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,7 +43,6 @@ import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.rebind.RebindTestUtils;
 import brooklyn.event.basic.Sensors;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.collect.Iterables;
 import com.google.common.io.Files;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 06f596a..a0278b2 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
@@ -40,6 +40,7 @@ import org.apache.brooklyn.camp.brooklyn.spi.dsl.methods.BrooklynDslCommon;
 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.core.management.internal.EntityManagerInternal;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.apache.brooklyn.test.entity.TestEntityImpl;
 import org.slf4j.Logger;
@@ -65,7 +66,6 @@ import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Functionals;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Suppliers;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppWithDslYamlRebindIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppWithDslYamlRebindIntegrationTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppWithDslYamlRebindIntegrationTest.java
index e558288..72b06e3 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppWithDslYamlRebindIntegrationTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppWithDslYamlRebindIntegrationTest.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
@@ -38,7 +39,6 @@ import org.testng.annotations.Test;
 import brooklyn.entity.basic.BrooklynTaskTags;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.rebind.RebindTestUtils;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.stream.Streams;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppsIntegrationTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppsIntegrationTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppsIntegrationTest.java
index 94b3f66..7314e66 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppsIntegrationTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppsIntegrationTest.java
@@ -38,6 +38,7 @@ import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatform;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.entity.webapp.DynamicWebAppCluster;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
 import org.apache.brooklyn.entity.webapp.WebAppService;
@@ -55,7 +56,6 @@ import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.Lifecycle;
 import brooklyn.policy.autoscaling.AutoScalerPolicy;
 import brooklyn.test.Asserts;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.net.Urls;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppsMatchingTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppsMatchingTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppsMatchingTest.java
index b4a647e..7e45019 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppsMatchingTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/JavaWebAppsMatchingTest.java
@@ -32,6 +32,8 @@ import java.util.Map;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatform;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampReservedKeys;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.task.DeferredSupplier;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -41,10 +43,8 @@ import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DeferredSupplier;
 
 @Test
 public class JavaWebAppsMatchingTest {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/MapReferenceYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/MapReferenceYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/MapReferenceYamlTest.java
index f20af51..7a8ca3c 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/MapReferenceYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/MapReferenceYamlTest.java
@@ -22,6 +22,7 @@ import java.util.Map;
 import java.util.concurrent.Callable;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.slf4j.Logger;
@@ -31,7 +32,6 @@ import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.BasicEntity;
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.collect.Iterables;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java
index ba29051..6b19d3b 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/ObjectsYamlTest.java
@@ -26,6 +26,9 @@ import org.apache.brooklyn.api.entity.trait.Configurable;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.core.management.ManagementContextInjectable;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.slf4j.Logger;
@@ -37,9 +40,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.flags.TypeCoercions;
 
 import com.google.common.collect.Lists;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/ReloadBrooklynPropertiesTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/ReloadBrooklynPropertiesTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/ReloadBrooklynPropertiesTest.java
index 3774e7e..961e2fd 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/ReloadBrooklynPropertiesTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/ReloadBrooklynPropertiesTest.java
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampConstants;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,7 +39,6 @@ import org.testng.annotations.Test;
 
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.trait.Startable;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.stream.Streams;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 55b9c27..c03a282 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,6 +24,7 @@ import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.entity.proxying.EntityInitializer;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.testng.Assert;
 
 import com.google.common.base.Preconditions;
@@ -32,7 +33,6 @@ import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.effector.EffectorBody;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.config.ConfigBag;
 
 public class TestSensorAndEffectorInitializer implements EntityInitializer {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/AbstractCatalogXmlTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/AbstractCatalogXmlTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/AbstractCatalogXmlTest.java
index 65bb7e0..5eab943 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/AbstractCatalogXmlTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/AbstractCatalogXmlTest.java
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.core.management.osgi.OsgiTestResources;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.test.TestResourceUnavailableException;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 
@@ -33,7 +34,6 @@ import java.io.StringReader;
 
 import brooklyn.config.BrooklynProperties;
 import brooklyn.config.BrooklynServerConfig;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.os.Os;
 import brooklyn.util.stream.ReaderInputStream;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
index 66fee85..d08cfed 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiVersionMoreEntityTest.java
@@ -39,9 +39,9 @@ import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
 import org.apache.brooklyn.camp.brooklyn.spi.creation.BrooklynEntityMatcher;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.osgi.OsgiVersionMoreEntityTest;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.test.TestResourceUnavailableException;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.text.Strings;
 
 import com.google.common.collect.Iterables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
index 3aa9b74..4cece0a 100644
--- a/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
+++ b/usage/camp/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlEntityTest.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.camp.brooklyn.AbstractYamlTest;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.osgi.OsgiStandaloneTest;
 import org.apache.brooklyn.core.management.osgi.OsgiTestResources;
+import org.apache.brooklyn.core.util.ResourceUtils;
 
 import brooklyn.entity.basic.BasicEntity;
 
@@ -42,7 +43,6 @@ import org.apache.brooklyn.test.TestResourceUnavailableException;
 import org.apache.brooklyn.test.entity.TestEntity;
 import org.apache.brooklyn.test.entity.TestEntityImpl;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.exceptions.Exceptions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/cli/src/main/java/org/apache/brooklyn/cli/ItemLister.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/java/org/apache/brooklyn/cli/ItemLister.java b/usage/cli/src/main/java/org/apache/brooklyn/cli/ItemLister.java
index c4f3cd2..16706ab 100644
--- a/usage/cli/src/main/java/org/apache/brooklyn/cli/ItemLister.java
+++ b/usage/cli/src/main/java/org/apache/brooklyn/cli/ItemLister.java
@@ -42,13 +42,13 @@ import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.cli.lister.ClassFinder;
 import org.apache.brooklyn.cli.lister.ItemDescriptors;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
 import com.fasterxml.jackson.annotation.JsonInclude;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/cli/src/main/java/org/apache/brooklyn/cli/Main.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/main/java/org/apache/brooklyn/cli/Main.java b/usage/cli/src/main/java/org/apache/brooklyn/cli/Main.java
index 8d3ed07..95c10a1 100644
--- a/usage/cli/src/main/java/org/apache/brooklyn/cli/Main.java
+++ b/usage/cli/src/main/java/org/apache/brooklyn/cli/Main.java
@@ -78,6 +78,7 @@ import org.apache.brooklyn.cli.CloudExplorer.ComputeTerminateInstancesCommand;
 import org.apache.brooklyn.cli.ItemLister.ListAllCommand;
 import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
 import org.apache.brooklyn.core.management.ha.OsgiManager;
+import org.apache.brooklyn.core.util.ResourceUtils;
 
 import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.basic.AbstractEntity;
@@ -95,7 +96,6 @@ import org.apache.brooklyn.launcher.config.StopWhichAppsOnShutdown;
 import org.apache.brooklyn.rest.security.PasswordHasher;
 import org.apache.brooklyn.rest.util.ShutdownHandler;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.FatalConfigurationRuntimeException;
 import brooklyn.util.exceptions.FatalRuntimeException;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 63ad940..4d22b3f 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,6 +31,8 @@ import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.javalang.UrlClassLoader;
 import org.reflections.Reflections;
 import org.reflections.scanners.FieldAnnotationsScanner;
 import org.reflections.scanners.SubTypesScanner;
@@ -44,8 +46,6 @@ import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.policy.basic.AbstractPolicy;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.javalang.UrlClassLoader;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/cli/src/test/java/org/apache/brooklyn/cli/CliTest.java
----------------------------------------------------------------------
diff --git a/usage/cli/src/test/java/org/apache/brooklyn/cli/CliTest.java b/usage/cli/src/test/java/org/apache/brooklyn/cli/CliTest.java
index ff6a5d3..44207c1 100644
--- a/usage/cli/src/test/java/org/apache/brooklyn/cli/CliTest.java
+++ b/usage/cli/src/test/java/org/apache/brooklyn/cli/CliTest.java
@@ -51,6 +51,7 @@ import org.apache.brooklyn.cli.AbstractMain.HelpCommand;
 import org.apache.brooklyn.cli.Main.AppShutdownHandler;
 import org.apache.brooklyn.cli.Main.GeneratePasswordCommand;
 import org.apache.brooklyn.cli.Main.LaunchCommand;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -70,7 +71,6 @@ import brooklyn.entity.trait.Startable;
 import org.apache.brooklyn.location.basic.SimulatedLocation;
 
 import brooklyn.test.Asserts;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.FatalConfigurationRuntimeException;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynWebServer.java
----------------------------------------------------------------------
diff --git a/usage/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynWebServer.java b/usage/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynWebServer.java
index 13ee15a..82c881f 100644
--- a/usage/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynWebServer.java
+++ b/usage/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynWebServer.java
@@ -68,6 +68,13 @@ import org.apache.brooklyn.api.location.PortRange;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.internal.BrooklynInitialization;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.BrooklynNetworkUtils;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.crypto.FluentKeySigner;
+import org.apache.brooklyn.core.util.crypto.SecureKeys;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.launcher.config.CustomResourceLocator;
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import org.apache.brooklyn.location.basic.PortRanges;
@@ -83,15 +90,8 @@ import org.apache.brooklyn.rest.util.ManagementContextProvider;
 import org.apache.brooklyn.rest.util.ShutdownHandler;
 import org.apache.brooklyn.rest.util.ShutdownHandlerProvider;
 
-import brooklyn.util.BrooklynNetworkUtils;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.crypto.FluentKeySigner;
-import brooklyn.util.crypto.SecureKeys;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.io.FileUtil;
 import brooklyn.util.javalang.Threads;
 import brooklyn.util.logging.LoggingSetup;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/launcher/src/main/java/org/apache/brooklyn/launcher/config/CustomResourceLocator.java
----------------------------------------------------------------------
diff --git a/usage/launcher/src/main/java/org/apache/brooklyn/launcher/config/CustomResourceLocator.java b/usage/launcher/src/main/java/org/apache/brooklyn/launcher/config/CustomResourceLocator.java
index 78ad7c6..eb1052d 100644
--- a/usage/launcher/src/main/java/org/apache/brooklyn/launcher/config/CustomResourceLocator.java
+++ b/usage/launcher/src/main/java/org/apache/brooklyn/launcher/config/CustomResourceLocator.java
@@ -23,12 +23,12 @@ import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.BrooklynVersion;
 import brooklyn.config.ConfigMap;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.os.Os;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/launcher/src/test/java/org/apache/brooklyn/entity/basic/VanillaSoftwareYamlTest.java
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/java/org/apache/brooklyn/entity/basic/VanillaSoftwareYamlTest.java b/usage/launcher/src/test/java/org/apache/brooklyn/entity/basic/VanillaSoftwareYamlTest.java
index a8c9f98..1d14d72 100644
--- a/usage/launcher/src/test/java/org/apache/brooklyn/entity/basic/VanillaSoftwareYamlTest.java
+++ b/usage/launcher/src/test/java/org/apache/brooklyn/entity/basic/VanillaSoftwareYamlTest.java
@@ -28,11 +28,11 @@ import brooklyn.entity.trait.Startable;
 
 import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.launcher.SimpleYamlLauncherForTests;
 import org.apache.brooklyn.launcher.camp.SimpleYamlLauncher;
 
 import brooklyn.test.Asserts;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/launcher/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeRestTest.java
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeRestTest.java b/usage/launcher/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeRestTest.java
index a8d301e..933071c 100644
--- a/usage/launcher/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeRestTest.java
+++ b/usage/launcher/src/test/java/org/apache/brooklyn/entity/brooklynnode/BrooklynNodeRestTest.java
@@ -44,15 +44,15 @@ import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.launcher.SimpleYamlLauncherForTests;
 import org.apache.brooklyn.launcher.camp.SimpleYamlLauncher;
 
 import brooklyn.util.collections.Jsonya;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.net.Urls;
 import brooklyn.util.repeat.Repeater;
 import brooklyn.util.time.Duration;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/launcher/src/test/java/org/apache/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/java/org/apache/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java b/usage/launcher/src/test/java/org/apache/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java
index 9103792..6badab5 100644
--- a/usage/launcher/src/test/java/org/apache/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java
+++ b/usage/launcher/src/test/java/org/apache/brooklyn/entity/database/mssql/MssqlBlueprintLiveTest.java
@@ -22,10 +22,9 @@ import java.io.StringReader;
 import java.util.Map;
 
 import org.testng.annotations.Test;
-
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.apache.brooklyn.launcher.blueprints.AbstractBlueprintTest;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.text.TemplateProcessor;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogTest.java
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogTest.java b/usage/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogTest.java
index 49596d6..060aa8f 100644
--- a/usage/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogTest.java
+++ b/usage/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynLauncherRebindCatalogTest.java
@@ -37,10 +37,10 @@ import com.google.common.io.Files;
 import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 
 import brooklyn.entity.rebind.persister.PersistMode;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.os.Os;
 
 public class BrooklynLauncherRebindCatalogTest {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynWebServerTest.java
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynWebServerTest.java b/usage/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynWebServerTest.java
index 8ee48f4..f743aea 100644
--- a/usage/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynWebServerTest.java
+++ b/usage/launcher/src/test/java/org/apache/brooklyn/launcher/BrooklynWebServerTest.java
@@ -19,6 +19,8 @@
 package org.apache.brooklyn.launcher;
 
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.launcher.BrooklynWebServer;
 
 import static org.testng.Assert.assertEquals;
@@ -55,8 +57,6 @@ import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java b/usage/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java
index 4fcc63d..707d9a7 100644
--- a/usage/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java
+++ b/usage/launcher/src/test/java/org/apache/brooklyn/launcher/blueprints/AbstractBlueprintTest.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherAbstract;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,7 +50,6 @@ import org.apache.brooklyn.launcher.SimpleYamlLauncherForTests;
 import org.apache.brooklyn.launcher.camp.BrooklynCampPlatformLauncher;
 
 import brooklyn.test.Asserts;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.os.Os;
 
 public abstract class AbstractBlueprintTest {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 7570cc5..b5f0cf4 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
@@ -30,10 +30,12 @@ import brooklyn.entity.database.mysql.MySqlSshDriver;
 import brooklyn.entity.software.SshEffectorTasks;
 import brooklyn.event.feed.function.FunctionFeed;
 import brooklyn.event.feed.function.FunctionPollConfig;
+
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
+
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.time.CountdownTimer;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/qa/src/main/java/org/apache/brooklyn/qa/longevity/MonitorUtils.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/main/java/org/apache/brooklyn/qa/longevity/MonitorUtils.java b/usage/qa/src/main/java/org/apache/brooklyn/qa/longevity/MonitorUtils.java
index 54acb3b..9dbfe0a 100644
--- a/usage/qa/src/main/java/org/apache/brooklyn/qa/longevity/MonitorUtils.java
+++ b/usage/qa/src/main/java/org/apache/brooklyn/qa/longevity/MonitorUtils.java
@@ -35,11 +35,11 @@ import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.stream.StreamGobbler;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/qa/src/test/java/org/apache/brooklyn/qa/brooklynnode/SoftlayerObtainPrivateLiveTest.java
----------------------------------------------------------------------
diff --git a/usage/qa/src/test/java/org/apache/brooklyn/qa/brooklynnode/SoftlayerObtainPrivateLiveTest.java b/usage/qa/src/test/java/org/apache/brooklyn/qa/brooklynnode/SoftlayerObtainPrivateLiveTest.java
index 59c5b0b..8a02698 100644
--- a/usage/qa/src/test/java/org/apache/brooklyn/qa/brooklynnode/SoftlayerObtainPrivateLiveTest.java
+++ b/usage/qa/src/test/java/org/apache/brooklyn/qa/brooklynnode/SoftlayerObtainPrivateLiveTest.java
@@ -44,10 +44,10 @@ import brooklyn.entity.brooklynnode.BrooklynNode.DeployBlueprintEffector;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.BrooklynMavenArtifacts;
 import org.apache.brooklyn.launcher.BrooklynLauncher;
 import org.apache.brooklyn.location.jclouds.JcloudsLocationConfig;
 
-import brooklyn.util.BrooklynMavenArtifacts;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.maven.MavenRetriever;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/AbstractBrooklynRestResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/AbstractBrooklynRestResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/AbstractBrooklynRestResource.java
index 9313987..830214e 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/AbstractBrooklynRestResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/AbstractBrooklynRestResource.java
@@ -34,12 +34,12 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.ManagementContextInjectable;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 import org.apache.brooklyn.rest.util.json.BrooklynJacksonJsonProvider;
 
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 
 public abstract class AbstractBrooklynRestResource implements ManagementContextInjectable {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 98d5648..d195af6 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
@@ -66,6 +66,7 @@ import org.apache.brooklyn.core.management.entitlement.Entitlements.EntityAndIte
 import org.apache.brooklyn.core.management.entitlement.Entitlements.StringAndArgument;
 import org.apache.brooklyn.core.management.internal.EntityManagementUtils;
 import org.apache.brooklyn.core.management.internal.EntityManagementUtils.CreationResult;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.rest.api.ApplicationApi;
 import org.apache.brooklyn.rest.domain.ApplicationSpec;
 import org.apache.brooklyn.rest.domain.ApplicationSummary;
@@ -79,7 +80,6 @@ import org.apache.brooklyn.rest.transform.TaskTransformer;
 import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
index 80dc2a3..08ed505 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
@@ -51,6 +51,7 @@ import org.apache.brooklyn.core.catalog.internal.CatalogItemComparator;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
 import org.apache.brooklyn.core.management.entitlement.Entitlements.StringAndArgument;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.rest.api.CatalogApi;
 import org.apache.brooklyn.rest.domain.ApiError;
 import org.apache.brooklyn.rest.domain.CatalogEntitySummary;
@@ -61,7 +62,6 @@ import org.apache.brooklyn.rest.filter.HaHotStateRequired;
 import org.apache.brooklyn.rest.transform.CatalogTransformer;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
index 5353f50..f5f43ea 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/EntityConfigResource.java
@@ -34,14 +34,14 @@ import brooklyn.event.basic.BasicConfigKey;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.ValueResolver;
 import org.apache.brooklyn.rest.api.EntityConfigApi;
 import org.apache.brooklyn.rest.domain.EntityConfigSummary;
 import org.apache.brooklyn.rest.filter.HaHotStateRequired;
 import org.apache.brooklyn.rest.transform.EntityTransformer;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.task.ValueResolver;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java
index a50a86e..eef52e9 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/EntityResource.java
@@ -50,6 +50,7 @@ import org.apache.brooklyn.core.management.entitlement.EntitlementPredicates;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
 import org.apache.brooklyn.core.management.internal.EntityManagementUtils;
 import org.apache.brooklyn.core.management.internal.EntityManagementUtils.CreationResult;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.rest.api.EntityApi;
 import org.apache.brooklyn.rest.domain.EntitySummary;
 import org.apache.brooklyn.rest.domain.LocationSummary;
@@ -61,7 +62,6 @@ import org.apache.brooklyn.rest.transform.LocationTransformer.LocationDetailLeve
 import org.apache.brooklyn.rest.transform.TaskTransformer;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java
----------------------------------------------------------------------
diff --git a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java
index 655c20c..a6ca58b 100644
--- a/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java
+++ b/usage/rest-server/src/main/java/org/apache/brooklyn/rest/resources/PolicyConfigResource.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.rest.api.PolicyConfigApi;
 import org.apache.brooklyn.rest.domain.PolicyConfigSummary;
 import org.apache.brooklyn.rest.filter.HaHotStateRequired;
@@ -37,8 +38,6 @@ import org.apache.brooklyn.rest.transform.PolicyTransformer;
 import org.apache.brooklyn.rest.util.BrooklynRestResourceUtils;
 import org.apache.brooklyn.rest.util.WebResourceUtils;
 
-import brooklyn.util.flags.TypeCoercions;
-
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 e8b85ef..d8be210 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
@@ -34,13 +34,13 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.core.management.entitlement.Entitlements;
+import org.apache.brooklyn.core.util.task.ValueResolver;
 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 brooklyn.util.task.ValueResolver;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 



[46/64] incubator-brooklyn git commit: brooklyn-software-messaging: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..1f108a0
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormSshDriver.java
@@ -0,0 +1,272 @@
+/*
+ * 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.entity.messaging.storm;
+
+import static java.lang.String.format;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble;
+import brooklyn.event.basic.DependentConfiguration;
+import org.apache.brooklyn.location.basic.Machines;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Networking;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class StormSshDriver extends JavaSoftwareProcessSshDriver implements StormDriver {
+
+    private static final Logger log = LoggerFactory.getLogger(StormSshDriver.class);
+
+    public StormSshDriver(EntityLocal entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    public String getRoleName() {
+        return entity.getConfig(Storm.ROLE).name().toLowerCase();
+    }
+
+    public String getZeromqVersion() {
+        return entity.getConfig(Storm.ZEROMQ_VERSION);
+    }
+
+    public String getLocalDir() {
+        return Optional.fromNullable(entity.getConfig(Storm.LOCAL_DIR)).or(Os.mergePathsUnix(getRunDir(), "storm"));
+    }
+
+    public String getNimbusHostname() {
+        String result = entity.getConfig(Storm.NIMBUS_HOSTNAME);
+        if (result != null) return result;
+
+        Entity nimbus = entity.getConfig(Storm.NIMBUS_ENTITY);
+        if (nimbus == null) {
+            log.warn("No nimbus hostname available; using 'localhost'");
+            return "localhost";
+        }
+        return Entities.submit(entity, DependentConfiguration.attributeWhenReady(nimbus, Attributes.HOSTNAME)).getUnchecked();
+    }
+
+    public Integer getUiPort() {
+        return entity.getAttribute(Storm.UI_PORT);
+    }
+
+    public Map<String, Integer> getPortMap() {
+        return MutableMap.of("uiPort", getUiPort());
+    }
+
+    @Override
+    protected List<String> getCustomJavaConfigOptions() {
+        List<String> result = super.getCustomJavaConfigOptions();
+        if ("nimbus".equals(getRoleName()) || "supervisor".equals(getRoleName())) {
+            result.add("-verbose:gc");
+            result.add("-XX:+PrintGCTimeStamps");
+            result.add("-XX:+PrintGCDetails");
+        }
+
+        if ("ui".equals(getRoleName())) {
+            result.add("-Xmx768m");
+        }
+
+        return result;
+    }
+
+    public String getJvmOptsLine() {
+        return Optional.fromNullable(getShellEnvironment().get("JAVA_OPTS")).or("");
+    }
+    
+    public List<String> getZookeeperServers() {
+        ZooKeeperEnsemble zooKeeperEnsemble = entity.getConfig(Storm.ZOOKEEPER_ENSEMBLE);
+        Supplier<List<String>> supplier = Entities.attributeSupplierWhenReady(zooKeeperEnsemble, ZooKeeperEnsemble.ZOOKEEPER_SERVERS);
+        return supplier.get();
+    }
+
+    public String getStormConfigTemplateUrl() {
+        return entity.getConfig(Storm.STORM_CONFIG_TEMPLATE_URL);
+    }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this);
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("storm-%s", getVersion()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+        
+        ImmutableList.Builder<String> commands= ImmutableList.<String> builder();
+        if (!getLocation().getOsDetails().isMac()) {
+            commands.add(BashCommands.installPackage(ImmutableMap.of(
+                        "yum", "libuuid-devel",
+                        "apt", "build-essential uuid-dev pkg-config libtool automake"), 
+                    "libuuid-devel"));
+            commands.add(BashCommands.ifExecutableElse0("yum", BashCommands.sudo("yum -y groupinstall 'Development Tools'")));
+        }
+        commands.add(BashCommands.installPackage(ImmutableMap.of("yum", "git"), "git"))
+                .add(BashCommands.INSTALL_UNZIP)
+                .addAll(installNativeDependencies())
+                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
+                .add("unzip " + saveAs)
+                .add("mkdir -p " + getLocalDir())
+                .add("chmod 777 " + getLocalDir()); // FIXME
+        newScript(INSTALLING)
+                .body.append(commands.build())
+                .gatherOutput()
+                .execute();
+    }
+
+    public String getPidFile() {
+        return Os.mergePathsUnix(getRunDir(), format("%s.pid", getRoleName()));
+    }
+
+    @Override
+    protected String getLogFileLocation() {
+        return Os.mergePathsUnix(getRunDir(), "logs", format("%s.log", getRoleName()));
+    }
+
+    @Override
+    public void launch() {
+        boolean needsSleep = false;
+        if (getRoleName().equals("supervisor")) {
+            Entity nimbus = entity.getConfig(Storm.NIMBUS_ENTITY);
+            if (nimbus == null) {
+                log.warn("No nimbus entity available; not blocking before starting supervisors");
+            } else {
+                Entities.waitForServiceUp(nimbus, entity.getConfig(SoftwareProcess.START_TIMEOUT));
+                needsSleep = true;
+            }
+        }
+
+        String subnetHostname = Machines.findSubnetOrPublicHostname(entity).get();
+        log.info("Launching " + entity + " with role " + getRoleName() + " and " + "hostname (public) " 
+                + getEntity().getAttribute(Attributes.HOSTNAME) + ", " + "hostname (subnet) " + subnetHostname + ")");
+
+        // ensure only one node at a time tries to start
+        // attempting to eliminate the causes of:
+        // 2013-12-12 09:21:45 supervisor [ERROR] Error on initialization of server mk-supervisor
+        // org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /assignments
+        // TODO use SoftwareProcess#START_LATCH instead here?
+
+        Object startMutex = Optional.fromNullable(entity.getConfig(Storm.START_MUTEX)).or(new Object());
+        synchronized (startMutex) {
+            if (needsSleep) {
+                // give 10s extra to make sure nimbus is ready; we see weird zookeeper no /assignments node error otherwise
+                // (this could be optimized by recording nimbus service_up time)
+                Time.sleep(Duration.TEN_SECONDS);
+            }
+            newScript(MutableMap.of(USE_PID_FILE, getPidFile()), LAUNCHING)
+                    .body.append(format("nohup ./bin/storm %s > %s 2>&1 &", getRoleName(), getLogFileLocation()))
+                    .execute();
+        }
+    }
+
+    @Override
+    public boolean isRunning() {
+        return newScript(MutableMap.of(USE_PID_FILE, getPidFile()), CHECK_RUNNING).execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(MutableMap.of(USE_PID_FILE, getPidFile()), STOPPING).execute();
+    }
+
+    @Override
+    public void customize() {
+        log.debug("Customizing {}", entity);
+        Networking.checkPortsValid(getPortMap());
+
+        newScript(CUSTOMIZING)
+                .body.append(format("cp -R %s/* .", getExpandedInstallDir()))
+                .execute();
+
+        String destinationConfigFile = Os.mergePathsUnix(getRunDir(), "conf/storm.yaml");
+        copyTemplate(getStormConfigTemplateUrl(), destinationConfigFile);
+    }
+
+    protected List<String> installNativeDependencies() {
+        String zeromqUrl = format("http://download.zeromq.org/zeromq-%s.tar.gz", getZeromqVersion());
+        String targz = format("zeromq-%s.tar.gz", getZeromqVersion());
+        String jzmq = "https://github.com/nathanmarz/jzmq.git";
+
+        ImmutableList.Builder<String> commands = ImmutableList.<String>builder();
+        if (getLocation().getOsDetails().isMac()) {
+            commands.add("export PATH=$PATH:/usr/local/bin")
+                   .add("export JAVA_HOME=$(/usr/libexec/java_home)")
+                   .add("cd " + getInstallDir())
+                   .add(BashCommands.installPackage(ImmutableMap.of("brew", "automake"), "make"))
+                   .add(BashCommands.installPackage(ImmutableMap.of("brew", "libtool"), "libtool"))
+                   .add(BashCommands.installPackage(ImmutableMap.of("brew", "pkg-config"), "pkg-config"))
+                   .add(BashCommands.installPackage(ImmutableMap.of("brew", "zeromq"), "zeromq"))
+                   .add("git clone https://github.com/asmaier/jzmq")
+                   .add("cd jzmq")
+                   .add("./autogen.sh")
+                   .add("./configure")
+                   .add("make")
+                   .add((BashCommands.sudo("make install")))
+                   .add("cd " + getInstallDir());
+        } else {
+            commands.add("export JAVA_HOME=$(dirname $(readlink -m `which java`))/../../ || export JAVA_HOME=/usr/lib/jvm/java")
+                   .add("cd " + getInstallDir())
+                   .add(BashCommands.commandToDownloadUrlAs(zeromqUrl, targz))
+                   .add("tar xzf " + targz)
+                   .add(format("cd zeromq-%s", getZeromqVersion()))
+                   .add("./configure")
+                   .add("make")
+                   .add((BashCommands.sudo("make install")))
+                   // install jzmq
+                   .add("cd " + getInstallDir())
+                   .add("git clone " + jzmq)
+                   .add("cd jzmq")
+                   .add("./autogen.sh")
+                   .add("./configure")
+                           
+                   // hack needed on ubuntu 12.04; ignore if it fails
+                   // see https://github.com/zeromq/jzmq/issues/114
+                   .add(BashCommands.ok(
+                       "pushd src ; touch classdist_noinst.stamp ; CLASSPATH=.:./.:$CLASSPATH "
+                       + "javac -d . org/zeromq/ZMQ.java org/zeromq/App.java org/zeromq/ZMQForwarder.java org/zeromq/EmbeddedLibraryTools.java org/zeromq/ZMQQueue.java org/zeromq/ZMQStreamer.java org/zeromq/ZMQException.java"))
+                   .add(BashCommands.ok("popd"))
+
+                   .add("make")
+                   .add((BashCommands.sudo("make install")))
+                   .add("cd " + getInstallDir());
+        }
+        return commands.build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..6cb5ab0
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/AbstractZooKeeperImpl.java
@@ -0,0 +1,109 @@
+/*
+ * 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.entity.zookeeper;
+
+import java.util.concurrent.TimeUnit;
+
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.SoftwareProcessImpl;
+import brooklyn.entity.java.JavaSoftwareProcessDriver;
+import brooklyn.event.feed.jmx.JmxAttributePollConfig;
+import brooklyn.event.feed.jmx.JmxFeed;
+import brooklyn.event.feed.jmx.JmxHelper;
+
+import com.google.common.base.Functions;
+import com.google.common.base.Objects.ToStringHelper;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Apache ZooKeeper instance.
+ */
+public abstract class AbstractZooKeeperImpl extends SoftwareProcessImpl implements ZooKeeperNode {
+
+    @SuppressWarnings("unused")
+    private static final Logger log = LoggerFactory.getLogger(AbstractZooKeeperImpl.class);
+    private static final ObjectName ZOOKEEPER_MBEAN = JmxHelper.createObjectName("org.apache.ZooKeeperService:name0=StandaloneServer_port-1");
+
+    private volatile JmxFeed jmxFeed;
+
+    public AbstractZooKeeperImpl() {
+    }
+
+    @Override
+    public Integer getZookeeperPort() { return getAttribute(ZOOKEEPER_PORT); }
+
+    @Override
+    public String getHostname() { return getAttribute(HOSTNAME); }
+
+    @Override
+    public void waitForServiceUp(long duration, TimeUnit units) {
+        super.waitForServiceUp(duration, units);
+
+        if (((JavaSoftwareProcessDriver)getDriver()).isJmxEnabled()) {
+            // Wait for the MBean to exist
+            JmxHelper helper = new JmxHelper(this);
+            try {
+                helper.assertMBeanExistsEventually(ZOOKEEPER_MBEAN, units.toMillis(duration));
+            } finally {
+                helper.terminate();
+            }
+        }
+    }
+
+    @Override
+    protected void connectSensors() {
+        connectServiceUpIsRunning();
+
+        if (((JavaSoftwareProcessDriver)getDriver()).isJmxEnabled()) {
+            jmxFeed = JmxFeed.builder()
+                .entity(this)
+                .period(500, TimeUnit.MILLISECONDS)
+                .pollAttribute(new JmxAttributePollConfig<Long>(OUTSTANDING_REQUESTS)
+                        .objectName(ZOOKEEPER_MBEAN)
+                        .attributeName("OutstandingRequests")
+                        .onFailureOrException(Functions.constant(-1l)))
+                .pollAttribute(new JmxAttributePollConfig<Long>(PACKETS_RECEIVED)
+                        .objectName(ZOOKEEPER_MBEAN)
+                        .attributeName("PacketsReceived")
+                        .onFailureOrException(Functions.constant(-1l)))
+                .pollAttribute(new JmxAttributePollConfig<Long>(PACKETS_SENT)
+                        .objectName(ZOOKEEPER_MBEAN)
+                        .attributeName("PacketsSent")
+                        .onFailureOrException(Functions.constant(-1l)))
+                .build();
+        }
+    }
+
+    @Override
+    public void disconnectSensors() {
+        super.disconnectSensors();
+        disconnectServiceUpIsRunning();
+        if (jmxFeed != null) jmxFeed.stop();
+    }
+
+    @Override
+    protected ToStringHelper toStringHelper() {
+        return super.toStringHelper()
+                .add("zookeeperPort", getZookeeperPort());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperDriver.java
new file mode 100644
index 0000000..36388f0
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperDriver.java
@@ -0,0 +1,27 @@
+/*
+ * 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.entity.zookeeper;
+
+import brooklyn.entity.java.JavaSoftwareProcessDriver;
+
+public interface ZooKeeperDriver extends JavaSoftwareProcessDriver {
+
+    Integer getZooKeeperPort();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..d29bc91
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperEnsemble.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.entity.zookeeper;
+
+import java.util.List;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.group.DynamicCluster;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+
+import com.google.common.reflect.TypeToken;
+
+@Catalog(name="ZooKeeper ensemble", description="A cluster of ZooKeeper servers. "
+        + "Apache ZooKeeper enables highly reliable distributed coordination.")
+@ImplementedBy(ZooKeeperEnsembleImpl.class)
+public interface ZooKeeperEnsemble extends DynamicCluster {
+
+    @SetFromFlag("clusterName")
+    BasicAttributeSensorAndConfigKey<String> CLUSTER_NAME = new BasicAttributeSensorAndConfigKey<String>(String
+            .class, "zookeeper.cluster.name", "Name of the Zookeeper cluster", "BrooklynZookeeperCluster");
+
+    @SetFromFlag("initialSize")
+    public static final ConfigKey<Integer> INITIAL_SIZE = ConfigKeys.newConfigKeyWithDefault(DynamicCluster.INITIAL_SIZE, 3);
+
+    @SuppressWarnings("serial")
+    AttributeSensor<List<String>> ZOOKEEPER_SERVERS = Sensors.newSensor(new TypeToken<List<String>>() { },
+            "zookeeper.servers", "Hostnames to connect to cluster with");
+
+    String getClusterName();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java
new file mode 100644
index 0000000..f9ce930
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java
@@ -0,0 +1,105 @@
+/*
+ * 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.entity.zookeeper;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
+import brooklyn.entity.group.DynamicClusterImpl;
+
+import com.google.common.collect.Lists;
+
+public class ZooKeeperEnsembleImpl extends DynamicClusterImpl implements ZooKeeperEnsemble {
+
+    private static final Logger log = LoggerFactory.getLogger(ZooKeeperEnsembleImpl.class);
+    private static final AtomicInteger myId = new AtomicInteger();
+    
+    private MemberTrackingPolicy policy;
+
+    public ZooKeeperEnsembleImpl() {}
+
+    /**
+     * Sets the default {@link #MEMBER_SPEC} to describe the ZooKeeper nodes.
+     */
+    @Override
+    protected EntitySpec<?> getMemberSpec() {
+        return getConfig(MEMBER_SPEC, EntitySpec.create(ZooKeeperNode.class));
+    }
+
+    @Override
+    public String getClusterName() {
+        return getAttribute(CLUSTER_NAME);
+    }
+
+    @Override
+    public void init() {
+        log.info("Initializing the ZooKeeper Ensemble");
+        super.init();
+
+        policy = addPolicy(PolicySpec.create(MemberTrackingPolicy.class)
+                .displayName("Members tracker")
+                .configure("group", this));
+    }
+
+    public static class MemberTrackingPolicy extends AbstractMembershipTrackingPolicy {
+        @Override
+        protected void onEntityChange(Entity member) {
+        }
+
+        @Override
+        protected void onEntityAdded(Entity member) {
+            if (member.getAttribute(ZooKeeperNode.MY_ID) == null) {
+                ((EntityInternal) member).setAttribute(ZooKeeperNode.MY_ID, myId.incrementAndGet());
+            }
+        }
+
+        @Override
+        protected void onEntityRemoved(Entity member) {
+        }
+    };
+
+    @Override
+    protected void initEnrichers() {
+        super.initEnrichers();
+        
+    }
+    
+    @Override
+    public void start(Collection<? extends Location> locations) {
+        super.start(locations);
+        
+        List<String> zookeeperServers = Lists.newArrayList();
+        for (Entity zookeeper : getMembers()) {
+            zookeeperServers.add(zookeeper.getAttribute(Attributes.HOSTNAME));
+        }
+        setAttribute(ZOOKEEPER_SERVERS, zookeeperServers);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..6a67394
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperNode.java
@@ -0,0 +1,67 @@
+/*
+ * 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.entity.zookeeper;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.event.basic.BasicAttributeSensor;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Apache ZooKeeper instance.
+ */
+@Catalog(name="ZooKeeper Node", description="Apache ZooKeeper is a server which enables "
+        + "highly reliable distributed coordination.")
+@ImplementedBy(ZooKeeperNodeImpl.class)
+public interface ZooKeeperNode extends SoftwareProcess {
+
+    @SetFromFlag("version")
+    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "3.4.5");
+    @SetFromFlag("zookeeperPort")
+    PortAttributeSensorAndConfigKey ZOOKEEPER_PORT = new PortAttributeSensorAndConfigKey("zookeeper.port", "Zookeeper port", "2181+");
+    @SetFromFlag("zookeeperLeaderPort")
+    PortAttributeSensorAndConfigKey ZOOKEEPER_LEADER_PORT = new PortAttributeSensorAndConfigKey("zookeeper.leader.port", "Zookeeper leader ports", "2888+");
+    @SetFromFlag("zookeeperElectionPort")
+    PortAttributeSensorAndConfigKey ZOOKEEPER_ELECTION_PORT = new PortAttributeSensorAndConfigKey("zookeeper.election.port", "Zookeeper election ports", "3888+");
+    @SetFromFlag("downloadUrl")
+    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
+            SoftwareProcess.DOWNLOAD_URL, "http://apache.fastbull.org/zookeeper/zookeeper-${version}/zookeeper-${version}.tar.gz");
+    /**
+     * Location of the ZK configuration file template to be copied to the server.
+     */
+    @SetFromFlag("zookeeperConfig")
+    ConfigKey<String> ZOOKEEPER_CONFIG_TEMPLATE = ConfigKeys.newStringConfigKey(
+            "zookeeper.configTemplate", "Zookeeper configuration template (in freemarker format)",
+            "classpath://org/apache/brooklyn/entity/messaging/zookeeper/zoo.cfg");
+    AttributeSensor<Long> OUTSTANDING_REQUESTS = new BasicAttributeSensor<Long>(Long.class, "zookeeper.outstandingRequests", "Outstanding request count");
+    AttributeSensor<Long> PACKETS_RECEIVED = new BasicAttributeSensor<Long>(Long.class, "zookeeper.packets.received", "Total packets received");
+    AttributeSensor<Long> PACKETS_SENT = new BasicAttributeSensor<Long>(Long.class, "zookeeper.packets.sent", "Total packets sent");
+    AttributeSensor<Integer> MY_ID = new BasicAttributeSensor<Integer>(Integer.class, "zookeeper.myid", "ZooKeeper node's myId");
+
+    Integer getZookeeperPort();
+
+    String getHostname();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperNodeImpl.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperNodeImpl.java
new file mode 100644
index 0000000..275e101
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperNodeImpl.java
@@ -0,0 +1,33 @@
+/*
+ * 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.entity.zookeeper;
+
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single standalone zookeeper instance.
+ */
+public class ZooKeeperNodeImpl extends AbstractZooKeeperImpl implements ZooKeeperNode {
+
+    public ZooKeeperNodeImpl() {}
+
+    @Override
+    public Class<?> getDriverInterface() {
+        return ZooKeeperDriver.class;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperSshDriver.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperSshDriver.java
new file mode 100644
index 0000000..709e44c
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/zookeeper/ZooKeeperSshDriver.java
@@ -0,0 +1,163 @@
+/*
+ * 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.entity.zookeeper;
+
+import static java.lang.String.format;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.brooklyn.api.entity.Entity;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.net.Networking;
+import brooklyn.util.os.Os;
+import brooklyn.util.ssh.BashCommands;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+
+public class ZooKeeperSshDriver extends JavaSoftwareProcessSshDriver implements ZooKeeperDriver {
+
+    public ZooKeeperSshDriver(ZooKeeperNodeImpl entity, SshMachineLocation machine) {
+        super(entity, machine);
+    }
+
+    @Override
+    protected String getLogFileLocation() { return Os.mergePathsUnix(getRunDir(), "console.out"); }
+
+    protected Map<String, Integer> getPortMap() {
+        return MutableMap.of("zookeeperPort", getZooKeeperPort());
+    }
+
+    protected String getConfigFileName() {
+        return entity.getConfig(ZooKeeperNode.ZOOKEEPER_CONFIG_TEMPLATE);
+    }
+
+    protected int getMyId() {
+        return entity.getAttribute(ZooKeeperNode.MY_ID);
+    }
+
+    // FIXME All for one, and one for all! If any node fails then we're stuck waiting for its hostname/port forever.
+    // Need a way to terminate the wait based on the entity going on-fire etc.
+    // FIXME Race in getMemebers. Should we change DynamicCluster.grow to create the members and only then call start on them all?
+    public List<ZooKeeperServerConfig> getZookeeperServers() throws ExecutionException, InterruptedException {
+        ZooKeeperEnsemble ensemble = (ZooKeeperEnsemble) entity.getParent();
+        List<ZooKeeperServerConfig> result = Lists.newArrayList();
+
+        for (Entity member : ensemble.getMembers()) {
+            Integer myid = Entities.attributeSupplierWhenReady(member, ZooKeeperNode.MY_ID).get();
+            String hostname = Entities.attributeSupplierWhenReady(member, ZooKeeperNode.HOSTNAME).get();
+            Integer port = Entities.attributeSupplierWhenReady(member, ZooKeeperNode.ZOOKEEPER_PORT).get();
+            Integer leaderPort = Entities.attributeSupplierWhenReady(member, ZooKeeperNode.ZOOKEEPER_LEADER_PORT).get();
+            Integer electionPort = Entities.attributeSupplierWhenReady(member, ZooKeeperNode.ZOOKEEPER_ELECTION_PORT).get();
+            result.add(new ZooKeeperServerConfig(myid, hostname, port, leaderPort, electionPort));
+        }
+        return result;
+    }
+
+    @Override
+    public Integer getZooKeeperPort() {
+        return getEntity().getAttribute(ZooKeeperNode.ZOOKEEPER_PORT);
+    }
+
+    @Override
+    public boolean isRunning() {
+        return newScript(MutableMap.of(USE_PID_FILE, getPidFile()), CHECK_RUNNING).execute() == 0;
+    }
+
+    @Override
+    public void stop() {
+        newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), STOPPING).execute();     
+    }
+
+    @Override
+    public void preInstall() {
+        resolver = Entities.newDownloader(this);
+        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("zookeeper-%s", getVersion()))));
+    }
+
+    @Override
+    public void install() {
+        List<String> urls = resolver.getTargets();
+        String saveAs = resolver.getFilename();
+
+        List<String> commands = ImmutableList.<String> builder()
+                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
+                .add(BashCommands.INSTALL_TAR)
+                .add("tar xzfv " + saveAs)
+                .build();
+
+        newScript(INSTALLING)
+                .body.append(commands)
+                .execute();
+    }
+
+    @Override
+    public void customize() {
+        log.debug("Customizing {}", entity);
+        Networking.checkPortsValid(getPortMap());
+        newScript(CUSTOMIZING)
+                .body.append(
+                        format("cp -R %s/* .", getExpandedInstallDir()),
+                        format("mkdir %s/zookeeper", getRunDir()),
+                        format("echo %d > %s/zookeeper/myid", getMyId(), getRunDir())
+                    )
+                .execute();
+
+        String destinationConfigFile = Os.mergePathsUnix(getRunDir(), "conf/zoo.cfg");
+        copyTemplate(getConfigFileName(), destinationConfigFile);
+    }
+
+    public String getPidFile() { return Os.mergePathsUnix(getRunDir(), "zookeeper.pid"); }
+
+    @Override
+    public void launch() {
+        newScript(MutableMap.of(USE_PID_FILE, getPidFile()), LAUNCHING)
+                .body.append(format("nohup java $JAVA_OPTS -cp zookeeper-%s.jar:lib/*:conf org.apache.zookeeper.server.quorum.QuorumPeerMain conf/zoo.cfg > %s 2>&1 &", getVersion(), getLogFileLocation()))
+                .execute();
+    }
+
+    public static class ZooKeeperServerConfig {
+        private final Integer myid;
+        private final String hostname;
+        private final Integer port;
+        private final Integer leaderPort;
+        private final Integer electionPort;
+
+        public ZooKeeperServerConfig(Integer myid, String hostname, Integer port, Integer leaderPort, Integer electionPort) {
+            this.myid = myid;
+            this.hostname = hostname;
+            this.port = port;
+            this.leaderPort = leaderPort;
+            this.electionPort = electionPort;
+        }
+
+        public Integer getMyid() { return myid; }
+        public String getHostname() { return hostname; }
+        public Integer getPort() { return port; }
+        public Integer getLeaderPort() { return leaderPort; }
+        public Integer getElectionPort() { return electionPort; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/brooklyn/entity/messaging/activemq/activemq.xml
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/brooklyn/entity/messaging/activemq/activemq.xml b/software/messaging/src/main/resources/brooklyn/entity/messaging/activemq/activemq.xml
deleted file mode 100644
index 52114d1..0000000
--- a/software/messaging/src/main/resources/brooklyn/entity/messaging/activemq/activemq.xml
+++ /dev/null
@@ -1,154 +0,0 @@
-[#ftl]
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Based on standard file from ActiveMQ Version 5.7.0 -->
-<!-- START SNIPPET: example -->
-<beans
-  xmlns="http://www.springframework.org/schema/beans"
-  xmlns:amq="http://activemq.apache.org/schema/core"
-  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
-  http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
-
-    <!-- Allows us to use system properties as variables in this configuration file -->
-    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
-        <property name="locations">
-            <value>file:[#noparse]${activemq.conf}[/#noparse]/credentials.properties</value>
-        </property>
-    </bean>
-
-    <!--
-        The <broker> element is used to configure the ActiveMQ broker.
-    -->
-    <broker useJmx="true" xmlns="http://activemq.apache.org/schema/core" brokerName="${entity.brokerName}" dataDirectory="[#noparse]${activemq.data}[/#noparse]">
-
-        <!--
-            For better performances use VM cursor and small memory limit.
-            For more information, see:
-
-            http://activemq.apache.org/message-cursors.html
-
-            Also, if your producer is "hanging", it's probably due to producer flow control.
-            For more information, see:
-            http://activemq.apache.org/producer-flow-control.html
-        -->
-
-        <destinationPolicy>
-            <policyMap>
-              <policyEntries>
-                <policyEntry topic=">" producerFlowControl="true">
-                    <!-- The constantPendingMessageLimitStrategy is used to prevent
-                         slow topic consumers to block producers and affect other consumers
-                         by limiting the number of messages that are retained
-                         For more information, see:
-
-                         http://activemq.apache.org/slow-consumer-handling.html
-
-                    -->
-                  <pendingMessageLimitStrategy>
-                    <constantPendingMessageLimitStrategy limit="1000"/>
-                  </pendingMessageLimitStrategy>
-                </policyEntry>
-                <policyEntry queue=">" producerFlowControl="true" memoryLimit="1mb">
-                  <!-- Use VM cursor for better latency
-                       For more information, see:
-
-                       http://activemq.apache.org/message-cursors.html
-
-                  <pendingQueuePolicy>
-                    <vmQueueCursor/>
-                  </pendingQueuePolicy>
-                  -->
-                </policyEntry>
-              </policyEntries>
-            </policyMap>
-        </destinationPolicy>
-
-
-        <!--
-            The managementContext is used to configure how ActiveMQ is exposed in
-            JMX. By default, ActiveMQ uses the MBean server that is started by
-            the JVM. For more information, see:
-
-            http://activemq.apache.org/jmx.html
-        -->
-        <managementContext>
-            [#if entity.jmxPort > 0]
-            <managementContext connectorPort="${entity.jmxPort?c}"/>
-            [#else]
-            <managementContext createConnector="false"/>
-            [/#if]
-        </managementContext>
-
-        <!--
-            Configure message persistence for the broker. The default persistence
-            mechanism is the KahaDB store (identified by the kahaDB tag).
-            For more information, see:
-
-            http://activemq.apache.org/persistence.html
-        -->
-        <persistenceAdapter>
-            <kahaDB directory="[#noparse]${activemq.data}[/#noparse]/kahadb"/>
-        </persistenceAdapter>
-
-
-          <!--
-            The systemUsage controls the maximum amount of space the broker will
-            use before slowing down producers. For more information, see:
-            http://activemq.apache.org/producer-flow-control.html
-            If using ActiveMQ embedded - the following limits could safely be used:
-
-        <systemUsage>
-            <systemUsage>
-                <memoryUsage>
-                    <memoryUsage limit="20 mb"/>
-                </memoryUsage>
-                <storeUsage>
-                    <storeUsage limit="1 gb"/>
-                </storeUsage>
-                <tempUsage>
-                    <tempUsage limit="100 mb"/>
-                </tempUsage>
-            </systemUsage>
-        </systemUsage>
-        -->
-          <systemUsage>
-            <systemUsage>
-                <memoryUsage>
-                    <memoryUsage limit="64 mb"/>
-                </memoryUsage>
-                <storeUsage>
-                    <storeUsage limit="100 gb"/>
-                </storeUsage>
-                <tempUsage>
-                    <tempUsage limit="50 gb"/>
-                </tempUsage>
-            </systemUsage>
-        </systemUsage>
-
-        <!--
-            The transport connectors expose ActiveMQ over a given protocol to
-            clients and other brokers. For more information, see:
-
-            http://activemq.apache.org/configuring-transports.html
-        -->
-        <transportConnectors>
-            <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
-            <transportConnector name="openwire" uri="tcp://0.0.0.0:${entity.openWirePort?c}?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600"/>
-        </transportConnectors>
-
-        <!-- destroy the spring context on shutdown to stop jetty -->
-        <shutdownHooks>
-            <bean xmlns="http://www.springframework.org/schema/beans" class="org.apache.activemq.hooks.SpringContextHook" />
-        </shutdownHooks>
-
-    </broker>
-
-    <!--
-        Enable web consoles, REST and Ajax APIs and demos
-
-        Take a look at [#noparse]${ACTIVEMQ_HOME}[/#noparse]/conf/jetty.xml for more details
-    -->
-    <import resource="jetty.xml"/>
-
-</beans>
-<!-- END SNIPPET: example -->

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/kafka-google-doorway.jpg
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/kafka-google-doorway.jpg b/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/kafka-google-doorway.jpg
deleted file mode 100644
index d600ef5..0000000
Binary files a/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/kafka-google-doorway.jpg and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/server.properties
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/server.properties b/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/server.properties
deleted file mode 100644
index feb871f..0000000
--- a/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/server.properties
+++ /dev/null
@@ -1,112 +0,0 @@
-[#ftl]
-#
-##
-# KafkaBroker configuration template for Brooklyn
-#
-# see kafka.server.KafkaConfig for additional details and defaults
-##
-
-############################# Server Basics #############################
-# The id of the broker. This must be set to a unique integer for each broker.
-broker.id=${entity.brokerId?c}
-
-############################# Socket Server Settings #############################
-
-# The port the socket server listens on
-port=${entity.kafkaPort?c}
-
-# Hostname the broker will bind to. If not set, the server will bind to all interfaces
-host.name=${driver.hostname}
-
-# Hostname the broker will advertise to producers and consumers. If not set, it uses the
-# value for "host.name" if configured.  Otherwise, it will use the value returned from
-# java.net.InetAddress.getCanonicalHostName().
-#advertised.host.name=<hostname routable by clients>
-
-# The port to publish to ZooKeeper for clients to use. If this is not set,
-# it will publish the same port that the broker binds to.
-#advertised.port=<port accessible by clients>
-
-# The number of threads handling network requests
-num.network.threads=3
- 
-# The number of threads doing disk I/O
-num.io.threads=8
-
-# The send buffer (SO_SNDBUF) used by the socket server
-socket.send.buffer.bytes=102400
-
-# The receive buffer (SO_RCVBUF) used by the socket server
-socket.receive.buffer.bytes=102400
-
-# The maximum size of a request that the socket server will accept (protection against OOM)
-max.socket.request.bytes=104857600
-
-
-############################# Log Basics #############################
-
-# The directory under which to store log files
-log.dir=${driver.runDir}/kafka-logs
-
-# The default number of log partitions per topic. More partitions allow greater
-# parallelism for consumption, but this will also result in more files across
-# the brokers.
-num.partitions=1
-
-# The number of threads per data directory to be used for log recovery at startup and flushing at shutdown.
-# This value is recommended to be increased for installations with data dirs located in RAID array.
-num.recovery.threads.per.data.dir=1
-
-############################# Log Flush Policy #############################
-
-# Messages are immediately written to the filesystem but by default we only fsync() to sync
-# the OS cache lazily. The following configurations control the flush of data to disk. 
-# There are a few important trade-offs here:
-#    1. Durability: Unflushed data may be lost if you are not using replication.
-#    2. Latency: Very large flush intervals may lead to latency spikes when the flush does occur as there will be a lot of data to flush.
-#    3. Throughput: The flush is generally the most expensive operation, and a small flush interval may lead to exceessive seeks. 
-# The settings below allow one to configure the flush policy to flush data after a period of time or
-# every N messages (or both). This can be done globally and overridden on a per-topic basis.
-
-# The number of messages to accept before forcing a flush of data to disk
-log.flush.interval.messages=10000
-
-# The maximum amount of time a message can sit in a log before we force a flush
-log.flush.interval.ms=1000
-
-############################# Log Retention Policy #############################
-
-# The following configurations control the disposal of log segments. The policy can
-# be set to delete segments after a period of time, or after a given size has accumulated.
-# A segment will be deleted whenever *either* of these criteria are met. Deletion always happens
-# from the end of the log.
-
-# The minimum age of a log file to be eligible for deletion
-log.retention.hours=168
-
-# A size-based retention policy for logs. Segments are pruned from the log as long as the remaining
-# segments don't drop below log.retention.bytes.
-#log.retention.bytes=1073741824
-
-# The maximum size of a log segment file. When this size is reached a new log segment will be created.
-log.segment.bytes=1073741824
-
-# The interval at which log segments are checked to see if they can be deleted according 
-# to the retention policies
-log.retention.check.interval.ms=300000
-
-# By default the log cleaner is disabled and the log retention policy will default to just delete segments after their retention expires.
-# If log.cleaner.enable=true is set the cleaner will be enabled and individual logs can then be marked for log compaction.
-log.cleaner.enable=false
-
-############################# Zookeeper #############################
-
-# Zookeeper connection string (see zookeeper docs for details).
-# This is a comma separated host:port pairs, each corresponding to a zk
-# server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002".
-# You can also append an optional chroot string to the urls to specify the
-# root directory for all kafka znodes.
-zookeeper.connect=${entity.zookeeper.hostname}:${entity.zookeeper.zookeeperPort?c}
-
-# Timeout in ms for connecting to zookeeper
-zookeeper.connection.timeout.ms=1000000
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/zookeeper.properties
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/zookeeper.properties b/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/zookeeper.properties
deleted file mode 100644
index 646d2f1..0000000
--- a/software/messaging/src/main/resources/brooklyn/entity/messaging/kafka/zookeeper.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-[#ftl]
-#
-
-##
-# KafkaZookeeper configuration template for Brooklyn
-##
-
-# the directory where the snapshot is stored.
-dataDir=${driver.runDir}/zookeeper
-# the port at which the clients will connect
-clientPort=${entity.zookeeperPort?c}
-# disable the per-ip limit on the number of connections since this is a non-production config
-maxClientCnxns=0

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/brooklyn/entity/messaging/rabbit/rabbitmq.config
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/brooklyn/entity/messaging/rabbit/rabbitmq.config b/software/messaging/src/main/resources/brooklyn/entity/messaging/rabbit/rabbitmq.config
deleted file mode 100644
index b4428f0..0000000
--- a/software/messaging/src/main/resources/brooklyn/entity/messaging/rabbit/rabbitmq.config
+++ /dev/null
@@ -1,5 +0,0 @@
-[
-<#if entity.enableManagementPlugin>
-    {rabbitmq_mochiweb, [{listeners, [{mgmt, [{port, ${entity.managementPort?c}}]}]}]}
-</#if>
-].
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/brooklyn/entity/messaging/storm/storm.yaml
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/brooklyn/entity/messaging/storm/storm.yaml b/software/messaging/src/main/resources/brooklyn/entity/messaging/storm/storm.yaml
deleted file mode 100644
index 99f0c71..0000000
--- a/software/messaging/src/main/resources/brooklyn/entity/messaging/storm/storm.yaml
+++ /dev/null
@@ -1,39 +0,0 @@
-[#ftl]
-#
-# Storm Configuration
-[#if driver.zookeeperServers?has_content]
- storm.zookeeper.servers:
-[#list driver.zookeeperServers as zkServer]
-   - "${zkServer}"
-[/#list]
-[/#if]
-
- storm.local.dir: "${driver.localDir}"
-
-### ui.* configs are for the master
- ui.port: ${driver.uiPort?c}
- ui.childopts: "-Xmx768m"
-
-[#if driver.roleName == "ui"]
- nimbus.host: "${driver.nimbusHostname}"
-[/#if]
-
- nimbus.childopts: " ${driver.jvmOptsLine}"
- worker.childopts: " ${driver.jvmOptsLine}"
- supervisor.childopts: " ${driver.jvmOptsLine}" 
-  
-# ##### These may optionally be filled in:
-#    
-## List of custom serializations
-# topology.kryo.register:
-#     - org.mycompany.MyType
-#     - org.mycompany.MyType2: org.mycompany.MyType2Serializer
-#
-## List of custom kryo decorators
-# topology.kryo.decorators:
-#     - org.mycompany.MyDecorator
-#
-## Locations of the drpc servers
-# drpc.servers:
-#     - "server1"
-#     - "server2"

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/brooklyn/entity/messaging/zookeeper/zoo.cfg
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/brooklyn/entity/messaging/zookeeper/zoo.cfg b/software/messaging/src/main/resources/brooklyn/entity/messaging/zookeeper/zoo.cfg
deleted file mode 100644
index 79721a6..0000000
--- a/software/messaging/src/main/resources/brooklyn/entity/messaging/zookeeper/zoo.cfg
+++ /dev/null
@@ -1,42 +0,0 @@
-[#ftl]
-#
-# 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.
-#
-
-##
-# ZooKeeper configuration template for Brooklyn
-##
-
-# The number of milliseconds of each tick
-tickTime=2000
-# The number of ticks that the initial
-# synchronization phase can take
-initLimit=10
-# The number of ticks that can pass between
-# sending a request and getting an acknowledgement
-syncLimit=5
-# the directory where the snapshot is stored.
-dataDir=${driver.runDir}/zookeeper
-# the port at which the clients will connect
-clientPort=${entity.zookeeperPort?c}
-# disable the per-ip limit on the number of connections since this is a non-production config
-maxClientCnxns=0
-
-[#list driver.zookeeperServers as zkServer]
-server.${zkServer.myid?c}=${zkServer.hostname}:${zkServer.leaderPort?c}:${zkServer.electionPort?c}
-[/#list]

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/activemq/activemq.xml
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/activemq/activemq.xml b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/activemq/activemq.xml
new file mode 100644
index 0000000..52114d1
--- /dev/null
+++ b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/activemq/activemq.xml
@@ -0,0 +1,154 @@
+[#ftl]
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Based on standard file from ActiveMQ Version 5.7.0 -->
+<!-- START SNIPPET: example -->
+<beans
+  xmlns="http://www.springframework.org/schema/beans"
+  xmlns:amq="http://activemq.apache.org/schema/core"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+  http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
+
+    <!-- Allows us to use system properties as variables in this configuration file -->
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="locations">
+            <value>file:[#noparse]${activemq.conf}[/#noparse]/credentials.properties</value>
+        </property>
+    </bean>
+
+    <!--
+        The <broker> element is used to configure the ActiveMQ broker.
+    -->
+    <broker useJmx="true" xmlns="http://activemq.apache.org/schema/core" brokerName="${entity.brokerName}" dataDirectory="[#noparse]${activemq.data}[/#noparse]">
+
+        <!--
+            For better performances use VM cursor and small memory limit.
+            For more information, see:
+
+            http://activemq.apache.org/message-cursors.html
+
+            Also, if your producer is "hanging", it's probably due to producer flow control.
+            For more information, see:
+            http://activemq.apache.org/producer-flow-control.html
+        -->
+
+        <destinationPolicy>
+            <policyMap>
+              <policyEntries>
+                <policyEntry topic=">" producerFlowControl="true">
+                    <!-- The constantPendingMessageLimitStrategy is used to prevent
+                         slow topic consumers to block producers and affect other consumers
+                         by limiting the number of messages that are retained
+                         For more information, see:
+
+                         http://activemq.apache.org/slow-consumer-handling.html
+
+                    -->
+                  <pendingMessageLimitStrategy>
+                    <constantPendingMessageLimitStrategy limit="1000"/>
+                  </pendingMessageLimitStrategy>
+                </policyEntry>
+                <policyEntry queue=">" producerFlowControl="true" memoryLimit="1mb">
+                  <!-- Use VM cursor for better latency
+                       For more information, see:
+
+                       http://activemq.apache.org/message-cursors.html
+
+                  <pendingQueuePolicy>
+                    <vmQueueCursor/>
+                  </pendingQueuePolicy>
+                  -->
+                </policyEntry>
+              </policyEntries>
+            </policyMap>
+        </destinationPolicy>
+
+
+        <!--
+            The managementContext is used to configure how ActiveMQ is exposed in
+            JMX. By default, ActiveMQ uses the MBean server that is started by
+            the JVM. For more information, see:
+
+            http://activemq.apache.org/jmx.html
+        -->
+        <managementContext>
+            [#if entity.jmxPort > 0]
+            <managementContext connectorPort="${entity.jmxPort?c}"/>
+            [#else]
+            <managementContext createConnector="false"/>
+            [/#if]
+        </managementContext>
+
+        <!--
+            Configure message persistence for the broker. The default persistence
+            mechanism is the KahaDB store (identified by the kahaDB tag).
+            For more information, see:
+
+            http://activemq.apache.org/persistence.html
+        -->
+        <persistenceAdapter>
+            <kahaDB directory="[#noparse]${activemq.data}[/#noparse]/kahadb"/>
+        </persistenceAdapter>
+
+
+          <!--
+            The systemUsage controls the maximum amount of space the broker will
+            use before slowing down producers. For more information, see:
+            http://activemq.apache.org/producer-flow-control.html
+            If using ActiveMQ embedded - the following limits could safely be used:
+
+        <systemUsage>
+            <systemUsage>
+                <memoryUsage>
+                    <memoryUsage limit="20 mb"/>
+                </memoryUsage>
+                <storeUsage>
+                    <storeUsage limit="1 gb"/>
+                </storeUsage>
+                <tempUsage>
+                    <tempUsage limit="100 mb"/>
+                </tempUsage>
+            </systemUsage>
+        </systemUsage>
+        -->
+          <systemUsage>
+            <systemUsage>
+                <memoryUsage>
+                    <memoryUsage limit="64 mb"/>
+                </memoryUsage>
+                <storeUsage>
+                    <storeUsage limit="100 gb"/>
+                </storeUsage>
+                <tempUsage>
+                    <tempUsage limit="50 gb"/>
+                </tempUsage>
+            </systemUsage>
+        </systemUsage>
+
+        <!--
+            The transport connectors expose ActiveMQ over a given protocol to
+            clients and other brokers. For more information, see:
+
+            http://activemq.apache.org/configuring-transports.html
+        -->
+        <transportConnectors>
+            <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
+            <transportConnector name="openwire" uri="tcp://0.0.0.0:${entity.openWirePort?c}?maximumConnections=1000&amp;wireformat.maxFrameSize=104857600"/>
+        </transportConnectors>
+
+        <!-- destroy the spring context on shutdown to stop jetty -->
+        <shutdownHooks>
+            <bean xmlns="http://www.springframework.org/schema/beans" class="org.apache.activemq.hooks.SpringContextHook" />
+        </shutdownHooks>
+
+    </broker>
+
+    <!--
+        Enable web consoles, REST and Ajax APIs and demos
+
+        Take a look at [#noparse]${ACTIVEMQ_HOME}[/#noparse]/conf/jetty.xml for more details
+    -->
+    <import resource="jetty.xml"/>
+
+</beans>
+<!-- END SNIPPET: example -->

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/kafka-google-doorway.jpg
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/kafka-google-doorway.jpg b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/kafka-google-doorway.jpg
new file mode 100644
index 0000000..d600ef5
Binary files /dev/null and b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/kafka-google-doorway.jpg differ

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/server.properties
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/server.properties b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/server.properties
new file mode 100644
index 0000000..feb871f
--- /dev/null
+++ b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/server.properties
@@ -0,0 +1,112 @@
+[#ftl]
+#
+##
+# KafkaBroker configuration template for Brooklyn
+#
+# see kafka.server.KafkaConfig for additional details and defaults
+##
+
+############################# Server Basics #############################
+# The id of the broker. This must be set to a unique integer for each broker.
+broker.id=${entity.brokerId?c}
+
+############################# Socket Server Settings #############################
+
+# The port the socket server listens on
+port=${entity.kafkaPort?c}
+
+# Hostname the broker will bind to. If not set, the server will bind to all interfaces
+host.name=${driver.hostname}
+
+# Hostname the broker will advertise to producers and consumers. If not set, it uses the
+# value for "host.name" if configured.  Otherwise, it will use the value returned from
+# java.net.InetAddress.getCanonicalHostName().
+#advertised.host.name=<hostname routable by clients>
+
+# The port to publish to ZooKeeper for clients to use. If this is not set,
+# it will publish the same port that the broker binds to.
+#advertised.port=<port accessible by clients>
+
+# The number of threads handling network requests
+num.network.threads=3
+ 
+# The number of threads doing disk I/O
+num.io.threads=8
+
+# The send buffer (SO_SNDBUF) used by the socket server
+socket.send.buffer.bytes=102400
+
+# The receive buffer (SO_RCVBUF) used by the socket server
+socket.receive.buffer.bytes=102400
+
+# The maximum size of a request that the socket server will accept (protection against OOM)
+max.socket.request.bytes=104857600
+
+
+############################# Log Basics #############################
+
+# The directory under which to store log files
+log.dir=${driver.runDir}/kafka-logs
+
+# The default number of log partitions per topic. More partitions allow greater
+# parallelism for consumption, but this will also result in more files across
+# the brokers.
+num.partitions=1
+
+# The number of threads per data directory to be used for log recovery at startup and flushing at shutdown.
+# This value is recommended to be increased for installations with data dirs located in RAID array.
+num.recovery.threads.per.data.dir=1
+
+############################# Log Flush Policy #############################
+
+# Messages are immediately written to the filesystem but by default we only fsync() to sync
+# the OS cache lazily. The following configurations control the flush of data to disk. 
+# There are a few important trade-offs here:
+#    1. Durability: Unflushed data may be lost if you are not using replication.
+#    2. Latency: Very large flush intervals may lead to latency spikes when the flush does occur as there will be a lot of data to flush.
+#    3. Throughput: The flush is generally the most expensive operation, and a small flush interval may lead to exceessive seeks. 
+# The settings below allow one to configure the flush policy to flush data after a period of time or
+# every N messages (or both). This can be done globally and overridden on a per-topic basis.
+
+# The number of messages to accept before forcing a flush of data to disk
+log.flush.interval.messages=10000
+
+# The maximum amount of time a message can sit in a log before we force a flush
+log.flush.interval.ms=1000
+
+############################# Log Retention Policy #############################
+
+# The following configurations control the disposal of log segments. The policy can
+# be set to delete segments after a period of time, or after a given size has accumulated.
+# A segment will be deleted whenever *either* of these criteria are met. Deletion always happens
+# from the end of the log.
+
+# The minimum age of a log file to be eligible for deletion
+log.retention.hours=168
+
+# A size-based retention policy for logs. Segments are pruned from the log as long as the remaining
+# segments don't drop below log.retention.bytes.
+#log.retention.bytes=1073741824
+
+# The maximum size of a log segment file. When this size is reached a new log segment will be created.
+log.segment.bytes=1073741824
+
+# The interval at which log segments are checked to see if they can be deleted according 
+# to the retention policies
+log.retention.check.interval.ms=300000
+
+# By default the log cleaner is disabled and the log retention policy will default to just delete segments after their retention expires.
+# If log.cleaner.enable=true is set the cleaner will be enabled and individual logs can then be marked for log compaction.
+log.cleaner.enable=false
+
+############################# Zookeeper #############################
+
+# Zookeeper connection string (see zookeeper docs for details).
+# This is a comma separated host:port pairs, each corresponding to a zk
+# server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002".
+# You can also append an optional chroot string to the urls to specify the
+# root directory for all kafka znodes.
+zookeeper.connect=${entity.zookeeper.hostname}:${entity.zookeeper.zookeeperPort?c}
+
+# Timeout in ms for connecting to zookeeper
+zookeeper.connection.timeout.ms=1000000
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/zookeeper.properties
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/zookeeper.properties b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/zookeeper.properties
new file mode 100644
index 0000000..646d2f1
--- /dev/null
+++ b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/kafka/zookeeper.properties
@@ -0,0 +1,13 @@
+[#ftl]
+#
+
+##
+# KafkaZookeeper configuration template for Brooklyn
+##
+
+# the directory where the snapshot is stored.
+dataDir=${driver.runDir}/zookeeper
+# the port at which the clients will connect
+clientPort=${entity.zookeeperPort?c}
+# disable the per-ip limit on the number of connections since this is a non-production config
+maxClientCnxns=0

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/rabbit/rabbitmq.config
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/rabbit/rabbitmq.config b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/rabbit/rabbitmq.config
new file mode 100644
index 0000000..b4428f0
--- /dev/null
+++ b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/rabbit/rabbitmq.config
@@ -0,0 +1,5 @@
+[
+<#if entity.enableManagementPlugin>
+    {rabbitmq_mochiweb, [{listeners, [{mgmt, [{port, ${entity.managementPort?c}}]}]}]}
+</#if>
+].
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/storm/storm.yaml
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/storm/storm.yaml b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/storm/storm.yaml
new file mode 100644
index 0000000..99f0c71
--- /dev/null
+++ b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/storm/storm.yaml
@@ -0,0 +1,39 @@
+[#ftl]
+#
+# Storm Configuration
+[#if driver.zookeeperServers?has_content]
+ storm.zookeeper.servers:
+[#list driver.zookeeperServers as zkServer]
+   - "${zkServer}"
+[/#list]
+[/#if]
+
+ storm.local.dir: "${driver.localDir}"
+
+### ui.* configs are for the master
+ ui.port: ${driver.uiPort?c}
+ ui.childopts: "-Xmx768m"
+
+[#if driver.roleName == "ui"]
+ nimbus.host: "${driver.nimbusHostname}"
+[/#if]
+
+ nimbus.childopts: " ${driver.jvmOptsLine}"
+ worker.childopts: " ${driver.jvmOptsLine}"
+ supervisor.childopts: " ${driver.jvmOptsLine}" 
+  
+# ##### These may optionally be filled in:
+#    
+## List of custom serializations
+# topology.kryo.register:
+#     - org.mycompany.MyType
+#     - org.mycompany.MyType2: org.mycompany.MyType2Serializer
+#
+## List of custom kryo decorators
+# topology.kryo.decorators:
+#     - org.mycompany.MyDecorator
+#
+## Locations of the drpc servers
+# drpc.servers:
+#     - "server1"
+#     - "server2"

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/zookeeper/zoo.cfg
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/zookeeper/zoo.cfg b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/zookeeper/zoo.cfg
new file mode 100644
index 0000000..79721a6
--- /dev/null
+++ b/software/messaging/src/main/resources/org/apache/brooklyn/entity/messaging/zookeeper/zoo.cfg
@@ -0,0 +1,42 @@
+[#ftl]
+#
+# 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.
+#
+
+##
+# ZooKeeper configuration template for Brooklyn
+##
+
+# The number of milliseconds of each tick
+tickTime=2000
+# The number of ticks that the initial
+# synchronization phase can take
+initLimit=10
+# The number of ticks that can pass between
+# sending a request and getting an acknowledgement
+syncLimit=5
+# the directory where the snapshot is stored.
+dataDir=${driver.runDir}/zookeeper
+# the port at which the clients will connect
+clientPort=${entity.zookeeperPort?c}
+# disable the per-ip limit on the number of connections since this is a non-production config
+maxClientCnxns=0
+
+[#list driver.zookeeperServers as zkServer]
+server.${zkServer.myid?c}=${zkServer.hostname}:${zkServer.leaderPort?c}:${zkServer.electionPort?c}
+[/#list]

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.java
deleted file mode 100644
index aaffda8..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.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 brooklyn.entity.messaging.activemq;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-
-import javax.jms.Connection;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-
-import org.apache.activemq.ActiveMQConnectionFactory;
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.AbstractEc2LiveTest;
-import brooklyn.entity.trait.Startable;
-
-import com.google.common.collect.ImmutableList;
-
-public class ActiveMQEc2LiveTest extends AbstractEc2LiveTest {
-
-    /**
-     * Test that can install+start, and use, ActiveMQ.
-     */
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        String queueName = "testQueue";
-        int number = 10;
-        String content = "01234567890123456789012345678901";
-
-        // Start broker with a configured queue
-        ActiveMQBroker activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class).configure("queue", queueName));
-        
-        app.start(ImmutableList.of(loc));
-        
-        EntityTestUtils.assertAttributeEqualsEventually(activeMQ, Startable.SERVICE_UP, true);
-
-        // Check queue created
-        assertEquals(ImmutableList.copyOf(activeMQ.getQueueNames()), ImmutableList.of(queueName));
-        assertEquals(activeMQ.getChildren().size(), 1);
-        assertEquals(activeMQ.getQueues().size(), 1);
-
-        // Get the named queue entity
-        ActiveMQQueue queue = activeMQ.getQueues().get(queueName);
-        assertNotNull(queue);
-
-        // Connect to broker using JMS and send messages
-        Connection connection = getActiveMQConnection(activeMQ);
-        clearQueue(connection, queueName);
-        EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, 0);
-        sendMessages(connection, number, queueName, content);
-
-        // Check messages arrived
-        EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, number);
-
-        connection.close();
-    }
-
-    private Connection getActiveMQConnection(ActiveMQBroker activeMQ) throws Exception {
-        int port = activeMQ.getAttribute(ActiveMQBroker.OPEN_WIRE_PORT);
-        String address = activeMQ.getAttribute(ActiveMQBroker.ADDRESS);
-        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(String.format("tcp://%s:%s", address, port));
-        Connection connection = factory.createConnection("admin", "activemq");
-        connection.start();
-        return connection;
-    }
-
-    private void sendMessages(Connection connection, int count, String queueName, String content) throws Exception {
-        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-        org.apache.activemq.command.ActiveMQQueue destination = (org.apache.activemq.command.ActiveMQQueue) session.createQueue(queueName);
-        MessageProducer messageProducer = session.createProducer(destination);
-
-        for (int i = 0; i < count; i++) {
-            TextMessage message = session.createTextMessage(content);
-            messageProducer.send(message);
-        }
-
-        session.close();
-    }
-
-    private int clearQueue(Connection connection, String queueName) throws Exception {
-        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-        org.apache.activemq.command.ActiveMQQueue destination = (org.apache.activemq.command.ActiveMQQueue) session.createQueue(queueName);
-        MessageConsumer messageConsumer = session.createConsumer(destination);
-
-        int received = 0;
-        while (messageConsumer.receive(500) != null) received++;
-
-        session.close();
-
-        return received;
-    }
-    
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQGoogleComputeLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQGoogleComputeLiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQGoogleComputeLiveTest.java
deleted file mode 100644
index e26dc2d..0000000
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/activemq/ActiveMQGoogleComputeLiveTest.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 brooklyn.entity.messaging.activemq;
-
-import brooklyn.entity.AbstractGoogleComputeLiveTest;
-import brooklyn.entity.trait.Startable;
-
-import com.google.common.collect.ImmutableList;
-
-import org.apache.activemq.ActiveMQConnectionFactory;
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.test.EntityTestUtils;
-import org.testng.annotations.Test;
-
-import javax.jms.Connection;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-import javax.jms.Session;
-import javax.jms.TextMessage;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-
-public class ActiveMQGoogleComputeLiveTest extends AbstractGoogleComputeLiveTest {
-
-    /**
-     * Test that can install+start, and use, ActiveMQ.
-     */
-    @Override
-    protected void doTest(Location loc) throws Exception {
-        String queueName = "testQueue";
-        int number = 10;
-        String content = "01234567890123456789012345678901";
-
-        // Start broker with a configured queue
-        ActiveMQBroker activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class).configure("queue", queueName));
-        
-        app.start(ImmutableList.of(loc));
-        
-        EntityTestUtils.assertAttributeEqualsEventually(activeMQ, Startable.SERVICE_UP, true);
-
-        // Check queue created
-        assertEquals(ImmutableList.copyOf(activeMQ.getQueueNames()), ImmutableList.of(queueName));
-        assertEquals(activeMQ.getChildren().size(), 1);
-        assertEquals(activeMQ.getQueues().size(), 1);
-
-        // Get the named queue entity
-        ActiveMQQueue queue = activeMQ.getQueues().get(queueName);
-        assertNotNull(queue);
-
-        // Connect to broker using JMS and send messages
-        Connection connection = getActiveMQConnection(activeMQ);
-        clearQueue(connection, queueName);
-        EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, 0);
-        sendMessages(connection, number, queueName, content);
-
-        // Check messages arrived
-        EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, number);
-
-        connection.close();
-    }
-
-    private Connection getActiveMQConnection(ActiveMQBroker activeMQ) throws Exception {
-        int port = activeMQ.getAttribute(ActiveMQBroker.OPEN_WIRE_PORT);
-        String address = activeMQ.getAttribute(ActiveMQBroker.ADDRESS);
-        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(String.format("tcp://%s:%s", address, port));
-        Connection connection = factory.createConnection("admin", "activemq");
-        connection.start();
-        return connection;
-    }
-
-    private void sendMessages(Connection connection, int count, String queueName, String content) throws Exception {
-        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-        org.apache.activemq.command.ActiveMQQueue destination = (org.apache.activemq.command.ActiveMQQueue) session.createQueue(queueName);
-        MessageProducer messageProducer = session.createProducer(destination);
-
-        for (int i = 0; i < count; i++) {
-            TextMessage message = session.createTextMessage(content);
-            messageProducer.send(message);
-        }
-
-        session.close();
-    }
-
-    private int clearQueue(Connection connection, String queueName) throws Exception {
-        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
-        org.apache.activemq.command.ActiveMQQueue destination = (org.apache.activemq.command.ActiveMQQueue) session.createQueue(queueName);
-        MessageConsumer messageConsumer = session.createConsumer(destination);
-
-        int received = 0;
-        while (messageConsumer.receive(500) != null) received++;
-
-        session.close();
-
-        return received;
-    }
-    
-    @Test(enabled=false)
-    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
-}


[12/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/BasicTasksFutureTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/BasicTasksFutureTest.java b/core/src/test/java/brooklyn/util/task/BasicTasksFutureTest.java
deleted file mode 100644
index f1c1332..0000000
--- a/core/src/test/java/brooklyn/util/task/BasicTasksFutureTest.java
+++ /dev/null
@@ -1,224 +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 brooklyn.util.task;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.management.Task;
-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 brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Stopwatch;
-
-public class BasicTasksFutureTest {
-
-    private static final Logger log = LoggerFactory.getLogger(BasicTasksFutureTest.class);
-    
-    private BasicExecutionManager em;
-    private BasicExecutionContext ec;
-    private Map<Object,Object> data;
-    private ExecutorService ex;
-    private Semaphore started;
-    private Semaphore waitInTask;
-    private Semaphore cancelledWhileSleeping;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() {
-        em = new BasicExecutionManager("mycontext");
-        ec = new BasicExecutionContext(em);
-        ex = Executors.newCachedThreadPool();
-        data = Collections.synchronizedMap(new LinkedHashMap<Object,Object>());
-        started = new Semaphore(0);
-        waitInTask = new Semaphore(0);
-        cancelledWhileSleeping = new Semaphore(0);
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (em != null) em.shutdownNow();
-        if (ex != null) ex.shutdownNow();
-    }
-
-    @Test
-    public void testBlockAndGetWithTimeoutsAndListenableFuture() throws InterruptedException {
-        Task<String> t = waitForSemaphore(Duration.FIVE_SECONDS, true, "x");
-        
-        Assert.assertFalse(t.blockUntilEnded(Duration.millis(1)));
-        Assert.assertFalse(t.blockUntilEnded(Duration.ZERO));
-        boolean didNotThrow = false;
-        
-        try { t.getUnchecked(Duration.millis(1)); didNotThrow = true; }
-        catch (Exception e) { /* expected */ }
-        Assert.assertFalse(didNotThrow);
-        
-        try { t.getUnchecked(Duration.ZERO); didNotThrow = true; }
-        catch (Exception e) { /* expected */ }
-        Assert.assertFalse(didNotThrow);
-
-        addFutureListener(t, "before");
-        ec.submit(t);
-        
-        Assert.assertFalse(t.blockUntilEnded(Duration.millis(1)));
-        Assert.assertFalse(t.blockUntilEnded(Duration.ZERO));
-        
-        try { t.getUnchecked(Duration.millis(1)); didNotThrow = true; }
-        catch (Exception e) { /* expected */ }
-        Assert.assertFalse(didNotThrow);
-        
-        try { t.getUnchecked(Duration.ZERO); didNotThrow = true; }
-        catch (Exception e) { /* expected */ }
-        Assert.assertFalse(didNotThrow);
-
-        addFutureListener(t, "during");
-            
-        synchronized (data) {
-            // now let it finish
-            waitInTask.release();
-            Assert.assertTrue(t.blockUntilEnded(Duration.TEN_SECONDS));
-
-            Assert.assertEquals(t.getUnchecked(Duration.millis(1)), "x");
-            Assert.assertEquals(t.getUnchecked(Duration.ZERO), "x");
-            
-            Assert.assertNull(data.get("before"));
-            Assert.assertNull(data.get("during"));
-            // can't set the data(above) until we release the lock (in assert call below)
-            assertSoonGetsData("before");
-            assertSoonGetsData("during");
-        }
-
-        // and see that a listener added late also runs
-        synchronized (data) {
-            addFutureListener(t, "after");
-            Assert.assertNull(data.get("after"));
-            assertSoonGetsData("after");
-        }
-    }
-
-    private void addFutureListener(Task<String> t, final String key) {
-        t.addListener(new Runnable() { public void run() {
-            synchronized (data) {
-                log.info("notifying for "+key);
-                data.notifyAll();
-                data.put(key, true);
-            }
-        }}, ex);
-    }
-
-    private void assertSoonGetsData(String key) throws InterruptedException {
-        for (int i=0; i<10; i++) {
-            if (Boolean.TRUE.equals(data.get(key))) {
-                log.info("got data for "+key);
-                return;
-            }
-            data.wait(Duration.ONE_SECOND.toMilliseconds());
-        }
-        Assert.fail("did not get data for '"+key+"' in time");
-    }
-
-    private <T> Task<T> waitForSemaphore(final Duration time, final boolean requireSemaphore, final T result) {
-        return Tasks.<T>builder().body(new Callable<T>() {
-            public T call() { 
-                try {
-                    started.release();
-                    log.info("waiting up to "+time+" to acquire before returning "+result);
-                    if (!waitInTask.tryAcquire(time.toMilliseconds(), TimeUnit.MILLISECONDS)) {
-                        log.info("did not get semaphore");
-                        if (requireSemaphore) Assert.fail("task did not get semaphore");
-                    } else {
-                        log.info("got semaphore");
-                    }
-                } catch (Exception e) {
-                    log.info("cancelled before returning "+result);
-                    cancelledWhileSleeping.release();
-                    throw Exceptions.propagate(e);
-                }
-                log.info("task returning "+result);
-                return result; 
-            }
-        }).build();
-    }
-
-    @Test
-    public void testCancelAfterStartTriggersListenableFuture() throws Exception {
-        doTestCancelTriggersListenableFuture(Duration.millis(50));
-    }
-    @Test
-    public void testCancelImmediateTriggersListenableFuture() throws Exception {
-        // if cancel fires after submit but before it passes to the executor,
-        // that needs handling separately; this doesn't guarantee this code path,
-        // but it happens sometimes (and it should be handled)
-        doTestCancelTriggersListenableFuture(Duration.ZERO);
-    }
-    public void doTestCancelTriggersListenableFuture(Duration delay) throws Exception {
-        Task<String> t = waitForSemaphore(Duration.TEN_SECONDS, true, "x");
-        addFutureListener(t, "before");
-
-        Stopwatch watch = Stopwatch.createStarted();
-        ec.submit(t);
-        
-        addFutureListener(t, "during");
-
-        log.info("test cancelling "+t+" ("+t.getClass()+") after "+delay);
-        // NB: two different code paths (callers to this method) for notifying futures 
-        // depending whether task is started 
-        Time.sleep(delay);
-
-        synchronized (data) {
-            t.cancel(true);
-            
-            assertSoonGetsData("before");
-            assertSoonGetsData("during");
-
-            addFutureListener(t, "after");
-            Assert.assertNull(data.get("after"));
-            assertSoonGetsData("after");
-        }
-        
-        Assert.assertTrue(t.isDone());
-        Assert.assertTrue(t.isCancelled());
-        try {
-            t.get();
-            Assert.fail("should have thrown CancellationException");
-        } catch (CancellationException e) { /* expected */ }
-        
-        Assert.assertTrue(watch.elapsed(TimeUnit.MILLISECONDS) < Duration.FIVE_SECONDS.toMilliseconds(), 
-            Time.makeTimeStringRounded(watch.elapsed(TimeUnit.MILLISECONDS))+" is too long; should have cancelled very quickly");
-
-        if (started.tryAcquire())
-            // if the task is begun, this should get released
-            Assert.assertTrue(cancelledWhileSleeping.tryAcquire(5, TimeUnit.SECONDS));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/CompoundTaskExecutionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/CompoundTaskExecutionTest.java b/core/src/test/java/brooklyn/util/task/CompoundTaskExecutionTest.java
deleted file mode 100644
index 9fe4ba0..0000000
--- a/core/src/test/java/brooklyn/util/task/CompoundTaskExecutionTest.java
+++ /dev/null
@@ -1,252 +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 brooklyn.util.task;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Semaphore;
-
-import org.apache.brooklyn.api.management.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
-import org.testng.collections.Lists;
-
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-
-/**
- * Test the operation of the {@link CompoundTask} class.
- */
-public class CompoundTaskExecutionTest {
-
-    private static final Logger LOG = LoggerFactory.getLogger(CompoundTaskExecutionTest.class);
-
-    BasicExecutionManager em;
-    BasicExecutionContext ec;
-
-    @BeforeClass
-    public void setup() {
-        em = new BasicExecutionManager("mycontext");
-        ec = new BasicExecutionContext(em);
-    }
-
-    @AfterClass
-    public void teardown() {
-        if (em != null) em.shutdownNow();
-        em = null;
-    }
-
-    private BasicTask<String> taskReturning(final String val) {
-        return new BasicTask<String>(new Callable<String>() {
-                @Override public String call() {
-                    return val;
-                }
-            });
-    }
-
-    private BasicTask<String> slowTaskReturning(final String val, final Duration pauseTime) {
-        return new BasicTask<String>(new Callable<String>() {
-                @Override public String call() {
-                    Time.sleep(pauseTime);
-                    return val;
-                }
-            });
-    }
-
-
-    @Test
-    public void runSequenceTask() throws Exception {
-        BasicTask<String> t1 = taskReturning("a");
-        BasicTask<String> t2 = taskReturning("b");
-        BasicTask<String> t3 = taskReturning("c");
-        BasicTask<String> t4 = taskReturning("d");
-        Task<List<String>> tSequence = ec.submit(new SequentialTask<String>(t1, t2, t3, t4));
-        assertEquals(tSequence.get(), ImmutableList.of("a", "b", "c", "d"));
-    }
-
-    @Test
-    public void testSequentialTaskFailsWhenIntermediateTaskThrowsException() throws Exception {
-        BasicTask<String> t1 = taskReturning("a");
-        BasicTask<String> t2 = new BasicTask<String>(new Callable<String>() {
-                @Override public String call() throws Exception {
-                    throw new IllegalArgumentException("forced exception");
-                }
-            });
-        BasicTask<String> t3 = taskReturning("c");
-        SequentialTask<String> task = new SequentialTask<String>(t1, t2, t3);
-        Task<List<String>> tSequence = ec.submit(task);
-
-        try {
-            tSequence.get();
-            fail("t2 should have thrown an exception");
-        } catch (Exception e) {}
-
-        assertTrue(task.isDone());
-        assertTrue(task.isError());
-        assertTrue(t1.isDone());
-        assertFalse(t1.isError());
-        assertTrue(t2.isDone());
-        assertTrue(t2.isError());
-        // t3 not run because of t2 exception
-        assertFalse(t3.isDone());
-        assertFalse(t3.isBegun());
-    }
-
-    @Test
-    public void testParallelTaskFailsWhenIntermediateTaskThrowsException() throws Exception {
-        // differs from test above of SequentialTask in that expect t3 to be executed,
-        // despite t2 failing.
-        // TODO Do we expect tSequence.get() to block for everything to either fail or complete,
-        // and then to throw exception? Currently it does *not* do that so test was previously failing.
-
-        BasicTask<String> t1 = taskReturning("a");
-        BasicTask<String> t2 = new BasicTask<String>(new Callable<String>() {
-                @Override public String call() throws Exception {
-                    throw new IllegalArgumentException("forced exception");
-                }
-            });
-        BasicTask<String> t3 = slowTaskReturning("c", Duration.millis(100));
-        ParallelTask<String> task = new ParallelTask<String>(t1, t2, t3);
-        Task<List<String>> tSequence = ec.submit(task);
-
-        try {
-            tSequence.get();
-            fail("t2 should have thrown an exception");
-        } catch (Exception e) {}
-
-        assertTrue(task.isDone());
-        assertTrue(task.isError());
-        assertTrue(t1.isDone());
-        assertFalse(t1.isError());
-        assertTrue(t2.isDone());
-        assertTrue(t2.isError());
-        assertTrue(t3.isBegun());
-        assertTrue(t3.isDone());
-        assertFalse(t3.isError());
-    }
-
-    @Test
-    public void runParallelTask() throws Exception {
-        BasicTask<String> t1 = taskReturning("a");
-        BasicTask<String> t2 = taskReturning("b");
-        BasicTask<String> t3 = taskReturning("c");
-        BasicTask<String> t4 = taskReturning("d");
-        Task<List<String>> tSequence = ec.submit(new ParallelTask<String>(t4, t2, t1, t3));
-        assertEquals(new HashSet<String>(tSequence.get()), ImmutableSet.of("a", "b", "c", "d"));
-    }
-
-    @Test
-    public void runParallelTaskWithDelay() throws Exception {
-        final Semaphore locker = new Semaphore(0);
-        BasicTask<String> t1 = new BasicTask<String>(new Callable<String>() {
-                @Override public String call() {
-                    try {
-                        locker.acquire();
-                    } catch (InterruptedException e) {
-                        throw Throwables.propagate(e);
-                    }
-                    return "a";
-                }
-            });
-        BasicTask<String> t2 = taskReturning("b");
-        BasicTask<String> t3 = taskReturning("c");
-        BasicTask<String> t4 = taskReturning("d");
-        final Task<List<String>> tSequence = ec.submit(new ParallelTask<String>(t4, t2, t1, t3));
-
-        assertEquals(ImmutableSet.of(t2.get(), t3.get(), t4.get()), ImmutableSet.of("b", "c", "d"));
-        assertFalse(t1.isDone());
-        assertFalse(tSequence.isDone());
-
-        // get blocks until tasks have completed
-        Thread t = new Thread() {
-            @Override public void run() {
-                try {
-                    tSequence.get();
-                } catch (Exception e) {
-                    throw Throwables.propagate(e);
-                }
-                locker.release();
-            }
-        };
-        t.start();
-        Thread.sleep(30);
-        assertTrue(t.isAlive());
-
-        locker.release();
-
-        assertEquals(new HashSet<String>(tSequence.get()), ImmutableSet.of("a", "b", "c", "d"));
-        assertTrue(t1.isDone());
-        assertTrue(tSequence.isDone());
-
-        locker.acquire();
-    }
-
-    @Test
-    public void testComplexOrdering() throws Exception {
-        List<String> data = new CopyOnWriteArrayList<String>();
-        SequentialTask<String> taskA = new SequentialTask<String>(
-                appendAfterDelay(data, "a1"), appendAfterDelay(data, "a2"), appendAfterDelay(data, "a3"), appendAfterDelay(data, "a4"));
-        SequentialTask<String> taskB = new SequentialTask<String>(
-                appendAfterDelay(data, "b1"), appendAfterDelay(data, "b2"), appendAfterDelay(data, "b3"), appendAfterDelay(data, "b4"));
-        Task<List<String>> t = ec.submit(new ParallelTask<String>(taskA, taskB));
-        t.get();
-
-        LOG.debug("Tasks happened in order: {}", data);
-        assertEquals(data.size(), 8);
-        assertEquals(new HashSet<String>(data), ImmutableSet.of("a1", "a2", "a3", "a4", "b1", "b2", "b3", "b4"));
-
-        // a1, ..., a4 should be in order
-        List<String> as = Lists.newArrayList(), bs = Lists.newArrayList();
-        for (String value : data) {
-            ((value.charAt(0) == 'a') ? as : bs).add(value);
-        }
-        assertEquals(as, ImmutableList.of("a1", "a2", "a3", "a4"));
-        assertEquals(bs, ImmutableList.of("b1", "b2", "b3", "b4"));
-    }
-
-    private BasicTask<String> appendAfterDelay(final List<String> list, final String value) {
-        return new BasicTask<String>(new Callable<String>() {
-                @Override public String call() {
-                    try {
-                        Thread.sleep((int) (100 * Math.random()));
-                    } catch (InterruptedException e) {
-                        throw Throwables.propagate(e);
-                    }
-                    LOG.debug("running {}", value);
-                    list.add(value);
-                    return value;
-                }
-            });
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/DynamicSequentialTaskTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/DynamicSequentialTaskTest.java b/core/src/test/java/brooklyn/util/task/DynamicSequentialTaskTest.java
deleted file mode 100644
index a5985fe..0000000
--- a/core/src/test/java/brooklyn/util/task/DynamicSequentialTaskTest.java
+++ /dev/null
@@ -1,365 +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 brooklyn.util.task;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-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 org.apache.brooklyn.api.management.HasTaskChildren;
-import org.apache.brooklyn.api.management.Task;
-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 brooklyn.test.Asserts;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.time.CountdownTimer;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-
-public class DynamicSequentialTaskTest {
-
-    private static final Logger log = LoggerFactory.getLogger(DynamicSequentialTaskTest.class);
-    
-    public static final Duration TIMEOUT = Duration.TEN_SECONDS;
-    public static final Duration TINY_TIME = Duration.millis(20);
-    
-    BasicExecutionManager em;
-    BasicExecutionContext ec;
-    List<String> messages;
-    Semaphore cancellations;
-    Stopwatch stopwatch;
-    Map<String,Semaphore> monitorableJobSemaphoreMap;
-    Map<String,Task<String>> monitorableTasksMap;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() {
-        em = new BasicExecutionManager("mycontext");
-        ec = new BasicExecutionContext(em);
-        cancellations = new Semaphore(0);
-        messages = new ArrayList<String>();
-        monitorableJobSemaphoreMap = MutableMap.of();
-        monitorableTasksMap = MutableMap.of();
-        monitorableTasksMap.clear();
-        stopwatch = Stopwatch.createStarted();
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (em != null) em.shutdownNow();
-    }
-
-    @Test
-    public void testSimple() throws InterruptedException, ExecutionException {
-        Callable<String> mainJob = new Callable<String>() {
-            public String call() {
-                log.info("main job - "+Tasks.current());
-                messages.add("main");
-                DynamicTasks.queue( sayTask("world") );
-                return "bye";
-            }            
-        };
-        DynamicSequentialTask<String> t = new DynamicSequentialTask<String>(mainJob);
-        // this should be added before anything added when the task is invoked
-        t.queue(sayTask("hello"));
-        
-        Assert.assertEquals(messages, Lists.newArrayList());
-        Assert.assertEquals(t.isBegun(), false);
-        Assert.assertEquals(Iterables.size(t.getChildren()), 1);
-        
-        ec.submit(t);
-        Assert.assertEquals(t.isSubmitted(), true);
-        Assert.assertEquals(t.getUnchecked(Duration.ONE_SECOND), "bye");
-        long elapsed = t.getEndTimeUtc() - t.getSubmitTimeUtc();
-        Assert.assertTrue(elapsed < 1000, "elapsed time should have been less than 1s but was "+
-                Time.makeTimeString(elapsed, true));
-        Assert.assertEquals(Iterables.size(t.getChildren()), 2);
-        Assert.assertEquals(messages.size(), 3, "expected 3 entries, but had "+messages);
-        // either main or hello can be first, but world should be last 
-        Assert.assertEquals(messages.get(2), "world");
-    }
-    
-    public Callable<String> sayCallable(final String message, final Duration duration, final String message2) {
-        return new Callable<String>() {
-            public String call() {
-                try {
-                    if (message != null) {
-                        log.info("saying: "+message+ " - "+Tasks.current());
-                        synchronized (messages) {
-                            messages.add(message);
-                            messages.notifyAll();
-                        }
-                    }
-                    if (message2 != null) {
-                        log.info("will say "+message2+" after "+duration);
-                    }
-                    if (duration != null && duration.toMilliseconds() > 0) {
-                        Thread.sleep(duration.toMillisecondsRoundingUp());
-                    }
-                } catch (InterruptedException e) {
-                    cancellations.release();
-                    throw Exceptions.propagate(e);
-                }
-                if (message2 != null) {
-                    log.info("saying: "+message2+ " - "+Tasks.current());
-                    synchronized (messages) {
-                        messages.add(message2);
-                        messages.notifyAll();
-                    }
-                }
-                return message;
-            }            
-        };
-    }
-    
-    public Task<String> sayTask(String message) {
-        return sayTask(message, null, null);
-    }
-    
-    public Task<String> sayTask(String message, Duration duration, String message2) {
-        return Tasks.<String>builder().body(sayCallable(message, duration, message2)).build();
-    }
-    
-    @Test
-    public void testComplex() throws InterruptedException, ExecutionException {
-        Task<List<?>> t = Tasks.sequential(
-                sayTask("1"),
-                sayTask("2"),
-                Tasks.parallel(sayTask("4"), sayTask("3")),
-                sayTask("5")
-            );
-        ec.submit(t);
-        Assert.assertEquals(t.get().size(), 4); 
-        Asserts.assertEqualsIgnoringOrder((List<?>)t.get().get(2), ImmutableSet.of("3", "4"));
-        Assert.assertTrue(messages.equals(Arrays.asList("1", "2", "3", "4", "5")) || messages.equals(Arrays.asList("1", "2", "4", "3", "5")), "messages="+messages);
-    }
-    
-    @Test
-    public void testCancelled() throws InterruptedException, ExecutionException {
-        Task<List<?>> t = Tasks.sequential(
-                sayTask("1"),
-                sayTask("2a", Duration.THIRTY_SECONDS, "2b"),
-                sayTask("3"));
-        ec.submit(t);
-        synchronized (messages) {
-            while (messages.size() <= 1)
-                messages.wait();
-        }
-        Assert.assertEquals(messages, Arrays.asList("1", "2a"));
-        Time.sleep(Duration.millis(50));
-        t.cancel(true);
-        Assert.assertTrue(t.isDone());
-        // 2 should get cancelled, and invoke the cancellation semaphore
-        // 3 should get cancelled and not run at all
-        Assert.assertEquals(messages, Arrays.asList("1", "2a"));
-        
-        // Need to ensure that 2 has been started; race where we might cancel it before its run method
-        // is even begun. Hence doing "2a; pause; 2b" where nothing is interruptable before pause.
-        Assert.assertTrue(cancellations.tryAcquire(10, TimeUnit.SECONDS));
-        
-        Iterator<Task<?>> ci = ((HasTaskChildren)t).getChildren().iterator();
-        Assert.assertEquals(ci.next().get(), "1");
-        Task<?> task2 = ci.next();
-        Assert.assertTrue(task2.isBegun());
-        Assert.assertTrue(task2.isDone());
-        Assert.assertTrue(task2.isCancelled());
-        
-        Task<?> task3 = ci.next();
-        Assert.assertFalse(task3.isBegun());
-        Assert.assertTrue(task2.isDone());
-        Assert.assertTrue(task2.isCancelled());
-        
-        // but we do _not_ get a mutex from task3 as it does not run (is not interrupted)
-        Assert.assertEquals(cancellations.availablePermits(), 0);
-    }
-
-    protected Task<String> monitorableTask(final String id) {
-        return monitorableTask(null, id, null);
-    }
-    protected Task<String> monitorableTask(final Runnable pre, final String id, final Callable<String> post) {
-        Task<String> t = Tasks.<String>builder().body(monitorableJob(pre, id, post)).build();
-        monitorableTasksMap.put(id, t);
-        return t;
-    }
-    protected Callable<String> monitorableJob(final String id) {
-        return monitorableJob(null, id, null);
-    }
-    protected Callable<String> monitorableJob(final Runnable pre, final String id, final Callable<String> post) {
-        monitorableJobSemaphoreMap.put(id, new Semaphore(0));
-        return new Callable<String>() {
-            @Override
-            public String call() throws Exception {
-                if (pre!=null) pre.run();
-                // wait for semaphore
-                if (!monitorableJobSemaphoreMap.get(id).tryAcquire(1, TIMEOUT.toMilliseconds(), TimeUnit.MILLISECONDS))
-                    throw new IllegalStateException("timeout for "+id);
-                synchronized (messages) {
-                    messages.add(id);
-                    messages.notifyAll();
-                }
-                if (post!=null) return post.call();
-                return id;
-            }
-        };
-    }
-    protected void releaseMonitorableJob(final String id) {
-        monitorableJobSemaphoreMap.get(id).release();
-    }
-    protected void waitForMessage(final String id) {
-        CountdownTimer timer = CountdownTimer.newInstanceStarted(TIMEOUT);
-        synchronized (messages) {
-            while (!timer.isExpired()) {
-                if (messages.contains(id)) return;
-                timer.waitOnForExpiryUnchecked(messages);
-            }
-        }
-        Assert.fail("Did not see message "+id);
-    }
-    protected void releaseAndWaitForMonitorableJob(final String id) {
-        releaseMonitorableJob(id);
-        waitForMessage(id);
-    }
-    
-    @Test
-    public void testChildrenRunConcurrentlyWithPrimary() {
-        Task<String> t = Tasks.<String>builder().dynamic(true)
-            .body(monitorableJob("main"))
-            .add(monitorableTask("1")).add(monitorableTask("2")).build();
-        ec.submit(t);
-        releaseAndWaitForMonitorableJob("1");
-        releaseAndWaitForMonitorableJob("main");
-        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
-        releaseMonitorableJob("2");
-        
-        Assert.assertTrue(t.blockUntilEnded(TIMEOUT));
-        Assert.assertEquals(messages, MutableList.of("1", "main", "2"));
-        Assert.assertTrue(stopwatch.elapsed(TimeUnit.MILLISECONDS) < TIMEOUT.toMilliseconds(), "took too long: "+stopwatch);
-        Assert.assertFalse(t.isError());
-    }
-    
-    protected static class FailRunnable implements Runnable {
-        @Override public void run() { throw new RuntimeException("Planned exception for test"); }
-    }
-    protected static class FailCallable implements Callable<String> {
-        @Override public String call() { throw new RuntimeException("Planned exception for test"); }
-    }
-    
-    @Test
-    public void testByDefaultChildrenFailureAbortsSecondaryFailsPrimaryButNotAbortsPrimary() {
-        Task<String> t1 = monitorableTask(null, "1", new FailCallable());
-        Task<String> t = Tasks.<String>builder().dynamic(true)
-            .body(monitorableJob("main"))
-            .add(t1).add(monitorableTask("2")).build();
-        ec.submit(t);
-        releaseAndWaitForMonitorableJob("1");
-        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
-        releaseMonitorableJob("main");
-        
-        Assert.assertTrue(t.blockUntilEnded(TIMEOUT));
-        Assert.assertEquals(messages, MutableList.of("1", "main"));
-        Assert.assertTrue(stopwatch.elapsed(TimeUnit.MILLISECONDS) < TIMEOUT.toMilliseconds(), "took too long: "+stopwatch);
-        Assert.assertTrue(t.isError());
-        Assert.assertTrue(t1.isError());
-    }
-
-    @Test
-    public void testWhenSwallowingChildrenFailureDoesNotAbortSecondaryOrFailPrimary() {
-        Task<String> t1 = monitorableTask(null, "1", new FailCallable());
-        Task<String> t = Tasks.<String>builder().dynamic(true)
-            .body(monitorableJob("main"))
-            .add(t1).add(monitorableTask("2")).swallowChildrenFailures(true).build();
-        ec.submit(t);
-        releaseAndWaitForMonitorableJob("1");
-        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
-        releaseAndWaitForMonitorableJob("2");
-        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
-        releaseMonitorableJob("main");
-        Assert.assertTrue(t.blockUntilEnded(TIMEOUT));
-        Assert.assertEquals(messages, MutableList.of("1", "2", "main"));
-        Assert.assertTrue(stopwatch.elapsed(TimeUnit.MILLISECONDS) < TIMEOUT.toMilliseconds(), "took too long: "+stopwatch);
-        Assert.assertFalse(t.isError());
-        Assert.assertTrue(t1.isError());
-    }
-
-    @Test
-    public void testInessentialChildrenFailureDoesNotAbortSecondaryOrFailPrimary() {
-        Task<String> t1 = monitorableTask(null, "1", new FailCallable());
-        TaskTags.markInessential(t1);
-        Task<String> t = Tasks.<String>builder().dynamic(true)
-            .body(monitorableJob("main"))
-            .add(t1).add(monitorableTask("2")).build();
-        ec.submit(t);
-        releaseAndWaitForMonitorableJob("1");
-        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
-        releaseAndWaitForMonitorableJob("2");
-        Assert.assertFalse(t.blockUntilEnded(TINY_TIME));
-        releaseMonitorableJob("main");
-        Assert.assertTrue(t.blockUntilEnded(TIMEOUT));
-        Assert.assertEquals(messages, MutableList.of("1", "2", "main"));
-        Assert.assertTrue(stopwatch.elapsed(TimeUnit.MILLISECONDS) < TIMEOUT.toMilliseconds(), "took too long: "+stopwatch);
-        Assert.assertFalse(t.isError());
-        Assert.assertTrue(t1.isError());
-    }
-
-    @Test
-    public void testTaskBuilderUsingAddVarargChildren() {
-        Task<String> t = Tasks.<String>builder().dynamic(true)
-            .body(monitorableJob("main"))
-            .add(monitorableTask("1"), monitorableTask("2"))
-            .build();
-        ec.submit(t);
-        releaseAndWaitForMonitorableJob("1");
-        releaseAndWaitForMonitorableJob("2");
-        releaseAndWaitForMonitorableJob("main");
-        
-        Assert.assertEquals(messages, MutableList.of("1", "2", "main"));
-    }
-    
-    @Test
-    public void testTaskBuilderUsingAddAllChildren() {
-        Task<String> t = Tasks.<String>builder().dynamic(true)
-            .body(monitorableJob("main"))
-            .addAll(ImmutableList.of(monitorableTask("1"), monitorableTask("2")))
-            .build();
-        ec.submit(t);
-        releaseAndWaitForMonitorableJob("1");
-        releaseAndWaitForMonitorableJob("2");
-        releaseAndWaitForMonitorableJob("main");
-        
-        Assert.assertEquals(messages, MutableList.of("1", "2", "main"));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/NonBasicTaskExecutionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/NonBasicTaskExecutionTest.java b/core/src/test/java/brooklyn/util/task/NonBasicTaskExecutionTest.java
deleted file mode 100644
index 82e3919..0000000
--- a/core/src/test/java/brooklyn/util/task/NonBasicTaskExecutionTest.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 brooklyn.util.task;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertSame;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.management.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.test.Asserts;
-import brooklyn.util.collections.MutableMap;
-
-/**
- * Test the operation of the {@link BasicTask} class.
- *
- * TODO clarify test purpose
- */
-public class NonBasicTaskExecutionTest {
-    private static final Logger log = LoggerFactory.getLogger(NonBasicTaskExecutionTest.class);
- 
-    private static final int TIMEOUT_MS = 10*1000;
-    
-    public static class ConcreteForwardingTask<T> extends ForwardingTask<T> {
-        private final TaskInternal<T> delegate;
-
-        ConcreteForwardingTask(TaskInternal<T> delegate) {
-            this.delegate = delegate;
-        }
-        
-        @Override
-        protected TaskInternal<T> delegate() {
-            return delegate;
-        }
-    }
-    
-    private BasicExecutionManager em;
-    private Map<Integer,String> data;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        em = new BasicExecutionManager("mycontext");
-        data = Collections.synchronizedMap(new HashMap<Integer,String>());
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (em != null) em.shutdownNow();
-    }
-    
-    @Test
-    public void runSimpleTask() throws Exception {
-        TaskInternal<Object> t = new ConcreteForwardingTask<Object>(new BasicTask<Object>(new Callable<Object>() {
-            @Override public Object call() {
-                return data.put(1, "b");
-            }}));
-        data.put(1, "a");
-        Task<?> t2 = em.submit(MutableMap.of("tag", "A"), t);
-        assertEquals("a", t.get());
-        assertEquals("a", t2.get());
-        assertSame(t, t2, "t="+t+"; t2="+t2);
-        assertEquals("b", data.get(1));
-    }
-    
-    @Test
-    public void runBasicTaskWithWaits() throws Exception {
-        final CountDownLatch signalStarted = new CountDownLatch(1);
-        final CountDownLatch allowCompletion = new CountDownLatch(1);
-        final TaskInternal<Object> t = new ConcreteForwardingTask<Object>(new BasicTask<Object>(new Callable<Object>() {
-            @Override public Object call() throws Exception {
-                Object result = data.put(1, "b");
-                signalStarted.countDown();
-                assertTrue(allowCompletion.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-                return result;
-            }}));
-        data.put(1, "a");
-
-        Task<?> t2 = em.submit(MutableMap.of("tag", "A"), t);
-        assertEquals(t, t2);
-        assertFalse(t.isDone());
-        
-        assertTrue(signalStarted.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        assertEquals("b", data.get(1));
-        assertFalse(t.isDone());
-        
-        log.debug("runBasicTaskWithWaits, BasicTask status: {}", t.getStatusDetail(false));
-        
-        Asserts.succeedsEventually(new Runnable() {
-            @Override public void run() {
-                t.getStatusDetail(false).toLowerCase().contains("waiting");
-            }});
-        // "details="+t.getStatusDetail(false))
-        
-        allowCompletion.countDown();
-        assertEquals("a", t.get());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/ScheduledExecutionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/ScheduledExecutionTest.java b/core/src/test/java/brooklyn/util/task/ScheduledExecutionTest.java
deleted file mode 100644
index 1ae65f2..0000000
--- a/core/src/test/java/brooklyn/util/task/ScheduledExecutionTest.java
+++ /dev/null
@@ -1,287 +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 brooklyn.util.task;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.brooklyn.api.management.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import brooklyn.test.Asserts;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.exceptions.RuntimeInterruptedException;
-import brooklyn.util.javalang.JavaClassNames;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.Lists;
-
-@SuppressWarnings({"unchecked","rawtypes"})
-public class ScheduledExecutionTest {
-
-    public static final Logger log = LoggerFactory.getLogger(ScheduledExecutionTest.class);
-    
-    @Test
-    public void testScheduledTask() throws Exception {
-        int PERIOD = 20;
-        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
-        final AtomicInteger i = new AtomicInteger(0);
-        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", 2*PERIOD, "period", PERIOD, "maxIterations", 5), new Callable<Task<?>>() {
-            public Task<?> call() throws Exception {
-                return new BasicTask<Integer>(new Callable<Integer>() {
-                    public Integer call() {
-                        log.debug("task running: "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
-                        return i.incrementAndGet();
-                    }});
-            }});
-    
-        log.info("submitting {} {}", t, t.getStatusDetail(false));
-        m.submit(t);
-        log.info("submitted {} {}", t, t.getStatusDetail(false));
-        Integer interimResult = (Integer) t.get();
-        log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)});
-        assertTrue(i.get() > 0, "i="+i);
-        t.blockUntilEnded();
-        Integer finalResult = (Integer) t.get();
-        log.info("ended ({}) {} {}", new Object[] {finalResult, t, t.getStatusDetail(false)});
-        assertEquals(finalResult, (Integer)5);
-        assertEquals(i.get(), 5);
-    }
-
-    /** like testScheduledTask but the loop is terminated by the task itself adjusting the period */
-    @Test
-    public void testScheduledTaskSelfEnding() throws Exception {
-        int PERIOD = 20;
-        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
-        final AtomicInteger i = new AtomicInteger(0);
-        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", 2*PERIOD, "period", PERIOD), new Callable<Task<?>>() {
-            public Task<?> call() throws Exception {
-                return new BasicTask<Integer>(new Callable<Integer>() {
-                    public Integer call() {
-                        ScheduledTask submitter = (ScheduledTask) ((BasicTask)Tasks.current()).getSubmittedByTask();
-                        if (i.get() >= 4) submitter.period = null;
-                        log.info("task running ("+i+"): "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
-                        return i.incrementAndGet();
-                    }});
-            }});
-    
-        log.info("submitting {} {}", t, t.getStatusDetail(false));
-        m.submit(t);
-        log.info("submitted {} {}", t, t.getStatusDetail(false));
-        Integer interimResult = (Integer) t.get();
-        log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)});
-        assertTrue(i.get() > 0);
-        t.blockUntilEnded();
-        Integer finalResult = (Integer) t.get();
-        log.info("ended ({}) {} {}", new Object[] {finalResult, t, t.getStatusDetail(false)});
-        assertEquals(finalResult, (Integer)5);
-        assertEquals(i.get(), 5);
-    }
-
-    @Test
-    public void testScheduledTaskCancelEnding() throws Exception {
-        Duration PERIOD = Duration.millis(20);
-        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
-        final AtomicInteger i = new AtomicInteger();
-        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", PERIOD.times(2), "period", PERIOD), new Callable<Task<?>>() {
-            public Task<?> call() throws Exception {
-                return new BasicTask<Integer>(new Callable<Integer>() {
-                    public Integer call() {
-                        log.info("task running ("+i+"): "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
-                        ScheduledTask submitter = (ScheduledTask) ((BasicTask)Tasks.current()).getSubmittedByTask();
-                        i.incrementAndGet();
-                        if (i.get() >= 5) submitter.cancel();
-                        return i.get();
-                    }});
-            }});
-    
-        log.info(JavaClassNames.niceClassAndMethod()+" - submitting {} {}", t, t.getStatusDetail(false));
-        m.submit(t);
-        log.info("submitted {} {}", t, t.getStatusDetail(false));
-        Integer interimResult = (Integer) t.get();
-        log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)});
-        assertTrue(i.get() > 0);
-        t.blockUntilEnded();
-//      int finalResult = t.get()
-        log.info("ended ({}) {} {}", new Object[] {i, t, t.getStatusDetail(false)});
-//      assertEquals(finalResult, 5)
-        assertEquals(i.get(), 5);
-    }
-
-    @Test(groups="Integration")
-    public void testScheduledTaskCancelOuter() throws Exception {
-        final Duration PERIOD = Duration.millis(20);
-        final Duration CYCLE_DELAY = Duration.ONE_SECOND;
-        // this should be enough to start the next cycle, but not so much that the cycle ends;
-        // and enough that when a task is interrupted it terminates within this period
-        final Duration SMALL_FRACTION_OF_CYCLE_DELAY = PERIOD.add(CYCLE_DELAY.multiply(0.1));
-        
-        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
-        final AtomicInteger i = new AtomicInteger();
-        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", PERIOD.times(2), "period", PERIOD), new Callable<Task<?>>() {
-            public Task<?> call() throws Exception {
-                return new BasicTask<Integer>(new Callable<Integer>() {
-                    public Integer call() {
-                        log.info("task running ("+i+"): "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
-                        Time.sleep(CYCLE_DELAY);
-                        i.incrementAndGet();
-                        return i.get();
-                    }});
-            }});
-    
-        log.info(JavaClassNames.niceClassAndMethod()+" - submitting {} {}", t, t.getStatusDetail(false));
-        m.submit(t);
-        log.info("submitted {} {}", t, t.getStatusDetail(false));
-        Integer interimResult = (Integer) t.get();
-        log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)});
-        assertEquals(i.get(), 1);
-        
-        Time.sleep(SMALL_FRACTION_OF_CYCLE_DELAY);
-        assertEquals(t.get(), 2);
-        
-        Time.sleep(SMALL_FRACTION_OF_CYCLE_DELAY);
-        Stopwatch timer = Stopwatch.createUnstarted();
-        t.cancel(true);
-        t.blockUntilEnded();
-//      int finalResult = t.get()
-        log.info("blocked until ended ({}) {} {}, in {}", new Object[] {i, t, t.getStatusDetail(false), Duration.of(timer)});
-        try {
-            t.get();
-            Assert.fail("Should have failed getting result of cancelled "+t);
-        } catch (Exception e) {
-            /* expected */
-        }
-        assertEquals(i.get(), 2);
-        log.info("ended ({}) {} {}, in {}", new Object[] {i, t, t.getStatusDetail(false), Duration.of(timer)});
-        Assert.assertTrue(Duration.of(timer).isShorterThan(SMALL_FRACTION_OF_CYCLE_DELAY));
-    }
-
-    @Test(groups="Integration")
-    public void testScheduledTaskCancelInterrupts() throws Exception {
-        final Duration PERIOD = Duration.millis(20);
-        final Duration CYCLE_DELAY = Duration.ONE_SECOND;
-        // this should be enough to start the next cycle, but not so much that the cycle ends;
-        // and enough that when a task is interrupted it terminates within this period
-        final Duration SMALL_FRACTION_OF_CYCLE_DELAY = PERIOD.add(CYCLE_DELAY.multiply(0.1));
-        
-        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
-        final Semaphore interruptedSemaphore = new Semaphore(0);
-        final AtomicInteger i = new AtomicInteger();
-        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", PERIOD.times(2), "period", PERIOD), new Callable<Task<?>>() {
-            public Task<?> call() throws Exception {
-                return new BasicTask<Integer>(new Callable<Integer>() {
-                    public Integer call() {
-                        try {
-                            log.info("task running ("+i+"): "+Tasks.current()+" "+Tasks.current().getStatusDetail(false));
-                            Time.sleep(CYCLE_DELAY);
-                            i.incrementAndGet();
-                            return i.get();
-                        } catch (RuntimeInterruptedException e) {
-                            interruptedSemaphore.release();
-                            throw Exceptions.propagate(e);
-                        }
-                    }});
-            }});
-    
-        log.info(JavaClassNames.niceClassAndMethod()+" - submitting {} {}", t, t.getStatusDetail(false));
-        m.submit(t);
-        log.info("submitted {} {}", t, t.getStatusDetail(false));
-        Integer interimResult = (Integer) t.get();
-        log.info("done one ({}) {} {}", new Object[] {interimResult, t, t.getStatusDetail(false)});
-        assertEquals(i.get(), 1);
-        
-        Time.sleep(SMALL_FRACTION_OF_CYCLE_DELAY);
-        assertEquals(t.get(), 2);
-        
-        Time.sleep(SMALL_FRACTION_OF_CYCLE_DELAY);
-        Stopwatch timer = Stopwatch.createUnstarted();
-        t.cancel(true);
-        t.blockUntilEnded();
-//      int finalResult = t.get()
-        log.info("blocked until ended ({}) {} {}, in {}", new Object[] {i, t, t.getStatusDetail(false), Duration.of(timer)});
-        try {
-            t.get();
-            Assert.fail("Should have failed getting result of cancelled "+t);
-        } catch (Exception e) {
-            /* expected */
-        }
-        assertEquals(i.get(), 2);
-        Assert.assertTrue(interruptedSemaphore.tryAcquire(1, SMALL_FRACTION_OF_CYCLE_DELAY.toMilliseconds(), TimeUnit.MILLISECONDS), "child thread was not interrupted");
-        log.info("ended ({}) {} {}, in {}", new Object[] {i, t, t.getStatusDetail(false), Duration.of(timer)});
-        Assert.assertTrue(Duration.of(timer).isShorterThan(SMALL_FRACTION_OF_CYCLE_DELAY));
-    }
-
-    @Test(groups="Integration")
-    public void testScheduledTaskTakesLongerThanPeriod() throws Exception {
-        final int PERIOD = 1;
-        final int SLEEP_TIME = 100;
-        final int EARLY_RETURN_GRACE = 10;
-        BasicExecutionManager m = new BasicExecutionManager("mycontextid");
-        final List<Long> execTimes = new CopyOnWriteArrayList<Long>();
-        
-        ScheduledTask t = new ScheduledTask(MutableMap.of("delay", PERIOD, "period", PERIOD), new Callable<Task<?>>() {
-            public Task<?> call() throws Exception {
-                return new BasicTask<Void>(new Runnable() {
-                    public void run() {
-                        execTimes.add(System.currentTimeMillis());
-                        try {
-                            Thread.sleep(100);
-                        } catch (InterruptedException e) {
-                            throw Exceptions.propagate(e);
-                        }
-                    }});
-            }});
-    
-        m.submit(t);
-        
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                assertTrue(execTimes.size() > 3, "size="+execTimes.size());
-            }});
-        
-        List<Long> timeDiffs = Lists.newArrayList();
-        long prevExecTime = -1;
-        for (Long execTime : execTimes) {
-            if (prevExecTime == -1) {
-                prevExecTime = execTime;
-            } else {
-                timeDiffs.add(execTime - prevExecTime);
-                prevExecTime = execTime;
-            }
-        }
-        
-        for (Long timeDiff : timeDiffs) {
-            if (timeDiff < (SLEEP_TIME - EARLY_RETURN_GRACE)) fail("timeDiffs="+timeDiffs+"; execTimes="+execTimes);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/SingleThreadedSchedulerTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/SingleThreadedSchedulerTest.java b/core/src/test/java/brooklyn/util/task/SingleThreadedSchedulerTest.java
deleted file mode 100644
index 265956d..0000000
--- a/core/src/test/java/brooklyn/util/task/SingleThreadedSchedulerTest.java
+++ /dev/null
@@ -1,192 +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 brooklyn.util.task;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.fail;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.test.Asserts;
-import brooklyn.util.collections.MutableMap;
-
-import com.google.common.util.concurrent.Callables;
-
-public class SingleThreadedSchedulerTest {
-
-    private static final Logger log = LoggerFactory.getLogger(SingleThreadedSchedulerTest.class);
-    
-    private BasicExecutionManager em;
-    
-    @BeforeMethod
-    public void setUp() {
-        em = new BasicExecutionManager("mycontextid");
-        em.setTaskSchedulerForTag("category1", SingleThreadedScheduler.class);
-    }
-    
-    @AfterMethod
-    public void tearDown() {
-        if (em != null) em.shutdownNow();
-    }
-    
-    @Test
-    public void testExecutesInOrder() throws Exception {
-        final int NUM_TIMES = 1000;
-        final List<Integer> result = new CopyOnWriteArrayList<Integer>();
-        for (int i = 0; i < NUM_TIMES; i++) {
-            final int counter = i;
-            em.submit(MutableMap.of("tag", "category1"), new Runnable() {
-                public void run() {
-                    result.add(counter);
-                }});
-        }
-        
-        Asserts.succeedsEventually(new Runnable() {
-            @Override public void run() {
-                assertEquals(result.size(), NUM_TIMES);
-            }});
-
-        for (int i = 0; i < NUM_TIMES; i++) {
-            assertEquals(result.get(i), (Integer)i);
-        }        
-    }
-    
-    @Test
-    public void testLargeQueueDoesNotConsumeTooManyThreads() throws Exception {
-        final int NUM_TIMES = 3000;
-        final CountDownLatch latch = new CountDownLatch(1);
-        BasicTask<Void> blockingTask = new BasicTask<Void>(newLatchAwaiter(latch));
-        em.submit(MutableMap.of("tag", "category1"), blockingTask);
-        
-        final AtomicInteger counter = new AtomicInteger(0);
-        for (int i = 0; i < NUM_TIMES; i++) {
-            BasicTask<Void> t = new BasicTask<Void>(new Runnable() {
-                public void run() {
-                    counter.incrementAndGet();
-                }});
-            em.submit(MutableMap.of("tag", "category1"), t);
-            if (i % 500 == 0) log.info("Submitted "+i+" jobs...");
-        }
-
-        Thread.sleep(100); // give it more of a chance to create the threads before we let them execute
-        latch.countDown();
-
-        Asserts.succeedsEventually(new Runnable() {
-            @Override public void run() {
-                assertEquals(counter.get(), NUM_TIMES);
-            }});
-    }
-    
-    @Test
-    public void testGetResultOfQueuedTaskBeforeItExecutes() throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
-        em.submit(MutableMap.of("tag", "category1"), newLatchAwaiter(latch));
-        
-        BasicTask<Integer> t = new BasicTask<Integer>(Callables.returning(123));
-        Future<Integer> future = em.submit(MutableMap.of("tag", "category1"), t);
-
-        Thread thread = new Thread(new Runnable() {
-            public void run() {
-                try {
-                    Thread.sleep(10);
-                } catch (InterruptedException e) {
-                    Thread.currentThread().interrupt();
-                }
-                latch.countDown();
-            }});
-        thread.start();
-        assertEquals(future.get(), (Integer)123);
-    }
-    
-    @Test
-    public void testGetResultOfQueuedTaskBeforeItExecutesWithTimeout() throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
-        em.submit(MutableMap.of("tag", "category1"), newLatchAwaiter(latch));
-        
-        BasicTask<Integer> t = new BasicTask<Integer>(Callables.returning(123));
-        Future<Integer> future = em.submit(MutableMap.of("tag", "category1"), t);
-
-        try {
-            assertEquals(future.get(10, TimeUnit.MILLISECONDS), (Integer)123);
-            fail();
-        } catch (TimeoutException e) {
-            // success
-        }
-    }
-    
-    @Test
-    public void testCancelQueuedTaskBeforeItExecutes() throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
-        em.submit(MutableMap.of("tag", "category1"), newLatchAwaiter(latch));
-        
-        final AtomicBoolean executed = new AtomicBoolean();
-        BasicTask<?> t = new BasicTask<Void>(new Runnable() {
-            public void run() {
-                executed.set(true);
-            }});
-        Future<?> future = em.submit(MutableMap.of("tag", "category1"), t);
-
-        future.cancel(true);
-        latch.countDown();
-        Thread.sleep(10);
-        try {
-            future.get();
-        } catch (CancellationException e) {
-            // success
-        }
-        assertFalse(executed.get());
-    }
-    
-    @Test
-    public void testGetResultOfQueuedTaskAfterItExecutes() throws Exception {
-        final CountDownLatch latch = new CountDownLatch(1);
-        em.submit(MutableMap.of("tag", "category1"), newLatchAwaiter(latch));
-        
-        BasicTask<Integer> t = new BasicTask<Integer>(Callables.returning(123));
-        Future<Integer> future = em.submit(MutableMap.of("tag", "category1"), t);
-
-        latch.countDown();
-        assertEquals(future.get(), (Integer)123);
-    }
-    
-    private Callable<Void> newLatchAwaiter(final CountDownLatch latch) {
-        return new Callable<Void>() {
-            public Void call() throws Exception {
-                latch.await();
-                return null;
-            }
-        };
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/TaskFinalizationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/TaskFinalizationTest.java b/core/src/test/java/brooklyn/util/task/TaskFinalizationTest.java
deleted file mode 100644
index 51750ca..0000000
--- a/core/src/test/java/brooklyn/util/task/TaskFinalizationTest.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 brooklyn.util.task;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.management.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Stopwatch;
-
-public class TaskFinalizationTest {
-
-    private static final Logger log = LoggerFactory.getLogger(TaskFinalizationTest.class);
-    
-    // integration because it can take a while (and finalizers aren't even guaranteed)
-    @Test(groups="Integration")
-    public void testFinalizerInvoked() throws InterruptedException {
-        BasicTask<?> t = new BasicTask<Void>(new Runnable() { public void run() { /* no op */ }});
-        final Semaphore x = new Semaphore(0);
-        t.setFinalizer(new BasicTask.TaskFinalizer() {
-            public void onTaskFinalization(Task<?> t) {
-                synchronized (x) { 
-                    x.release();
-                }
-            }
-        });
-        t = null;
-        Stopwatch watch = Stopwatch.createStarted();
-        for (int i=0; i<30; i++) {
-            System.gc(); System.gc();
-            if (x.tryAcquire(1, TimeUnit.SECONDS)) {
-                log.info("finalizer ran after "+Time.makeTimeStringRounded(watch));
-                return;
-            }
-        }
-        Assert.fail("finalizer did not run in time");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/TasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/TasksTest.java b/core/src/test/java/brooklyn/util/task/TasksTest.java
deleted file mode 100644
index 58ce24f..0000000
--- a/core/src/test/java/brooklyn/util/task/TasksTest.java
+++ /dev/null
@@ -1,181 +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 brooklyn.util.task;
-
-import static brooklyn.event.basic.DependentConfiguration.attributeWhenReady;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.management.ExecutionContext;
-import org.apache.brooklyn.api.management.Task;
-import org.apache.brooklyn.test.entity.TestApplication;
-import org.apache.brooklyn.test.entity.TestEntity;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.BrooklynAppUnitTestSupport;
-import brooklyn.entity.basic.EntityFunctions;
-import brooklyn.util.guava.Functionals;
-import brooklyn.util.repeat.Repeater;
-import brooklyn.util.time.Duration;
-
-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.util.concurrent.Callables;
-
-
-public class TasksTest extends BrooklynAppUnitTestSupport {
-
-    private ExecutionContext executionContext;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        executionContext = app.getExecutionContext();
-    }
-    
-    @Test
-    public void testResolveNull() throws Exception {
-        assertResolvesValue(null, String.class, null);
-    }
-    
-    @Test
-    public void testResolveValueCastsToType() throws Exception {
-        assertResolvesValue(123, String.class, "123");
-    }
-    
-    @Test
-    public void testResolvesAttributeWhenReady() throws Exception {
-        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
-        assertResolvesValue(attributeWhenReady(app, TestApplication.MY_ATTRIBUTE), String.class, "myval");
-    }
-    
-    @Test
-    public void testResolvesMapWithAttributeWhenReady() throws Exception {
-        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
-        Map<?,?> orig = ImmutableMap.of("mykey", attributeWhenReady(app, TestApplication.MY_ATTRIBUTE));
-        Map<?,?> expected = ImmutableMap.of("mykey", "myval");
-        assertResolvesValue(orig, String.class, expected);
-    }
-    
-    @Test
-    public void testResolvesSetWithAttributeWhenReady() throws Exception {
-        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
-        Set<?> orig = ImmutableSet.of(attributeWhenReady(app, TestApplication.MY_ATTRIBUTE));
-        Set<?> expected = ImmutableSet.of("myval");
-        assertResolvesValue(orig, String.class, expected);
-    }
-    
-    @Test
-    public void testResolvesMapOfMapsWithAttributeWhenReady() throws Exception {
-        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
-        Map<?,?> orig = ImmutableMap.of("mykey", ImmutableMap.of("mysubkey", attributeWhenReady(app, TestApplication.MY_ATTRIBUTE)));
-        Map<?,?> expected = ImmutableMap.of("mykey", ImmutableMap.of("mysubkey", "myval"));
-        assertResolvesValue(orig, String.class, expected);
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testResolvesIterableOfMapsWithAttributeWhenReady() throws Exception {
-        app.setAttribute(TestApplication.MY_ATTRIBUTE, "myval");
-        // using Iterables.concat so that orig is of type FluentIterable rather than List etc
-        Iterable<?> orig = Iterables.concat(ImmutableList.of(ImmutableMap.of("mykey", attributeWhenReady(app, TestApplication.MY_ATTRIBUTE))));
-        Iterable<Map<?,?>> expected = ImmutableList.<Map<?,?>>of(ImmutableMap.of("mykey", "myval"));
-        assertResolvesValue(orig, String.class, expected);
-    }
-    
-    private void assertResolvesValue(Object actual, Class<?> type, Object expected) throws Exception {
-        Object result = Tasks.resolveValue(actual, type, executionContext);
-        assertEquals(result, expected);
-    }
-    
-    @Test
-    public void testErrorsResolvingPropagatesOrSwallowedAllCorrectly() throws Exception {
-        app.setConfig(TestEntity.CONF_OBJECT, ValueResolverTest.newThrowTask(Duration.ZERO));
-        Task<Object> t = Tasks.builder().body(Functionals.callable(EntityFunctions.config(TestEntity.CONF_OBJECT), app)).build();
-        ValueResolver<Object> v = Tasks.resolving(t).as(Object.class).context(app.getExecutionContext());
-        
-        ValueResolverTest.assertThrowsOnMaybe(v);
-        ValueResolverTest.assertThrowsOnGet(v);
-        
-        v.swallowExceptions();
-        ValueResolverTest.assertMaybeIsAbsent(v);
-        ValueResolverTest.assertThrowsOnGet(v);
-        
-        v.defaultValue("foo");
-        ValueResolverTest.assertMaybeIsAbsent(v);
-        assertEquals(v.clone().get(), "foo");
-        assertResolvesValue(v, Object.class, "foo");
-    }
-
-    @Test
-    public void testRepeater() throws Exception {
-        Task<?> t;
-        
-        t = Tasks.requiring(Repeater.create().until(Callables.returning(true)).every(Duration.millis(1))).build();
-        app.getExecutionContext().submit(t);
-        t.get(Duration.TEN_SECONDS);
-        
-        t = Tasks.testing(Repeater.create().until(Callables.returning(true)).every(Duration.millis(1))).build();
-        app.getExecutionContext().submit(t);
-        Assert.assertEquals(t.get(Duration.TEN_SECONDS), true);
-        
-        t = Tasks.requiring(Repeater.create().until(Callables.returning(false)).limitIterationsTo(2).every(Duration.millis(1))).build();
-        app.getExecutionContext().submit(t);
-        try {
-            t.get(Duration.TEN_SECONDS);
-            Assert.fail("Should have failed");
-        } catch (Exception e) {
-            // expected
-        }
-
-        t = Tasks.testing(Repeater.create().until(Callables.returning(false)).limitIterationsTo(2).every(Duration.millis(1))).build();
-        app.getExecutionContext().submit(t);
-        Assert.assertEquals(t.get(Duration.TEN_SECONDS), false);
-    }
-
-    @Test
-    public void testRepeaterDescription() throws Exception{
-        final String description = "task description";
-        Repeater repeater = Repeater.create(description)
-            .repeat(Callables.returning(null))
-            .every(Duration.ONE_MILLISECOND)
-            .limitIterationsTo(1)
-            .until(new Callable<Boolean>() {
-                @Override
-                public Boolean call() {
-                    TaskInternal<?> current = (TaskInternal<?>)Tasks.current();
-                    assertEquals(current.getBlockingDetails(), description);
-                    return true;
-                }
-            });
-        Task<Boolean> t = Tasks.testing(repeater).build();
-        app.getExecutionContext().submit(t);
-        assertTrue(t.get(Duration.TEN_SECONDS));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/ValueResolverTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/ValueResolverTest.java b/core/src/test/java/brooklyn/util/task/ValueResolverTest.java
deleted file mode 100644
index d50ff54..0000000
--- a/core/src/test/java/brooklyn/util/task/ValueResolverTest.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 brooklyn.util.task;
-
-import java.util.concurrent.Callable;
-
-import org.apache.brooklyn.api.management.ExecutionContext;
-import org.apache.brooklyn.api.management.Task;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.BrooklynAppUnitTestSupport;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-/**
- * see also {@link TasksTest} for more tests
- */
-@Test
-public class ValueResolverTest extends BrooklynAppUnitTestSupport {
-
-    private ExecutionContext executionContext;
-
-    @BeforeMethod(alwaysRun=true)
-    @Override
-    public void setUp() throws Exception {
-        super.setUp();
-        executionContext = app.getExecutionContext();
-    }
-    
-    public static final Task<String> newSleepTask(final Duration timeout, final String result) {
-        return Tasks.<String>builder().body(new Callable<String>() { 
-            public String call() { 
-                Time.sleep(timeout); 
-                return result; 
-            }}
-        ).build();
-    }
-    
-    public static final Task<String> newThrowTask(final Duration timeout) {
-        return Tasks.<String>builder().body(new Callable<String>() { 
-            public String call() {
-                Time.sleep(timeout); 
-                throw new IllegalStateException("intended, during tests");
-            }}
-        ).build();
-    }
-    
-    public void testTimeoutZero() {
-        Maybe<String> result = Tasks.resolving(newSleepTask(Duration.TEN_SECONDS, "foo")).as(String.class).context(executionContext).timeout(Duration.ZERO).getMaybe();
-        Assert.assertFalse(result.isPresent());
-    }
-    
-    public void testTimeoutBig() {
-        Maybe<String> result = Tasks.resolving(newSleepTask(Duration.ZERO, "foo")).as(String.class).context(executionContext).timeout(Duration.TEN_SECONDS).getMaybe();
-        Assert.assertEquals(result.get(), "foo");
-    }
-
-    public void testNoExecutionContextOnCompleted() {
-        Task<String> t = newSleepTask(Duration.ZERO, "foo");
-        executionContext.submit(t).getUnchecked();
-        Maybe<String> result = Tasks.resolving(t).as(String.class).timeout(Duration.ZERO).getMaybe();
-        Assert.assertEquals(result.get(), "foo");
-    }
-
-    public static Throwable assertThrowsOnMaybe(ValueResolver<?> result) {
-        try {
-            result = result.clone();
-            result.getMaybe();
-            Assert.fail("should have thrown");
-            return null;
-        } catch (Exception e) { return e; }
-    }
-    public static Throwable assertThrowsOnGet(ValueResolver<?> result) {
-        result = result.clone();
-        try {
-            result.get();
-            Assert.fail("should have thrown");
-            return null;
-        } catch (Exception e) { return e; }
-    }
-    public static <T> Maybe<T> assertMaybeIsAbsent(ValueResolver<T> result) {
-        result = result.clone();
-        Maybe<T> maybe = result.getMaybe();
-        Assert.assertFalse(maybe.isPresent());
-        return maybe;
-    }
-    
-    public void testSwallowError() {
-        ValueResolver<String> result = Tasks.resolving(newThrowTask(Duration.ZERO)).as(String.class).context(executionContext).swallowExceptions();
-        assertMaybeIsAbsent(result);
-        assertThrowsOnGet(result);
-    }
-
-
-    public void testDontSwallowError() {
-        ValueResolver<String> result = Tasks.resolving(newThrowTask(Duration.ZERO)).as(String.class).context(executionContext);
-        assertThrowsOnMaybe(result);
-        assertThrowsOnGet(result);
-    }
-
-    public void testDefaultWhenSwallowError() {
-        ValueResolver<String> result = Tasks.resolving(newThrowTask(Duration.ZERO)).as(String.class).context(executionContext).swallowExceptions().defaultValue("foo");
-        assertMaybeIsAbsent(result);
-        Assert.assertEquals(result.get(), "foo");
-    }
-
-    public void testDefaultBeforeDelayAndError() {
-        ValueResolver<String> result = Tasks.resolving(newThrowTask(Duration.TEN_SECONDS)).as(String.class).context(executionContext).timeout(Duration.ZERO).defaultValue("foo");
-        assertMaybeIsAbsent(result);
-        Assert.assertEquals(result.get(), "foo");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/ssh/SshTasksTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/ssh/SshTasksTest.java b/core/src/test/java/brooklyn/util/task/ssh/SshTasksTest.java
deleted file mode 100644
index 578164f..0000000
--- a/core/src/test/java/brooklyn/util/task/ssh/SshTasksTest.java
+++ /dev/null
@@ -1,207 +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 brooklyn.util.task.ssh;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.brooklyn.api.location.LocationSpec;
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.apache.brooklyn.core.management.internal.LocalManagementContext;
-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 brooklyn.entity.basic.BrooklynConfigKeys;
-import brooklyn.entity.basic.Entities;
-
-import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import brooklyn.util.net.Urls;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommandsIntegrationTest;
-import brooklyn.util.task.system.ProcessTaskFactory;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-
-/**
- * Some tests for {@link SshTasks}. Note more tests in {@link BashCommandsIntegrationTest}, 
- * {@link SshEffectorTasksTest}, and {@link SoftwareEffectorTest}.
- */
-public class SshTasksTest {
-
-    private static final Logger log = LoggerFactory.getLogger(SshTasksTest.class);
-    
-    ManagementContext mgmt;
-    SshMachineLocation host;
-    File tempDir;
-    
-    boolean failureExpected;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setup() throws Exception {
-        mgmt = new LocalManagementContext();
-        
-        LocalhostMachineProvisioningLocation lhc = mgmt.getLocationManager().createLocation(LocationSpec.create(LocalhostMachineProvisioningLocation.class));
-        host = lhc.obtain();
-        clearExpectedFailure();
-        tempDir = Os.newTempDir(getClass());
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (mgmt != null) Entities.destroyAll(mgmt);
-        mgmt = null;
-        tempDir = Os.deleteRecursively(tempDir).asNullOrThrowing();
-        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;
-    }
-
-
-    protected <T> ProcessTaskWrapper<T> submit(final ProcessTaskFactory<T> tf) {
-        tf.machine(host);
-        ProcessTaskWrapper<T> t = tf.newTask();
-        mgmt.getExecutionManager().submit(t);
-        return t;
-    }
-
-    protected SshPutTaskWrapper submit(final SshPutTaskFactory tf) {
-        SshPutTaskWrapper t = tf.newTask();
-        mgmt.getExecutionManager().submit(t);
-        return t;
-    }
-
-    @Test(groups="Integration")
-    public void testSshEchoHello() {
-        ProcessTaskWrapper<Integer> t = submit(SshTasks.newSshExecTaskFactory(host, "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 testCopyTo() throws IOException {
-        String fn = Urls.mergePaths(tempDir.getPath(), "f1");
-        SshPutTaskWrapper t = submit(SshTasks.newSshPutTaskFactory(host, 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 testCopyToFailBadSubdir() throws IOException {
-        String fn = Urls.mergePaths(tempDir.getPath(), "non-existent-subdir/file");
-        SshPutTaskWrapper t = submit(SshTasks.newSshPutTaskFactory(host, fn).contents("hello world"));
-        //this doesn't fail
-        t.block();        
-        Assert.assertTrue(t.isDone());
-        setExpectingFailure();
-        try {
-            // but this does
-            t.get();
-        } catch (Exception e) {
-            log.info("The error if file cannot be written is: "+e);
-            clearExpectedFailure();
-        }
-        checkExpectedFailure();
-        // and the results indicate failure
-        Assert.assertFalse(t.isSuccessful());
-        Assert.assertNotNull(t.getException());
-        Assert.assertNotEquals(t.getExitCode(), (Integer)0);
-    }
-
-    @Test(groups="Integration")
-    public void testCopyToFailBadSubdirAllow() throws IOException {
-        String fn = Urls.mergePaths(tempDir.getPath(), "non-existent-subdir/file");
-        SshPutTaskWrapper t = submit(SshTasks.newSshPutTaskFactory(host, fn).contents("hello world").allowFailure());
-        //this doesn't fail
-        t.block();        
-        Assert.assertTrue(t.isDone());
-        // and this doesn't fail either
-        Assert.assertEquals(t.get(), null);
-        // but it's not successful
-        Assert.assertNotNull(t.getException());
-        Assert.assertFalse(t.isSuccessful());
-        // exit code probably null, but won't be zero
-        Assert.assertNotEquals(t.getExitCode(), (Integer)0);
-    }
-
-    @Test(groups="Integration")
-    public void testCopyToFailBadSubdirCreate() throws IOException {
-        String fn = Urls.mergePaths(tempDir.getPath(), "non-existent-subdir-to-create/file");
-        SshPutTaskWrapper t = submit(SshTasks.newSshPutTaskFactory(host, fn).contents("hello world").createDirectory());
-        t.block();
-        // directory should be created, and file readable now
-        Assert.assertEquals(FileUtils.readFileToString(new File(fn)), "hello world");
-        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");
-        
-        SshFetchTaskFactory tf = SshTasks.newSshFetchTaskFactory(host, fn);
-        SshFetchTaskWrapper t = tf.newTask();
-        mgmt.getExecutionManager().submit(t);
-
-        t.block();
-        Assert.assertTrue(t.isDone());
-        Assert.assertEquals(t.get(), "hello fetched world");
-        Assert.assertEquals(t.getBytes(), "hello fetched world".getBytes());
-    }
-
-    @Test(groups="Integration")
-    public void testSshWithHeaderProperty() {
-        host.setConfig(BrooklynConfigKeys.SSH_CONFIG_SCRIPT_HEADER, "#!/bin/bash -e\necho foo\n");
-        ProcessTaskWrapper<Integer> t = submit(SshTasks.newSshExecTaskFactory(host, "echo bar"));
-        Assert.assertTrue(t.block().getStdout().trim().matches("foo\\s+bar"), "mismatched output was: "+t.getStdout());
-    }
-
-    @Test(groups="Integration")
-    public void testSshIgnoringHeaderProperty() {
-        host.setConfig(BrooklynConfigKeys.SSH_CONFIG_SCRIPT_HEADER, "#!/bin/bash -e\necho foo\n");
-        ProcessTaskWrapper<Integer> t = submit(SshTasks.newSshExecTaskFactory(host, false, "echo bar"));
-        Assert.assertTrue(t.block().getStdout().trim().matches("bar"), "mismatched output was: "+t.getStdout());
-    }
-
-}



[50/64] incubator-brooklyn git commit: brooklyn-software-messaging: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerImpl.java
deleted file mode 100644
index 7b810ae..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerImpl.java
+++ /dev/null
@@ -1,170 +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 brooklyn.entity.messaging.kafka;
-
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import javax.management.ObjectName;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.messaging.MessageBroker;
-import brooklyn.entity.zookeeper.ZooKeeperNode;
-import brooklyn.event.feed.jmx.JmxAttributePollConfig;
-import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.event.feed.jmx.JmxHelper;
-
-import com.google.common.base.Functions;
-import com.google.common.base.Objects.ToStringHelper;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Kafka broker instance.
- */
-public class KafkaBrokerImpl extends SoftwareProcessImpl implements MessageBroker, KafkaBroker {
-
-    @SuppressWarnings("unused")
-    private static final Logger log = LoggerFactory.getLogger(KafkaBrokerImpl.class);
-    private static final ObjectName SOCKET_SERVER_STATS_MBEAN = JmxHelper.createObjectName("kafka:type=kafka.SocketServerStats");
-
-    private volatile JmxFeed jmxFeed;
-
-    public KafkaBrokerImpl() {
-        super();
-    }
-
-    @Override
-    public void init() {
-        super.init();
-        setAttribute(BROKER_ID, Math.abs(hashCode())); // Must be positive for partitioning to work
-    }
-
-    @Override
-    public Integer getKafkaPort() { return getAttribute(KAFKA_PORT); }
-
-    @Override
-    public Integer getBrokerId() { return getAttribute(BROKER_ID); }
-
-    @Override
-    public ZooKeeperNode getZookeeper() { return getConfig(ZOOKEEPER); }
-
-    @Override
-    public Class<?> getDriverInterface() {
-        return KafkaBrokerDriver.class;
-    }
-
-    @Override
-    public void waitForServiceUp(long duration, TimeUnit units) {
-        super.waitForServiceUp(duration, units);
-
-        if (((KafkaBrokerDriver)getDriver()).isJmxEnabled()) {
-            // Wait for the MBean to exist
-            JmxHelper helper = new JmxHelper(this);
-            try {
-                helper.assertMBeanExistsEventually(SOCKET_SERVER_STATS_MBEAN, units.toMillis(duration));
-            } finally {
-                helper.terminate();
-            }
-        }
-    }
-
-    @Override
-    protected void connectSensors() {
-        connectServiceUpIsRunning();
-        boolean retrieveUsageMetrics = getConfig(RETRIEVE_USAGE_METRICS);
-        
-        if (((KafkaBrokerDriver)getDriver()).isJmxEnabled()) {
-            jmxFeed = JmxFeed.builder()
-                .entity(this)
-                .period(500, TimeUnit.MILLISECONDS)
-                .pollAttribute(new JmxAttributePollConfig<Long>(FETCH_REQUEST_COUNT)
-                        .objectName(SOCKET_SERVER_STATS_MBEAN)
-                        .attributeName("NumFetchRequests")
-                        .onException(Functions.constant(-1l))
-                        .enabled(retrieveUsageMetrics))
-                .pollAttribute(new JmxAttributePollConfig<Long>(TOTAL_FETCH_TIME)
-                        .objectName(SOCKET_SERVER_STATS_MBEAN)
-                        .attributeName("TotalFetchRequestMs")
-                        .onException(Functions.constant(-1l))
-                        .enabled(retrieveUsageMetrics))
-                .pollAttribute(new JmxAttributePollConfig<Double>(MAX_FETCH_TIME)
-                        .objectName(SOCKET_SERVER_STATS_MBEAN)
-                        .attributeName("MaxFetchRequestMs")
-                        .onException(Functions.constant(-1.0d))
-                        .enabled(retrieveUsageMetrics))
-                .pollAttribute(new JmxAttributePollConfig<Long>(PRODUCE_REQUEST_COUNT)
-                        .objectName(SOCKET_SERVER_STATS_MBEAN)
-                        .attributeName("NumProduceRequests")
-                        .onException(Functions.constant(-1l))
-                        .enabled(retrieveUsageMetrics))
-                .pollAttribute(new JmxAttributePollConfig<Long>(TOTAL_PRODUCE_TIME)
-                        .objectName(SOCKET_SERVER_STATS_MBEAN)
-                        .attributeName("TotalProduceRequestMs")
-                        .onException(Functions.constant(-1l))
-                        .enabled(retrieveUsageMetrics))
-                .pollAttribute(new JmxAttributePollConfig<Double>(MAX_PRODUCE_TIME)
-                        .objectName(SOCKET_SERVER_STATS_MBEAN)
-                        .attributeName("MaxProduceRequestMs")
-                        .onException(Functions.constant(-1.0d))
-                        .enabled(retrieveUsageMetrics))
-                .pollAttribute(new JmxAttributePollConfig<Long>(BYTES_RECEIVED)
-                        .objectName(SOCKET_SERVER_STATS_MBEAN)
-                        .attributeName("TotalBytesRead")
-                        .onException(Functions.constant(-1l))
-                        .enabled(retrieveUsageMetrics))
-                .pollAttribute(new JmxAttributePollConfig<Long>(BYTES_SENT)
-                        .objectName(SOCKET_SERVER_STATS_MBEAN)
-                        .attributeName("TotalBytesWritten")
-                        .onException(Functions.constant(-1l))
-                        .enabled(retrieveUsageMetrics))
-                .build();
-        }
-
-        setBrokerUrl();
-    }
-
-    @Override
-    public void disconnectSensors() {
-        super.disconnectSensors();
-        disconnectServiceUpIsRunning();
-        if (jmxFeed != null) jmxFeed.stop();
-    }
-
-    @Override
-    protected ToStringHelper toStringHelper() {
-        return super.toStringHelper()
-                .add("kafkaPort", getKafkaPort());
-    }
-
-    /** Use the {@link #getZookeeper() zookeeper} details if available, otherwise use our own host and port. */
-    @Override
-    public void setBrokerUrl() {
-        ZooKeeperNode zookeeper = getZookeeper();
-        if (zookeeper != null) {
-            setAttribute(BROKER_URL, String.format("zookeeper://%s:%d", zookeeper.getAttribute(HOSTNAME), zookeeper.getZookeeperPort()));
-        } else {
-            setAttribute(BROKER_URL, String.format("kafka://%s:%d", getAttribute(HOSTNAME), getKafkaPort()));
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerSshDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerSshDriver.java
deleted file mode 100644
index 7892ac5..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaBrokerSshDriver.java
+++ /dev/null
@@ -1,97 +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 brooklyn.entity.messaging.kafka;
-
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.java.UsesJmx;
-import brooklyn.entity.java.UsesJmx.JmxAgentModes;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-
-public class KafkaBrokerSshDriver extends AbstractfKafkaSshDriver implements KafkaBrokerDriver {
-
-    private static final Logger LOG = LoggerFactory.getLogger(KafkaBrokerSshDriver.class);
-
-    public KafkaBrokerSshDriver(KafkaBrokerImpl entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    @Override
-    protected Map<String, Integer> getPortMap() {
-        return MutableMap.of("kafkaPort", getKafkaPort());
-    }
-
-    @Override
-    protected ConfigKey<String> getConfigTemplateKey() {
-        return KafkaBroker.KAFKA_BROKER_CONFIG_TEMPLATE;
-    }
-
-    @Override
-    protected String getConfigFileName() {
-        return "server.properties";
-    }
-
-    @Override
-    protected String getLaunchScriptName() {
-        return "kafka-server-start.sh";
-    }
-
-    @Override
-    public String getTopicsScriptName() {
-        return "kafka-topics.sh";
-    }
-
-    @Override
-    protected String getProcessIdentifier() {
-        return "kafka\\.Kafka";
-    }
-
-    @Override
-    public Integer getKafkaPort() {
-        return getEntity().getAttribute(KafkaBroker.KAFKA_PORT);
-    }
-
-    @Override
-    public Map<String, String> getShellEnvironment() {
-        JmxAgentModes jmxAgentMode = getEntity().getConfig(KafkaBroker.JMX_AGENT_MODE);
-        String jmxPort;
-        if (jmxAgentMode == JmxAgentModes.NONE) {
-            // seems odd to pass RMI port here, as it gets assigned to com.sun.mgmt.jmx.port in kafka-run-class.sh
-            // but RMI server/registry port works, whereas JMX port does not
-            jmxPort = String.valueOf(entity.getAttribute(UsesJmx.JMX_PORT));
-        } else {
-            /*
-             * See ./bin/kafka-server-start.sh  and ./bin/kafka-run-class.sh
-             * Really hard to turn off jmxremote on kafka! And can't use default because
-             * uses 9999, which means could only run one kafka broker per server.
-             */
-            jmxPort = String.valueOf(entity.getAttribute(KafkaBroker.INTERNAL_JMX_PORT));
-        }
-
-        return MutableMap.<String, String> builder()
-                .putAll(super.getShellEnvironment())
-                .put("JMX_PORT", jmxPort)
-                .build();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaCluster.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaCluster.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaCluster.java
deleted file mode 100644
index 3a24377..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaCluster.java
+++ /dev/null
@@ -1,92 +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 brooklyn.entity.messaging.kafka;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.Group;
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.BrooklynConfigKeys;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.group.Cluster;
-import brooklyn.entity.group.DynamicCluster;
-import brooklyn.entity.trait.Resizable;
-import brooklyn.entity.trait.Startable;
-import brooklyn.entity.zookeeper.ZooKeeperNode;
-import brooklyn.event.basic.BasicAttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.time.Duration;
-
-/**
- * Provides Kafka cluster functionality through a group of {@link KafkaBroker brokers} controlled
- * by a single {@link KafkaZookeeper zookeeper} entity.
- * <p>
- * You can customise the Kafka zookeeper and brokers by supplying {@link EntitySpec entity specifications}
- * to be used when creating them. An existing {@link Zookeeper} entity may also be provided instead of the
- * Kafka zookeeper.
- * <p>
- * The contents of this entity are:
- * <ul>
- * <li>a {@link brooklyn.entity.group.DynamicCluster} of {@link KafkaBroker}s
- * <li>a {@link KafkaZookeeper} or {@link Zookeeper}
- * <li>a {@link org.apache.brooklyn.api.policy.Policy} to resize the broker cluster
- * </ul>
- * The {@link Group group} and {@link Resizable} interface methods are delegated to the broker cluster, so calling
- * {@link Resizable#resize(Integer) resize} will change the number of brokers.
- */
-@SuppressWarnings({ "unchecked", "rawtypes" })
-@Catalog(name="Kafka", description="Apache Kafka is a distributed publish-subscribe messaging system", iconUrl="classpath://brooklyn/entity/messaging/kafka/kafka-google-doorway.jpg")
-@ImplementedBy(KafkaClusterImpl.class)
-public interface KafkaCluster extends Entity, Startable, Resizable, Group  {
-
-    @SetFromFlag("startTimeout")
-    ConfigKey<Duration> START_TIMEOUT = BrooklynConfigKeys.START_TIMEOUT;
-
-    @SetFromFlag("initialSize")
-    ConfigKey<Integer> INITIAL_SIZE = ConfigKeys.newConfigKeyWithDefault(Cluster.INITIAL_SIZE, 1);
-
-    /** Zookeeper for the cluster. If null a default be will created. */
-    @SetFromFlag("zookeeper")
-    BasicAttributeSensorAndConfigKey<ZooKeeperNode> ZOOKEEPER = new BasicAttributeSensorAndConfigKey<ZooKeeperNode>(
-            ZooKeeperNode.class, "kafka.cluster.zookeeper", "The zookeeper for the cluster; if null a default be will created");
-
-    /** Spec for creating the default Kafka zookeeper entity. */
-    @SetFromFlag("zookeeperSpec")
-    BasicAttributeSensorAndConfigKey<EntitySpec<KafkaZooKeeper>> ZOOKEEPER_SPEC = new BasicAttributeSensorAndConfigKey(
-            EntitySpec.class, "kafka.cluster.zookeeperSpec", "Spec for creating the kafka zookeeper");
-
-    /** Spec for Kafka broker entities to be created. */
-    @SetFromFlag("brokerSpec")
-    BasicAttributeSensorAndConfigKey<EntitySpec<KafkaBroker>> BROKER_SPEC = new BasicAttributeSensorAndConfigKey(
-            EntitySpec.class, "kafka.cluster.brokerSpec", "Spec for Kafka broker entiites to be created");
-
-    /** Underlying Kafka broker cluster. */
-    AttributeSensor<DynamicCluster> CLUSTER = new BasicAttributeSensor<DynamicCluster>(
-            DynamicCluster.class, "kafka.cluster.brokerCluster", "Underlying Kafka broker cluster");
-
-    ZooKeeperNode getZooKeeper();
-
-    DynamicCluster getCluster();
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
deleted file mode 100644
index b5b8449..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaClusterImpl.java
+++ /dev/null
@@ -1,206 +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 brooklyn.entity.messaging.kafka;
-
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.enricher.Enrichers;
-import brooklyn.entity.basic.AbstractEntity;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.group.DynamicCluster;
-import brooklyn.entity.trait.Startable;
-import brooklyn.entity.zookeeper.ZooKeeperNode;
-import brooklyn.event.feed.ConfigToAttributes;
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.exceptions.CompoundRuntimeException;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-
-/**
- * Implementation of a Kafka cluster containing a {@link KafkaZookeeper} node and a group of {@link KafkaBroker}s.
- */
-public class KafkaClusterImpl extends AbstractEntity implements KafkaCluster {
-
-    public static final Logger log = LoggerFactory.getLogger(KafkaClusterImpl.class);
-
-    public KafkaClusterImpl() {
-    }
-
-    @Override
-    public void init() {
-        super.init();
-        
-        setAttribute(SERVICE_UP, false);
-        ConfigToAttributes.apply(this, BROKER_SPEC);
-        ConfigToAttributes.apply(this, ZOOKEEPER);
-        ConfigToAttributes.apply(this, ZOOKEEPER_SPEC);
-
-        log.debug("creating zookeeper child for {}", this);
-        ZooKeeperNode zookeeper = getAttribute(ZOOKEEPER);
-        if (zookeeper == null) {
-            EntitySpec<KafkaZooKeeper> zookeeperSpec = getAttribute(ZOOKEEPER_SPEC);
-            if (zookeeperSpec == null) {
-                log.debug("creating zookeeper using default spec for {}", this);
-                zookeeperSpec = EntitySpec.create(KafkaZooKeeper.class);
-                setAttribute(ZOOKEEPER_SPEC, zookeeperSpec);
-            } else {
-                log.debug("creating zookeeper using custom spec for {}", this);
-            }
-            zookeeper = addChild(zookeeperSpec);
-            if (Entities.isManaged(this)) Entities.manage(zookeeper);
-            setAttribute(ZOOKEEPER, zookeeper);
-        }
-
-        log.debug("creating cluster child for {}", this);
-        EntitySpec<KafkaBroker> brokerSpec = getAttribute(BROKER_SPEC);
-        if (brokerSpec == null) {
-            log.debug("creating default broker spec for {}", this);
-            brokerSpec = EntitySpec.create(KafkaBroker.class);
-            setAttribute(BROKER_SPEC, brokerSpec);
-        }
-        // Relies on initialSize being inherited by DynamicCluster, because key id is identical
-        // We add the zookeeper configuration to the KafkaBroker specification here
-        DynamicCluster cluster = addChild(EntitySpec.create(DynamicCluster.class)
-                .configure("memberSpec", EntitySpec.create(brokerSpec).configure(KafkaBroker.ZOOKEEPER, zookeeper)));
-        if (Entities.isManaged(this)) Entities.manage(cluster);
-        setAttribute(CLUSTER, cluster);
-        
-        connectSensors();
-    }
-
-    @Override
-    public ZooKeeperNode getZooKeeper() {
-        return getAttribute(ZOOKEEPER);
-    }
-
-    @Override
-    public DynamicCluster getCluster() {
-        return getAttribute(CLUSTER);
-    }
-
-    @Override
-    public void start(Collection<? extends Location> locations) {
-        if (isLegacyConstruction()) {
-            init();
-        }
-
-        if (locations.isEmpty()) locations = getLocations();
-        Iterables.getOnlyElement(locations); // Assert just one
-        addLocations(locations);
-
-        List<Entity> childrenToStart = MutableList.<Entity>of(getCluster());
-        // Set the KafkaZookeeper entity as child of cluster, if it does not already have a parent
-        if (getZooKeeper().getParent() == null) {
-            addChild(getZooKeeper());
-        } // And only start zookeeper if we are parent
-        if (Objects.equal(this, getZooKeeper().getParent())) childrenToStart.add(getZooKeeper());
-        Entities.invokeEffector(this, childrenToStart, Startable.START, ImmutableMap.of("locations", locations)).getUnchecked();
-    }
-
-    @Override
-    public void stop() {
-        List<Exception> errors = Lists.newArrayList();
-        if (getZooKeeper() != null && Objects.equal(this, getZooKeeper().getParent())) {
-            try {
-                getZooKeeper().stop();
-            } catch (Exception e) {
-                errors.add(e);
-            }
-        }
-        if (getCurrentSize() > 0) {
-            try {
-                getCluster().stop();
-            } catch (Exception e) {
-                errors.add(e);
-            }
-        }
-
-        clearLocations();
-        setAttribute(SERVICE_UP, false);
-
-        if (errors.size() != 0) {
-            throw new CompoundRuntimeException("Error stopping Kafka cluster", errors);
-        }
-    }
-
-    @Override
-    public void restart() {
-        // TODO prod the entities themselves to restart, instead?
-        Collection<Location> locations = Lists.newArrayList(getLocations());
-
-        stop();
-        start(locations);
-    }
-
-    void connectSensors() {
-        addEnricher(Enrichers.builder()
-                .propagatingAllBut(SERVICE_UP)
-                .from(getCluster())
-                .build());
-        addEnricher(Enrichers.builder()
-                .propagating(SERVICE_UP)
-                .from(getZooKeeper())
-                .build());
-    }
-
-    /*
-     * All Group and Resizable interface methods are delegated to the broker cluster.
-     */
-
-    /** {@inheritDoc} */
-    @Override
-    public Collection<Entity> getMembers() { return getCluster().getMembers(); }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean hasMember(Entity member) { return getCluster().hasMember(member); }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean addMember(Entity member) { return getCluster().addMember(member); }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean removeMember(Entity member) { return getCluster().removeMember(member); }
-
-    /** {@inheritDoc} */
-    @Override
-    public Integer getCurrentSize() { return getCluster().getCurrentSize(); }
-
-    /** {@inheritDoc} */
-    @Override
-    public Integer resize(Integer desiredSize) { return getCluster().resize(desiredSize); }
-
-    @Override
-    public <T extends Entity> T addMemberChild(EntitySpec<T> spec) { return getCluster().addMemberChild(spec); }
-
-    @Override
-    public <T extends Entity> T addMemberChild(T child) { return getCluster().addMemberChild(child); }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
deleted file mode 100644
index 106690a..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeper.java
+++ /dev/null
@@ -1,58 +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 brooklyn.entity.messaging.kafka;
-
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.annotation.Effector;
-import brooklyn.entity.annotation.EffectorParam;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.zookeeper.ZooKeeperNode;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.time.Duration;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Kafka zookeeper instance.
- */
-@ImplementedBy(KafkaZooKeeperImpl.class)
-public interface KafkaZooKeeper extends ZooKeeperNode, Kafka {
-
-    @SetFromFlag("startTimeout")
-    ConfigKey<Duration> START_TIMEOUT = SoftwareProcess.START_TIMEOUT;
-
-    /** The Kafka version, not the Zookeeper version. */
-    @SetFromFlag("version")
-    ConfigKey<String> SUGGESTED_VERSION = Kafka.SUGGESTED_VERSION;
-    
-    /** The Kafka version, not the Zookeeper version. */
-    @SetFromFlag("downloadUrl")
-    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = Kafka.DOWNLOAD_URL;
-
-    /** Location of the kafka configuration file template to be copied to the server. */
-    @SetFromFlag("kafkaZookeeperConfig")
-    ConfigKey<String> KAFKA_ZOOKEEPER_CONFIG_TEMPLATE = new BasicConfigKey<String>(String.class,
-            "kafka.zookeeper.configTemplate", "Kafka zookeeper configuration template (in freemarker format)",
-            "classpath://brooklyn/entity/messaging/kafka/zookeeper.properties");
-
-    @Effector(description = "Create a topic with a single partition and only one replica")
-    void createTopic(@EffectorParam(name = "topic") String topic);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperDriver.java
deleted file mode 100644
index 97edc8b..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperDriver.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 brooklyn.entity.messaging.kafka;
-
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-
-public interface KafkaZooKeeperDriver extends JavaSoftwareProcessDriver {
-
-    Integer getZookeeperPort();
-
-    void createTopic(String topic);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperImpl.java
deleted file mode 100644
index c9a1148..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperImpl.java
+++ /dev/null
@@ -1,47 +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 brooklyn.entity.messaging.kafka;
-
-import brooklyn.entity.annotation.EffectorParam;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.zookeeper.AbstractZooKeeperImpl;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Kafka zookeeper instance.
- */
-public class KafkaZooKeeperImpl extends AbstractZooKeeperImpl implements KafkaZooKeeper {
-
-    @SuppressWarnings("unused")
-    private static final Logger log = LoggerFactory.getLogger(KafkaZooKeeperImpl.class);
-
-    public KafkaZooKeeperImpl() {
-    }
-
-    @Override
-    public Class<?> getDriverInterface() {
-        return KafkaZooKeeperDriver.class;
-    }
-
-    @Override
-    public void createTopic(String topic) {
-        ((KafkaZooKeeperDriver)getDriver()).createTopic(topic);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperSshDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperSshDriver.java
deleted file mode 100644
index dc7688f..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/kafka/KafkaZooKeeperSshDriver.java
+++ /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 brooklyn.entity.messaging.kafka;
-
-import java.util.Map;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.Attributes;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-
-import static brooklyn.util.text.StringEscapes.BashStringEscapes.escapeLiteralForDoubleQuotedBash;
-
-public class KafkaZooKeeperSshDriver extends AbstractfKafkaSshDriver implements KafkaZooKeeperDriver {
-
-    public KafkaZooKeeperSshDriver(KafkaZooKeeperImpl entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    @Override
-    protected Map<String, Integer> getPortMap() {
-        return MutableMap.of("zookeeperPort", getZookeeperPort());
-    }
-
-    @Override
-    protected ConfigKey<String> getConfigTemplateKey() {
-        return KafkaZooKeeper.KAFKA_ZOOKEEPER_CONFIG_TEMPLATE;
-    }
-
-    @Override
-    protected String getConfigFileName() {
-        return "zookeeper.properties";
-    }
-
-    @Override
-    protected String getLaunchScriptName() {
-        return "zookeeper-server-start.sh";
-    }
-
-    @Override
-    protected String getTopicsScriptName() {
-        return "kafka-topics.sh";
-    }
-
-    @Override
-    protected String getProcessIdentifier() {
-        return "quorum\\.QuorumPeerMain";
-    }
-
-    @Override
-    public Integer getZookeeperPort() {
-        return getEntity().getAttribute(KafkaZooKeeper.ZOOKEEPER_PORT);
-    }
-
-    @Override
-    public void createTopic(String topic) {
-        String zookeeperUrl = getEntity().getAttribute(Attributes.HOSTNAME) + ":" + getZookeeperPort();
-        newScript(CUSTOMIZING)
-                .failOnNonZeroResultCode()
-                .body.append(String.format("./bin/%s  --create --zookeeper \"%s\" --replication-factor 1 --partitions 1 --topic \"%s\"",
-                                           getTopicsScriptName(),
-                                           escapeLiteralForDoubleQuotedBash(zookeeperUrl),
-                                           escapeLiteralForDoubleQuotedBash(topic)))
-                .execute();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBroker.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBroker.java
deleted file mode 100644
index a2af8a4..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBroker.java
+++ /dev/null
@@ -1,79 +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 brooklyn.entity.messaging.qpid;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.java.UsesJmx;
-import brooklyn.entity.messaging.MessageBroker;
-import brooklyn.entity.messaging.amqp.AmqpServer;
-import brooklyn.entity.messaging.jms.JMSBroker;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Qpid broker instance, using AMQP 0-10.
- */
-@Catalog(name="Qpid Broker", description="Apache Qpid is an open-source messaging system, implementing the Advanced Message Queuing Protocol (AMQP)", iconUrl="classpath:///qpid-logo.jpeg")
-@ImplementedBy(QpidBrokerImpl.class)
-public interface QpidBroker extends SoftwareProcess, MessageBroker, UsesJmx, AmqpServer, JMSBroker<QpidQueue, QpidTopic> {
-
-    /* Qpid runtime file locations for convenience. */
-
-    public static final String CONFIG_XML = "etc/config.xml";
-    public static final String VIRTUALHOSTS_XML = "etc/virtualhosts.xml";
-    public static final String PASSWD = "etc/passwd";
-
-    @SetFromFlag("version")
-    public static final ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "0.20");
-    
-    @SetFromFlag("downloadUrl")
-    public static final BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
-            Attributes.DOWNLOAD_URL, "http://download.nextag.com/apache/qpid/${version}/qpid-java-broker-${version}.tar.gz");
-
-    @SetFromFlag("amqpPort")
-    public static final PortAttributeSensorAndConfigKey AMQP_PORT = AmqpServer.AMQP_PORT;
-
-    @SetFromFlag("virtualHost")
-    public static final BasicAttributeSensorAndConfigKey<String> VIRTUAL_HOST_NAME = AmqpServer.VIRTUAL_HOST_NAME;
-
-    @SetFromFlag("amqpVersion")
-    public static final BasicAttributeSensorAndConfigKey<String> AMQP_VERSION = new BasicAttributeSensorAndConfigKey<String>(
-            AmqpServer.AMQP_VERSION, AmqpServer.AMQP_0_10);
-    
-    @SetFromFlag("httpManagementPort")
-    public static final PortAttributeSensorAndConfigKey HTTP_MANAGEMENT_PORT = new PortAttributeSensorAndConfigKey("qpid.http-management.port", "Qpid HTTP management plugin port");
-
-    @SetFromFlag("jmxUser")
-    public static final BasicAttributeSensorAndConfigKey<String> JMX_USER = new BasicAttributeSensorAndConfigKey<String>(
-            UsesJmx.JMX_USER, "admin");
-    
-    @SetFromFlag("jmxPassword")
-    public static final BasicAttributeSensorAndConfigKey<String> JMX_PASSWORD = new BasicAttributeSensorAndConfigKey<String>(
-            UsesJmx.JMX_PASSWORD, "admin");
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBrokerImpl.java
deleted file mode 100644
index baf487d..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidBrokerImpl.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 brooklyn.entity.messaging.qpid;
-
-import static java.lang.String.format;
-
-import java.io.IOException;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.java.JmxSupport;
-import brooklyn.entity.messaging.jms.JMSBrokerImpl;
-import brooklyn.event.feed.jmx.JmxAttributePollConfig;
-import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.event.feed.jmx.JmxHelper;
-import brooklyn.util.exceptions.Exceptions;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Objects.ToStringHelper;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Qpid broker instance, using AMQP 0-10.
- */
-public class QpidBrokerImpl extends JMSBrokerImpl<QpidQueue, QpidTopic> implements QpidBroker {
-    private static final Logger log = LoggerFactory.getLogger(QpidBrokerImpl.class);
-
-    private volatile JmxFeed jmxFeed;
-
-    public QpidBrokerImpl() {
-        super();
-    }
-
-    public String getVirtualHost() { return getAttribute(VIRTUAL_HOST_NAME); }
-    public String getAmqpVersion() { return getAttribute(AMQP_VERSION); }
-    public Integer getAmqpPort() { return getAttribute(AMQP_PORT); }
-
-    public void setBrokerUrl() {
-        String urlFormat = "amqp://guest:guest@/%s?brokerlist='tcp://%s:%d'";
-        setAttribute(BROKER_URL, format(urlFormat, getAttribute(VIRTUAL_HOST_NAME), getAttribute(HOSTNAME), getAttribute(AMQP_PORT)));
-    }
-    
-    @Override
-    public void init() {
-        super.init();
-        new JmxSupport(this, null).recommendJmxRmiCustomAgent();
-    }
-
-    public void waitForServiceUp(long duration, TimeUnit units) {
-        super.waitForServiceUp(duration, units);
-
-        // Also wait for the MBean to exist (as used when creating queue/topic)
-        JmxHelper helper = new JmxHelper(this);
-        try {
-            String virtualHost = getConfig(QpidBroker.VIRTUAL_HOST_NAME);
-            ObjectName virtualHostManager = new ObjectName(format("org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=\"%s\"", virtualHost));
-            helper.connect();
-            helper.assertMBeanExistsEventually(virtualHostManager, units.toMillis(duration));
-        } catch (MalformedObjectNameException e) {
-            throw Exceptions.propagate(e);
-        } catch (IOException e) {
-            throw Exceptions.propagate(e);
-        } finally {
-            if (helper != null) helper.terminate();
-        }
-    }
-    
-    public QpidQueue createQueue(Map properties) {
-        QpidQueue result = addChild(EntitySpec.create(QpidQueue.class).configure(properties));
-        Entities.manage(result);
-        result.create();
-        return result;
-    }
-
-    public QpidTopic createTopic(Map properties) {
-        QpidTopic result = addChild(EntitySpec.create(QpidTopic.class).configure(properties));
-        Entities.manage(result);
-        result.create();
-        return result;
-    }
-
-    @Override
-    public Class getDriverInterface() {
-        return QpidDriver.class;
-    }
-
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-        String serverInfoMBeanName = "org.apache.qpid:type=ServerInformation,name=ServerInformation";
-
-        jmxFeed = JmxFeed.builder()
-                .entity(this)
-                .period(500, TimeUnit.MILLISECONDS)
-                .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP)
-                        .objectName(serverInfoMBeanName)
-                        .attributeName("ProductVersion")
-                        .onSuccess(new Function<Object,Boolean>() {
-                                private boolean hasWarnedOfVersionMismatch;
-                                @Override public Boolean apply(Object input) {
-                                    if (input == null) return false;
-                                    if (!hasWarnedOfVersionMismatch && !getConfig(QpidBroker.SUGGESTED_VERSION).equals(input)) {
-                                        log.warn("Qpid version mismatch: ProductVersion is {}, requested version is {}", input, getConfig(QpidBroker.SUGGESTED_VERSION));
-                                        hasWarnedOfVersionMismatch = true;
-                                    }
-                                    return true;
-                                }})
-                        .onException(Functions.constant(false))
-                        .suppressDuplicates(true))
-                .build();
-    }
-
-    @Override
-    public void disconnectSensors() {
-        super.disconnectSensors();
-        if (jmxFeed != null) jmxFeed.stop();
-    }
-
-    @Override
-    protected ToStringHelper toStringHelper() {
-        return super.toStringHelper().add("amqpPort", getAmqpPort());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestination.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestination.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestination.java
deleted file mode 100644
index 9250e2a..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestination.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 brooklyn.entity.messaging.qpid;
-
-import brooklyn.entity.messaging.amqp.AmqpExchange;
-import brooklyn.entity.messaging.jms.JMSDestination;
-
-public interface QpidDestination extends JMSDestination, AmqpExchange {
-    
-    public void create();
-    
-    /**
-     * Return the AMQP name for the queue.
-     */
-    public String getQueueName();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
deleted file mode 100644
index 0dc6390..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
+++ /dev/null
@@ -1,101 +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 brooklyn.entity.messaging.qpid;
-
-import static java.lang.String.format;
-
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import org.apache.brooklyn.api.entity.basic.EntityLocal;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.java.UsesJmx;
-import brooklyn.entity.messaging.amqp.AmqpServer;
-import brooklyn.entity.messaging.jms.JMSDestinationImpl;
-import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.event.feed.jmx.JmxHelper;
-import brooklyn.util.exceptions.Exceptions;
-
-public abstract class QpidDestinationImpl extends JMSDestinationImpl implements QpidDestination {
-    public static final Logger log = LoggerFactory.getLogger(QpidDestination.class);
-    
-    @SetFromFlag
-    String virtualHost;
-
-    protected ObjectName virtualHostManager;
-    protected ObjectName exchange;
-    protected transient JmxHelper jmxHelper;
-    protected volatile JmxFeed jmxFeed;
-
-    public QpidDestinationImpl() {
-    }
-
-    @Override
-    public QpidBroker getParent() {
-        return (QpidBroker) super.getParent();
-    }
-    
-    @Override
-    public void onManagementStarting() {
-        super.onManagementStarting();
-        
-        // TODO Would be nice to share the JmxHelper for all destinations, so just one connection.
-        // But tricky for if brooklyn were distributed
-        try {
-            if (virtualHost == null) virtualHost = getConfig(QpidBroker.VIRTUAL_HOST_NAME);
-            setAttribute(QpidBroker.VIRTUAL_HOST_NAME, virtualHost);
-            virtualHostManager = new ObjectName(format("org.apache.qpid:type=VirtualHost.VirtualHostManager,VirtualHost=\"%s\"", virtualHost));
-            jmxHelper = new JmxHelper((EntityLocal)getParent());
-        } catch (MalformedObjectNameException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    @Override
-    protected void disconnectSensors() {
-        if (jmxFeed != null) jmxFeed.stop();
-    }
-
-    @Override
-    public void create() {
-        jmxHelper.operation(virtualHostManager, "createNewQueue", getName(), getParent().getAttribute(UsesJmx.JMX_USER), true);
-        jmxHelper.operation(exchange, "createNewBinding", getName(), getName());
-        connectSensors();
-    }
-    
-    @Override
-    public void delete() {
-        jmxHelper.operation(exchange, "removeBinding", getName(), getName());
-        jmxHelper.operation(virtualHostManager, "deleteQueue", getName());
-        disconnectSensors();
-    }
-
-    @Override
-    public String getQueueName() {
-
-        if (AmqpServer.AMQP_0_10.equals(getParent().getAmqpVersion())) {
-            return String.format("'%s'/'%s'; { assert: never }", getExchangeName(), getName());
-        } else {
-            return getName();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDriver.java
deleted file mode 100644
index 26d0e5a..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDriver.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 brooklyn.entity.messaging.qpid;
-
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-
-public interface QpidDriver extends JavaSoftwareProcessDriver {
-
-    Integer getAmqpPort();
-
-    String getAmqpVersion();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidQueue.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidQueue.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidQueue.java
deleted file mode 100644
index 42c3065..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidQueue.java
+++ /dev/null
@@ -1,29 +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 brooklyn.entity.messaging.qpid;
-
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-
-import brooklyn.entity.messaging.Queue;
-
-@ImplementedBy(QpidQueueImpl.class)
-public interface QpidQueue extends QpidDestination, Queue {
-    @Override
-    public String getExchangeName();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidQueueImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidQueueImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidQueueImpl.java
deleted file mode 100644
index 1774583..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidQueueImpl.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 brooklyn.entity.messaging.qpid;
-
-import static java.lang.String.format;
-
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import brooklyn.entity.messaging.amqp.AmqpExchange;
-import brooklyn.event.feed.jmx.JmxAttributePollConfig;
-import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.util.exceptions.Exceptions;
-
-public class QpidQueueImpl extends QpidDestinationImpl implements QpidQueue {
-    public QpidQueueImpl() {
-    }
-
-    @Override
-    public void onManagementStarting() {
-        super.onManagementStarting();
-        setAttribute(QUEUE_NAME, getName());
-        try {
-            exchange = new ObjectName(format("org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=\"%s\",name=\"%s\",ExchangeType=direct", virtualHost, getExchangeName()));
-        } catch (MalformedObjectNameException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    @Override
-    protected void connectSensors() {
-        String queue = format("org.apache.qpid:type=VirtualHost.Queue,VirtualHost=\"%s\",name=\"%s\"", virtualHost, getName());
-        
-        jmxFeed = JmxFeed.builder()
-                .entity(this)
-                .helper(jmxHelper)
-                .pollAttribute(new JmxAttributePollConfig<Integer>(QUEUE_DEPTH_BYTES)
-                        .objectName(queue)
-                        .attributeName("QueueDepth"))
-                .pollAttribute(new JmxAttributePollConfig<Integer>(QUEUE_DEPTH_MESSAGES)
-                        .objectName(queue)
-                        .attributeName("MessageCount"))
-                .build();
-    }
-
-    @Override
-    public String getExchangeName() {
-        return AmqpExchange.DIRECT;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidSshDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidSshDriver.java
deleted file mode 100644
index 2b1a8ec..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidSshDriver.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 brooklyn.entity.messaging.qpid;
-
-import static java.lang.String.format;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.net.Networking;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-
-import com.google.common.collect.ImmutableMap;
-
-public class QpidSshDriver extends JavaSoftwareProcessSshDriver implements QpidDriver{
-
-    private static final Logger log = LoggerFactory.getLogger(QpidSshDriver.class);
-
-    public QpidSshDriver(QpidBrokerImpl entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    @Override
-    protected String getLogFileLocation() { return Os.mergePaths(getRunDir(), "log", "qpid.log"); }
-
-    @Override
-    public Integer getAmqpPort() { return entity.getAttribute(QpidBroker.AMQP_PORT); }
-
-    @Override
-    public String getAmqpVersion() { return entity.getAttribute(QpidBroker.AMQP_VERSION); }
-
-    public Integer getHttpManagementPort() { return entity.getAttribute(QpidBroker.HTTP_MANAGEMENT_PORT); }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("qpid-broker-%s", getVersion()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-
-        List<String> commands = new LinkedList<String>();
-        commands.addAll( BashCommands.commandsToDownloadUrlsAs(urls, saveAs));
-        commands.add(BashCommands.INSTALL_TAR);
-        commands.add("tar xzfv "+saveAs);
-
-        newScript(INSTALLING)
-                .body.append(commands)
-                .execute();
-    }
-
-    @Override
-    public void customize() {
-        Networking.checkPortsValid(MutableMap.of("jmxPort", getJmxPort(), "amqpPort", getAmqpPort()));
-        newScript(CUSTOMIZING)
-                .body.append(
-                        format("cp -R %s/{bin,etc,lib} .", getExpandedInstallDir()),
-                        "mkdir lib/opt"
-                    )
-                .execute();
-    }
-
-    @Override
-    public void launch() {
-        newScript(ImmutableMap.of(USE_PID_FILE, false), LAUNCHING)
-                .body.append("nohup ./bin/qpid-server -b '*' > qpid-server-launch.log 2>&1 &")
-                .execute();
-    }
-
-    public String getPidFile() { return "qpid-server.pid"; }
-    
-    @Override
-    public boolean isRunning() {
-        return newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), CHECK_RUNNING).execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), STOPPING).execute();
-    }
-
-    @Override
-    public void kill() {
-        newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), KILLING).execute();
-    }
-
-    @Override
-    public Map<String, Object> getCustomJavaSystemProperties() {
-        return MutableMap.<String, Object>builder()
-                .putAll(super.getCustomJavaSystemProperties())
-                .put("connector.port", getAmqpPort())
-                .put("management.enabled", "true")
-                .put("management.jmxport.registryServer", getRmiRegistryPort())
-                .put("management.jmxport.connectorServer", getJmxPort())
-                .put("management.http.enabled", Boolean.toString(getHttpManagementPort() != null))
-                .putIfNotNull("management.http.port", getHttpManagementPort())
-                .build();
-    }
-
-    @Override
-    public Map<String, String> getShellEnvironment() {
-        return MutableMap.<String, String>builder()
-                .putAll(super.getShellEnvironment())
-                .put("QPID_HOME", getRunDir())
-                .put("QPID_WORK", getRunDir())
-                .renameKey("JAVA_OPTS", "QPID_OPTS")
-                .build();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidTopic.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidTopic.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidTopic.java
deleted file mode 100644
index 3ec1c06..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidTopic.java
+++ /dev/null
@@ -1,27 +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 brooklyn.entity.messaging.qpid;
-
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-
-import brooklyn.entity.messaging.Topic;
-
-@ImplementedBy(QpidTopicImpl.class)
-public interface QpidTopic extends QpidDestination, Topic {
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidTopicImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidTopicImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidTopicImpl.java
deleted file mode 100644
index 1d8e3c3..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidTopicImpl.java
+++ /dev/null
@@ -1,56 +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 brooklyn.entity.messaging.qpid;
-
-import static java.lang.String.format;
-
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-
-import brooklyn.entity.messaging.amqp.AmqpExchange;
-import brooklyn.util.exceptions.Exceptions;
-
-public class QpidTopicImpl extends QpidDestinationImpl implements QpidTopic {
-
-    public QpidTopicImpl() {
-    }
-
-    @Override
-    public void onManagementStarting() {
-        super.onManagementStarting();
-        setAttribute(TOPIC_NAME, getName());
-        try {
-            String virtualHost = getParent().getVirtualHost();
-            exchange = new ObjectName(format("org.apache.qpid:type=VirtualHost.Exchange,VirtualHost=\"%s\",name=\"%s\",ExchangeType=topic", virtualHost, getExchangeName()));
-        } catch (MalformedObjectNameException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-    // TODO sensors
-    @Override
-    public void connectSensors() {
-    }
-
-    @Override
-    public String getExchangeName() { return AmqpExchange.TOPIC; }
-
-    @Override
-    public String getTopicName() { return getQueueName(); }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBroker.java b/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBroker.java
deleted file mode 100644
index a70bfce..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBroker.java
+++ /dev/null
@@ -1,91 +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 brooklyn.entity.messaging.rabbit;
-
-import java.util.Map;
-
-import com.google.common.annotations.Beta;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.messaging.MessageBroker;
-import brooklyn.entity.messaging.amqp.AmqpServer;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Rabbit MQ broker instance, using AMQP 0-9-1.
- */
-@Catalog(name="RabbitMQ Broker", description="RabbitMQ is an open source message broker software (i.e. message-oriented middleware) that implements the Advanced Message Queuing Protocol (AMQP) standard", iconUrl="classpath:///RabbitMQLogo.png")
-@ImplementedBy(RabbitBrokerImpl.class)
-public interface RabbitBroker extends SoftwareProcess, MessageBroker, AmqpServer {
-
-    @SetFromFlag("version")
-    public static final ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "2.8.7");
-
-    @SetFromFlag("downloadUrl")
-    public static final BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
-            SoftwareProcess.DOWNLOAD_URL, "http://www.rabbitmq.com/releases/rabbitmq-server/v${version}/rabbitmq-server-generic-unix-${version}.tar.gz");
-    
-    @SetFromFlag("erlangVersion")
-    public static final BasicConfigKey<String> ERLANG_VERSION = new BasicConfigKey<String>(String.class, "erlang.version", "Erlang runtime version", "R15B");
-
-    @SetFromFlag("rabbitmqConfigTemplateUrl")
-    ConfigKey<String> CONFIG_TEMPLATE_URL = ConfigKeys.newStringConfigKey(
-            "rabbitmq.templateUrl", "Template file (in freemarker format) for the rabbitmq.config config file",
-            "classpath://brooklyn/entity/messaging/rabbit/rabbitmq.config");
-
-    @SetFromFlag("amqpPort")
-    public static final PortAttributeSensorAndConfigKey AMQP_PORT = AmqpServer.AMQP_PORT;
-
-    @SetFromFlag("virtualHost")
-    public static final BasicAttributeSensorAndConfigKey<String> VIRTUAL_HOST_NAME = AmqpServer.VIRTUAL_HOST_NAME;
-
-    @SetFromFlag("amqpVersion")
-    public static final BasicAttributeSensorAndConfigKey<String> AMQP_VERSION = new BasicAttributeSensorAndConfigKey<String>(
-            AmqpServer.AMQP_VERSION, AmqpServer.AMQP_0_9_1);
-
-    @SetFromFlag("managmentPort")
-    public static final PortAttributeSensorAndConfigKey MANAGEMENT_PORT = new PortAttributeSensorAndConfigKey(
-            "rabbitmq.management.port", "Port on which management interface will be available", "15672+");
-
-    public static AttributeSensor<String> MANAGEMENT_URL = Sensors.newStringSensor(
-            "rabbitmq.management.url", "Management URL is only available if management plugin flag is true");
-
-    @SetFromFlag("enableManagementPlugin")
-    public static final ConfigKey<Boolean> ENABLE_MANAGEMENT_PLUGIN = ConfigKeys.newBooleanConfigKey(
-            "rabbitmq.management.plugin", "Management plugin will be enabled", false);
-
-    RabbitQueue createQueue(Map properties);
-
-    // TODO required by RabbitDestination due to close-coupling between that and RabbitBroker; how best to improve?
-    @Beta
-    Map<String, String> getShellEnvironment();
-    
-    @Beta
-    String getRunDir();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.java
deleted file mode 100644
index 5d96d92..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBrokerImpl.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 brooklyn.entity.messaging.rabbit;
-
-import static java.lang.String.format;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Objects.ToStringHelper;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Rabbit MQ broker instance, using AMQP 0-9-1.
- */
-public class RabbitBrokerImpl extends SoftwareProcessImpl implements RabbitBroker {
-    private static final Logger log = LoggerFactory.getLogger(RabbitBrokerImpl.class);
-
-    public String getVirtualHost() { return getAttribute(VIRTUAL_HOST_NAME); }
-    public String getAmqpVersion() { return getAttribute(AMQP_VERSION); }
-    public Integer getAmqpPort() { return getAttribute(AMQP_PORT); }
-
-    public RabbitBrokerImpl() {
-        super();
-    }
-
-    @Override
-    public RabbitDriver getDriver() {
-        return (RabbitDriver) super.getDriver();
-    }
-
-    @Override
-    public Map<String, String> getShellEnvironment() {
-        return getDriver().getShellEnvironment();
-    }
-    
-    @Override
-    public String getRunDir() {
-        return getDriver().getRunDir();
-    }
-    
-    @Override
-    protected void postStart() {
-        super.postStart();
-
-        getDriver().configure();
-
-        // TODO implement this using AMQP connection, no external mechanism available
-        // queueNames.each { String name -> addQueue(name) }
-    }
-
-    public void setBrokerUrl() {
-        String urlFormat = "amqp://guest:guest@%s:%d/%s";
-        setAttribute(BROKER_URL, format(urlFormat, getAttribute(HOSTNAME), getAttribute(AMQP_PORT), getAttribute(VIRTUAL_HOST_NAME)));
-    }
-
-    public RabbitQueue createQueue(Map properties) {
-        RabbitQueue result = addChild(EntitySpec.create(RabbitQueue.class).configure(properties));
-        Entities.manage(result);
-        result.create();
-        return result;
-    }
-
-    @Override
-    public Class<? extends RabbitDriver> getDriverInterface() {
-        return RabbitDriver.class;
-    }
-
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-
-        connectServiceUpIsRunning();
-
-        setBrokerUrl();
-
-        if (getEnableManagementPlugin()) {
-            setAttribute(MANAGEMENT_URL, format("http://%s:%s/", getAttribute(HOSTNAME), getAttribute(MANAGEMENT_PORT)));
-        }
-    }
-
-    @Override
-    public void disconnectSensors() {
-        super.disconnectSensors();
-        disconnectServiceUpIsRunning();
-    }
-
-    public boolean getEnableManagementPlugin() {
-        return Boolean.TRUE.equals(getConfig(ENABLE_MANAGEMENT_PLUGIN));
-    }
-
-    public Integer getManagementPort() {
-        return getAttribute(MANAGEMENT_PORT);
-    }
-
-    @Override
-    protected ToStringHelper toStringHelper() {
-        return super.toStringHelper().add("amqpPort", getAmqpPort());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitDestination.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitDestination.java b/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitDestination.java
deleted file mode 100644
index 14e0e47..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitDestination.java
+++ /dev/null
@@ -1,92 +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 brooklyn.entity.messaging.rabbit;
-
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.AbstractEntity;
-import brooklyn.entity.messaging.amqp.AmqpExchange;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-
-import com.google.common.base.Objects.ToStringHelper;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
-
-public abstract class RabbitDestination extends AbstractEntity implements AmqpExchange {
-    public static final Logger log = LoggerFactory.getLogger(RabbitDestination.class);
-    
-    private String virtualHost;
-    private String exchange;
-    protected SshMachineLocation machine;
-    protected Map<String,String> shellEnvironment;
-
-    public RabbitDestination() {
-    }
-
-    @Override
-    public void onManagementStarting() {
-        super.onManagementStarting();
-        
-        exchange = (getConfig(EXCHANGE_NAME) != null) ? getConfig(EXCHANGE_NAME) : getDefaultExchangeName();
-        virtualHost = getConfig(RabbitBroker.VIRTUAL_HOST_NAME);
-        setAttribute(RabbitBroker.VIRTUAL_HOST_NAME, virtualHost);
-        
-        machine = (SshMachineLocation) Iterables.find(getParent().getLocations(), Predicates.instanceOf(SshMachineLocation.class));
-        shellEnvironment = getParent().getShellEnvironment();
-    }
-
-    // FIXME Should return RabbitBroker; won't work if gets a proxy rather than "real" entity
-    @Override
-    public RabbitBroker getParent() {
-        return (RabbitBroker) super.getParent();
-    }
-    
-    public void create() {
-        connectSensors();
-    }
-    
-    public void delete() {
-        disconnectSensors();
-    }
-
-    protected void connectSensors() { }
-
-    protected void disconnectSensors() { }
-
-    public String getVirtualHost() {
-        return virtualHost;
-    }
-    
-    @Override
-    public String getExchangeName() { 
-        return exchange;
-    }
-    
-    public String getDefaultExchangeName() {
-        return AmqpExchange.DIRECT;
-    }
-
-    @Override
-    protected ToStringHelper toStringHelper() {
-        return super.toStringHelper().add("virtualHost", getParent().getVirtualHost()).add("exchange", getExchangeName());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitDriver.java
deleted file mode 100644
index da07477..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitDriver.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 brooklyn.entity.messaging.rabbit;
-
-import java.util.Map;
-
-import brooklyn.entity.basic.SoftwareProcessDriver;
-
-public interface RabbitDriver extends SoftwareProcessDriver {
-    
-    public void configure();
-    
-    public Map<String, String> getShellEnvironment();
-
-    public String getRunDir();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitQueue.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitQueue.java b/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitQueue.java
deleted file mode 100644
index 31f1876..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitQueue.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 brooklyn.entity.messaging.rabbit;
-
-import brooklyn.entity.messaging.Queue;
-import brooklyn.event.feed.ssh.SshFeed;
-import brooklyn.event.feed.ssh.SshPollConfig;
-import brooklyn.event.feed.ssh.SshPollValue;
-
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-
-public class RabbitQueue extends RabbitDestination implements Queue {
-
-    private SshFeed sshFeed;
-
-    public RabbitQueue() {
-    }
-    
-    public String getName() {
-        return getDisplayName();
-    }
-
-    @Override
-    public void create() {
-        setAttribute(QUEUE_NAME, getName());
-        super.create();
-    }
-
-    @Override
-    protected void connectSensors() {
-        String runDir = getParent().getRunDir();
-        String cmd = String.format("%s/sbin/rabbitmqctl list_queues -p /%s  | grep '%s'", runDir, getVirtualHost(), getQueueName());
-        
-        sshFeed = SshFeed.builder()
-                .entity(this)
-                .machine(machine)
-                .poll(new SshPollConfig<Integer>(QUEUE_DEPTH_BYTES)
-                        .env(shellEnvironment)
-                        .command(cmd)
-                        .onFailure(Functions.constant(-1))
-                        .onSuccess(new Function<SshPollValue, Integer>() {
-                                @Override public Integer apply(SshPollValue input) {
-                                    return 0; // TODO parse out queue depth from output
-                                }}))
-                .poll(new SshPollConfig<Integer>(QUEUE_DEPTH_MESSAGES)
-                        .env(shellEnvironment)
-                        .command(cmd)
-                        .onFailure(Functions.constant(-1))
-                        .onSuccess(new Function<SshPollValue, Integer>() {
-                                @Override public Integer apply(SshPollValue input) {
-                                    return 0; // TODO parse out queue depth from output
-                                }}))
-                .build();
-    }
-    
-    @Override
-    protected void disconnectSensors() {
-        if (sshFeed != null) sshFeed.stop();
-        super.disconnectSensors();
-    }
-    
-    /**
-     * Return the AMQP name for the queue.
-     */
-    public String getQueueName() {
-        return getName();
-    }
-}


[35/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
deleted file mode 100644
index 31f27be..0000000
--- a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
+++ /dev/null
@@ -1,879 +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 brooklyn.util.flags;
-
-import groovy.lang.Closure;
-import groovy.time.TimeDuration;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.net.InetAddress;
-import java.net.URI;
-import java.net.URL;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-
-import javax.annotation.Nullable;
-import javax.annotation.concurrent.GuardedBy;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.api.event.Sensor;
-import org.apache.brooklyn.core.internal.BrooklynInitialization;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.BrooklynTaskTags;
-import brooklyn.entity.basic.ClosureEntityFactory;
-import brooklyn.entity.basic.ConfigurableEntityFactory;
-import brooklyn.entity.basic.ConfigurableEntityFactoryFromEntityFactory;
-import brooklyn.event.basic.Sensors;
-import brooklyn.util.JavaGroovyEquivalents;
-import brooklyn.util.collections.MutableSet;
-import brooklyn.util.collections.QuorumCheck;
-import brooklyn.util.collections.QuorumCheck.QuorumChecks;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.javalang.Enums;
-import brooklyn.util.net.Cidr;
-import brooklyn.util.net.Networking;
-import brooklyn.util.net.UserAndHostAndPort;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.text.StringEscapes.JavaStringEscapes;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-import brooklyn.util.yaml.Yamls;
-
-import com.google.common.base.CaseFormat;
-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.collect.HashBasedTable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-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.collect.Table;
-import com.google.common.net.HostAndPort;
-import com.google.common.primitives.Primitives;
-import com.google.common.reflect.TypeToken;
-
-@SuppressWarnings("rawtypes")
-public class TypeCoercions {
-
-    private static final Logger log = LoggerFactory.getLogger(TypeCoercions.class);
-    
-    private TypeCoercions() {}
-
-    /** Store the coercion {@link Function functions} in a {@link Table table}. */
-    @GuardedBy("TypeCoercions.class")
-    private static Table<Class, Class, Function> registry = HashBasedTable.create();
-
-    /**
-     * Attempts to coerce {@code value} to {@code targetType}.
-     * <p>
-     * Maintains a registry of adapter functions for type pairs in a {@link Table} which
-     * is searched after checking various strategies, including the following:
-     * <ul>
-     * <li>{@code value.asTargetType()}
-     * <li>{@code TargetType.fromType(value)} (if {@code value instanceof Type})
-     * <li>{@code value.targetTypeValue()} (handy for primitives)
-     * <li>{@code TargetType.valueOf(value)} (for enums)
-     * </ul>
-     * <p>
-     * A default set of adapters will handle most common Java-type coercions
-     * as well as <code>String</code> coercion to:
-     * <ul>
-     * <li> {@link Set}, {@link List}, {@link Map} and similar -- parses as YAML
-     * <li> {@link Date} -- parses using {@link Time#parseDate(String)}
-     * <li> {@link Duration} -- parses using {@link Duration#parse(String)}
-     * </ul>
-     */
-    public static <T> T coerce(Object value, Class<T> targetType) {
-        return coerce(value, TypeToken.of(targetType));
-    }
-
-    /** @see #coerce(Object, Class) */
-    public static <T> Maybe<T> tryCoerce(Object value, TypeToken<T> targetTypeToken) {
-        try {
-            return Maybe.of( coerce(value, targetTypeToken) );
-        } catch (Throwable t) {
-            Exceptions.propagateIfFatal(t);
-            return Maybe.absent(t); 
-        }
-    }
-    
-    /** @see #coerce(Object, Class) */
-    @SuppressWarnings({ "unchecked" })
-    public static <T> T coerce(Object value, TypeToken<T> targetTypeToken) {
-        if (value==null) return null;
-        Class<? super T> targetType = targetTypeToken.getRawType();
-
-        //recursive coercion of parameterized collections and map entries
-        if (targetTypeToken.getType() instanceof ParameterizedType) {
-            if (value instanceof Collection && Collection.class.isAssignableFrom(targetType)) {
-                Type[] arguments = ((ParameterizedType) targetTypeToken.getType()).getActualTypeArguments();
-                if (arguments.length != 1) {
-                    throw new IllegalStateException("Unexpected number of parameters in collection type: " + arguments);
-                }
-                Collection coerced = Lists.newLinkedList();
-                TypeToken<?> listEntryType = TypeToken.of(arguments[0]);
-                for (Object entry : (Iterable<?>) value) {
-                    coerced.add(coerce(entry, listEntryType));
-                }
-                if (Set.class.isAssignableFrom(targetType)) {
-                    return (T) Sets.newLinkedHashSet(coerced);
-                } else {
-                    return (T) Lists.newArrayList(coerced);
-                }
-            } else if (value instanceof Map && Map.class.isAssignableFrom(targetType)) {
-                Type[] arguments = ((ParameterizedType) targetTypeToken.getType()).getActualTypeArguments();
-                if (arguments.length != 2) {
-                    throw new IllegalStateException("Unexpected number of parameters in map type: " + arguments);
-                }
-                Map coerced = Maps.newLinkedHashMap();
-                TypeToken<?> mapKeyType = TypeToken.of(arguments[0]);
-                TypeToken<?> mapValueType = TypeToken.of(arguments[1]);
-                for (Map.Entry entry : ((Map<?,?>) value).entrySet()) {
-                    coerced.put(coerce(entry.getKey(), mapKeyType),  coerce(entry.getValue(), mapValueType));
-                }
-                return (T) Maps.newLinkedHashMap(coerced);
-            }
-        }
-
-        if (targetType.isInstance(value)) return (T) value;
-
-        // TODO use registry first?
-
-        //deal with primitive->primitive casting
-        if (isPrimitiveOrBoxer(targetType) && isPrimitiveOrBoxer(value.getClass())) {
-            // Don't just rely on Java to do its normal casting later; if caller writes
-            // long `l = coerce(new Integer(1), Long.class)` then letting java do its casting will fail,
-            // because an Integer will not automatically be unboxed and cast to a long
-            return castPrimitive(value, (Class<T>)targetType);
-        }
-
-        //deal with string->primitive
-        if (value instanceof String && isPrimitiveOrBoxer(targetType)) {
-            return stringToPrimitive((String)value, (Class<T>)targetType);
-        }
-
-        //deal with primitive->string
-        if (isPrimitiveOrBoxer(value.getClass()) && targetType.equals(String.class)) {
-            return (T) value.toString();
-        }
-
-        //look for value.asType where Type is castable to targetType
-        String targetTypeSimpleName = getVerySimpleName(targetType);
-        if (targetTypeSimpleName!=null && targetTypeSimpleName.length()>0) {
-            for (Method m: value.getClass().getMethods()) {
-                if (m.getName().startsWith("as") && m.getParameterTypes().length==0 &&
-                        targetType.isAssignableFrom(m.getReturnType()) ) {
-                    if (m.getName().equals("as"+getVerySimpleName(m.getReturnType()))) {
-                        try {
-                            return (T) m.invoke(value);
-                        } catch (Exception e) {
-                            throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): "+m.getName()+" adapting failed, "+e);
-                        }
-                    }
-                }
-            }
-        }
-        
-        //now look for static TargetType.fromType(Type t) where value instanceof Type  
-        for (Method m: targetType.getMethods()) {
-            if (((m.getModifiers()&Modifier.STATIC)==Modifier.STATIC) && 
-                    m.getName().startsWith("from") && m.getParameterTypes().length==1 &&
-                    m.getParameterTypes()[0].isInstance(value)) {
-                if (m.getName().equals("from"+getVerySimpleName(m.getParameterTypes()[0]))) {
-                    try {
-                        return (T) m.invoke(null, value);
-                    } catch (Exception e) {
-                        throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): "+m.getName()+" adapting failed, "+e);
-                    }
-                }
-            }
-        }
-        
-       //ENHANCEMENT could look in type hierarchy of both types for a conversion method...
-        
-        //primitives get run through again boxed up
-        Class boxedT = UNBOXED_TO_BOXED_TYPES.get(targetType);
-        Class boxedVT = UNBOXED_TO_BOXED_TYPES.get(value.getClass());
-        if (boxedT!=null || boxedVT!=null) {
-            try {
-                if (boxedT==null) boxedT=targetType;
-                Object boxedV;
-                if (boxedVT==null) { boxedV = value; }
-                else { boxedV = boxedVT.getConstructor(value.getClass()).newInstance(value); }
-                return (T) coerce(boxedV, boxedT);
-            } catch (Exception e) {
-                throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): unboxing failed, "+e);
-            }
-        }
-
-        //for enums call valueOf with the string representation of the value
-        if (targetType.isEnum()) {
-            T result = (T) stringToEnum((Class<Enum>) targetType, null).apply(String.valueOf(value));
-            if (result != null) return result;
-        }
-
-        //now look in registry
-        synchronized (TypeCoercions.class) {
-            Map<Class, Function> adapters = registry.row(targetType);
-            for (Map.Entry<Class, Function> entry : adapters.entrySet()) {
-                if (entry.getKey().isInstance(value)) {
-                    T result = (T) entry.getValue().apply(value);
-                    
-                    // Check if need to unwrap again (e.g. if want List<Integer> and are given a String "1,2,3"
-                    // then we'll have so far converted to List.of("1", "2", "3"). Call recursively.
-                    // First check that value has changed, to avoid stack overflow!
-                    if (!Objects.equal(value, result) && targetTypeToken.getType() instanceof ParameterizedType) {
-                        // Could duplicate check for `result instanceof Collection` etc; but recursive call
-                        // will be fine as if that doesn't match we'll safely reach `targetType.isInstance(value)`
-                        // and just return the result.
-                        return coerce(result, targetTypeToken);
-                    }
-                    return result;
-                }
-            }
-        }
-
-        //not found
-        throw new ClassCoercionException("Cannot coerce type "+value.getClass()+" to "+targetType.getCanonicalName()+" ("+value+"): no adapter known");
-    }
-
-    /**
-     * Returns a function that does a type coercion to the given type. For example,
-     * {@code TypeCoercions.function(Double.class)} will return a function that will
-     * coerce its input value to a {@link Double} (or throw a {@link ClassCoercionException}
-     * if that is not possible).
-     */
-    public static <T> Function<Object, T> function(final Class<T> type) {
-        return new CoerceFunction<T>(type);
-    }
-    
-    private static class CoerceFunction<T> implements Function<Object, T> {
-        private final Class<T> type;
-
-        public CoerceFunction(Class<T> type) {
-            this.type = type;
-        }
-        @Override
-        public T apply(Object input) {
-            return coerce(input, type);
-        }
-    }
-
-    /**
-     * Type coercion {@link Function function} for {@link Enum enums}.
-     * <p>
-     * Tries to convert the string to {@link CaseFormat#UPPER_UNDERSCORE} first,
-     * handling all of the different {@link CaseFormat format} possibilites. Failing 
-     * that, it tries a case-insensitive comparison with the valid enum values.
-     * <p>
-     * Returns {@code defaultValue} if the string cannot be converted.
-     *
-     * @see TypeCoercions#coerce(Object, Class)
-     * @see Enum#valueOf(Class, String)
-     */
-    public static <E extends Enum<E>> Function<String, E> stringToEnum(final Class<E> type, @Nullable final E defaultValue) {
-        return new StringToEnumFunction<E>(type, defaultValue);
-    }
-    
-    private static class StringToEnumFunction<E extends Enum<E>> implements Function<String, E> {
-        private final Class<E> type;
-        private final E defaultValue;
-        
-        public StringToEnumFunction(Class<E> type, @Nullable E defaultValue) {
-            this.type = type;
-            this.defaultValue = defaultValue;
-        }
-        @Override
-        public E apply(String input) {
-            Preconditions.checkNotNull(input, "input");
-            List<String> options = ImmutableList.of(
-                    input,
-                    CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, input),
-                    CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_UNDERSCORE, input),
-                    CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, input),
-                    CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, input));
-            for (String value : options) {
-                try {
-                    return Enum.valueOf(type, value);
-                } catch (IllegalArgumentException iae) {
-                    continue;
-                }
-            }
-            Maybe<E> result = Enums.valueOfIgnoreCase(type, input);
-            return (result.isPresent()) ? result.get() : defaultValue;
-        }
-    }
-
-    /**
-     * Sometimes need to explicitly cast primitives, rather than relying on Java casting.
-     * For example, when using generics then type-erasure means it doesn't actually cast,
-     * which causes tests to fail with 0 != 0.0
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> T castPrimitive(Object value, Class<T> targetType) {
-        if (value==null) return null;
-        assert isPrimitiveOrBoxer(targetType) : "targetType="+targetType;
-        assert isPrimitiveOrBoxer(value.getClass()) : "value="+targetType+"; valueType="+value.getClass();
-
-        Class<?> sourceWrapType = Primitives.wrap(value.getClass());
-        Class<?> targetWrapType = Primitives.wrap(targetType);
-        
-        // optimization, for when already correct type
-        if (sourceWrapType == targetWrapType) {
-            return (T) value;
-        }
-        
-        if (targetWrapType == Boolean.class) {
-            // only char can be mapped to boolean
-            // (we could say 0=false, nonzero=true, but there is no compelling use case so better
-            // to encourage users to write as boolean)
-            if (sourceWrapType == Character.class)
-                return (T) stringToPrimitive(value.toString(), targetType);
-            
-            throw new ClassCoercionException("Cannot cast "+sourceWrapType+" ("+value+") to "+targetType);
-        } else if (sourceWrapType == Boolean.class) {
-            // boolean can't cast to anything else
-            
-            throw new ClassCoercionException("Cannot cast "+sourceWrapType+" ("+value+") to "+targetType);
-        }
-        
-        // for whole-numbers (where casting to long won't lose anything)...
-        long v = 0;
-        boolean islong = true;
-        if (sourceWrapType == Character.class) {
-            v = (long) ((Character)value).charValue();
-        } else if (sourceWrapType == Byte.class) {
-            v = (long) ((Byte)value).byteValue();
-        } else if (sourceWrapType == Short.class) {
-            v = (long) ((Short)value).shortValue();
-        } else if (sourceWrapType == Integer.class) {
-            v = (long) ((Integer)value).intValue();
-        } else if (sourceWrapType == Long.class) {
-            v = ((Long)value).longValue();
-        } else {
-            islong = false;
-        }
-        if (islong) {
-            if (targetWrapType == Character.class) return (T) Character.valueOf((char)v); 
-            if (targetWrapType == Byte.class) return (T) Byte.valueOf((byte)v); 
-            if (targetWrapType == Short.class) return (T) Short.valueOf((short)v); 
-            if (targetWrapType == Integer.class) return (T) Integer.valueOf((int)v); 
-            if (targetWrapType == Long.class) return (T) Long.valueOf((long)v); 
-            if (targetWrapType == Float.class) return (T) Float.valueOf((float)v); 
-            if (targetWrapType == Double.class) return (T) Double.valueOf((double)v);
-            throw new IllegalStateException("Unexpected: sourceType="+sourceWrapType+"; targetType="+targetWrapType);
-        }
-        
-        // for real-numbers (cast to double)...
-        double d = 0;
-        boolean isdouble = true;
-        if (sourceWrapType == Float.class) {
-            d = (double) ((Float)value).floatValue();
-        } else if (sourceWrapType == Double.class) {
-            d = (double) ((Double)value).doubleValue();
-        } else {
-            isdouble = false;
-        }
-        if (isdouble) {
-            if (targetWrapType == Character.class) return (T) Character.valueOf((char)d); 
-            if (targetWrapType == Byte.class) return (T) Byte.valueOf((byte)d); 
-            if (targetWrapType == Short.class) return (T) Short.valueOf((short)d); 
-            if (targetWrapType == Integer.class) return (T) Integer.valueOf((int)d); 
-            if (targetWrapType == Long.class) return (T) Long.valueOf((long)d); 
-            if (targetWrapType == Float.class) return (T) Float.valueOf((float)d); 
-            if (targetWrapType == Double.class) return (T) Double.valueOf((double)d);
-            throw new IllegalStateException("Unexpected: sourceType="+sourceWrapType+"; targetType="+targetWrapType);
-        } else {
-            throw new IllegalStateException("Unexpected: sourceType="+sourceWrapType+"; targetType="+targetWrapType);
-        }
-    }
-    
-    public static boolean isPrimitiveOrBoxer(Class<?> type) {
-        return Primitives.allPrimitiveTypes().contains(type) || Primitives.allWrapperTypes().contains(type);
-    }
-    
-    @SuppressWarnings("unchecked")
-    public static <T> T stringToPrimitive(String value, Class<T> targetType) {
-        assert Primitives.allPrimitiveTypes().contains(targetType) || Primitives.allWrapperTypes().contains(targetType) : "targetType="+targetType;
-        // If char, then need to do explicit conversion
-        if (targetType == Character.class || targetType == char.class) {
-            if (value.length() == 1) {
-                return (T) (Character) value.charAt(0);
-            } else if (value.length() != 1) {
-                throw new ClassCoercionException("Cannot coerce type String to "+targetType.getCanonicalName()+" ("+value+"): adapting failed");
-            }
-        }
-        value = value.trim();
-        // For boolean we could use valueOf, but that returns false whereas we'd rather throw errors on bad values
-        if (targetType == Boolean.class || targetType == boolean.class) {
-            if ("true".equalsIgnoreCase(value)) return (T) Boolean.TRUE;
-            if ("false".equalsIgnoreCase(value)) return (T) Boolean.FALSE;
-            if ("yes".equalsIgnoreCase(value)) return (T) Boolean.TRUE;
-            if ("no".equalsIgnoreCase(value)) return (T) Boolean.FALSE;
-            if ("t".equalsIgnoreCase(value)) return (T) Boolean.TRUE;
-            if ("f".equalsIgnoreCase(value)) return (T) Boolean.FALSE;
-            if ("y".equalsIgnoreCase(value)) return (T) Boolean.TRUE;
-            if ("n".equalsIgnoreCase(value)) return (T) Boolean.FALSE;
-            
-            throw new ClassCoercionException("Cannot coerce type String to "+targetType.getCanonicalName()+" ("+value+"): adapting failed"); 
-        }
-        
-        // Otherwise can use valueOf reflectively
-        Class<?> wrappedType;
-        if (Primitives.allPrimitiveTypes().contains(targetType)) {
-            wrappedType = Primitives.wrap(targetType);
-        } else {
-            wrappedType = targetType;
-        }
-        
-        try {
-            return (T) wrappedType.getMethod("valueOf", String.class).invoke(null, value);
-        } catch (Exception e) {
-            ClassCoercionException tothrow = new ClassCoercionException("Cannot coerce "+JavaStringEscapes.wrapJavaString(value)+" to "+targetType.getCanonicalName()+" ("+value+"): adapting failed");
-            tothrow.initCause(e);
-            throw tothrow;
-        }
-    }
-    
-    /** returns the simple class name, and for any inner class the portion after the $ */
-    public static String getVerySimpleName(Class c) {
-        String s = c.getSimpleName();
-        if (s.indexOf('$')>=0)
-            s = s.substring(s.lastIndexOf('$')+1);
-        return s;
-    }
-    public static final Map<Class,Class> BOXED_TO_UNBOXED_TYPES = ImmutableMap.<Class,Class>builder().
-            put(Integer.class, Integer.TYPE).
-            put(Long.class, Long.TYPE).
-            put(Boolean.class, Boolean.TYPE).
-            put(Byte.class, Byte.TYPE).
-            put(Double.class, Double.TYPE).
-            put(Float.class, Float.TYPE).
-            put(Character.class, Character.TYPE).
-            put(Short.class, Short.TYPE).
-            build();
-    public static final Map<Class,Class> UNBOXED_TO_BOXED_TYPES = ImmutableMap.<Class,Class>builder().
-            put(Integer.TYPE, Integer.class).
-            put(Long.TYPE, Long.class).
-            put(Boolean.TYPE, Boolean.class).
-            put(Byte.TYPE, Byte.class).
-            put(Double.TYPE, Double.class).
-            put(Float.TYPE, Float.class).
-            put(Character.TYPE, Character.class).
-            put(Short.TYPE, Short.class).
-            build();
-    
-    /** for automatic conversion */
-    public static Object getMatchingConstructor(Class target, Object ...arguments) {
-        Constructor[] cc = target.getConstructors();
-        for (Constructor c: cc) {
-            if (c.getParameterTypes().length != arguments.length)
-                continue;
-            boolean matches = true;
-            Class[] tt = c.getParameterTypes();
-            for (int i=0; i<tt.length; i++) {
-                if (arguments[i]!=null && !tt[i].isInstance(arguments[i])) {
-                    matches=false;
-                    break;
-                }
-            }
-            if (matches) 
-                return c;
-        }
-        return null;
-    }
-
-    /** Registers an adapter for use with type coercion. Returns any old adapter. */
-    public synchronized static <A,B> Function registerAdapter(Class<A> sourceType, Class<B> targetType, Function<? super A,B> fn) {
-        return registry.put(targetType, sourceType, fn);
-    }
-
-    static { BrooklynInitialization.initTypeCoercionStandardAdapters(); }
-    
-    public static void initStandardAdapters() {
-        registerAdapter(CharSequence.class, String.class, new Function<CharSequence,String>() {
-            @Override
-            public String apply(CharSequence input) {
-                return input.toString();
-            }
-        });
-        registerAdapter(byte[].class, String.class, new Function<byte[],String>() {
-            @Override
-            public String apply(byte[] input) {
-                return new String(input);
-            }
-        });
-        registerAdapter(Collection.class, Set.class, new Function<Collection,Set>() {
-            @SuppressWarnings("unchecked")
-            @Override
-            public Set apply(Collection input) {
-                return Sets.newLinkedHashSet(input);
-            }
-        });
-        registerAdapter(Collection.class, List.class, new Function<Collection,List>() {
-            @SuppressWarnings("unchecked")
-            @Override
-            public List apply(Collection input) {
-                return Lists.newArrayList(input);
-            }
-        });
-        registerAdapter(String.class, InetAddress.class, new Function<String,InetAddress>() {
-            @Override
-            public InetAddress apply(String input) {
-                return Networking.getInetAddressWithFixedName(input);
-            }
-        });
-        registerAdapter(String.class, HostAndPort.class, new Function<String,HostAndPort>() {
-            @Override
-            public HostAndPort apply(String input) {
-                return HostAndPort.fromString(input);
-            }
-        });
-        registerAdapter(String.class, UserAndHostAndPort.class, new Function<String,UserAndHostAndPort>() {
-            @Override
-            public UserAndHostAndPort apply(String input) {
-                return UserAndHostAndPort.fromString(input);
-            }
-        });
-        registerAdapter(String.class, Cidr.class, new Function<String,Cidr>() {
-            @Override
-            public Cidr apply(String input) {
-                return new Cidr(input);
-            }
-        });
-        registerAdapter(String.class, URL.class, new Function<String,URL>() {
-            @Override
-            public URL apply(String input) {
-                try {
-                    return new URL(input);
-                } catch (Exception e) {
-                    throw Exceptions.propagate(e);
-                }
-            }
-        });
-        registerAdapter(String.class, URI.class, new Function<String,URI>() {
-            @Override
-            public URI apply(String input) {
-                return URI.create(input);
-            }
-        });
-        registerAdapter(Closure.class, ConfigurableEntityFactory.class, new Function<Closure,ConfigurableEntityFactory>() {
-            @SuppressWarnings("unchecked")
-            @Override
-            public ConfigurableEntityFactory apply(Closure input) {
-                return new ClosureEntityFactory(input);
-            }
-        });
-        @SuppressWarnings({"unused", "deprecation"})
-        Function<?,?> ignoredVarHereToAllowSuppressDeprecationWarning1 = registerAdapter(brooklyn.entity.basic.EntityFactory.class, ConfigurableEntityFactory.class, new Function<brooklyn.entity.basic.EntityFactory,ConfigurableEntityFactory>() {
-            @SuppressWarnings("unchecked")
-            @Override
-            public ConfigurableEntityFactory apply(brooklyn.entity.basic.EntityFactory input) {
-                if (input instanceof ConfigurableEntityFactory) return (ConfigurableEntityFactory)input;
-                return new ConfigurableEntityFactoryFromEntityFactory(input);
-            }
-        });
-        @SuppressWarnings({"unused", "deprecation"})
-        Function<?,?> ignoredVarHereToAllowSuppressDeprecationWarning2 = registerAdapter(Closure.class, brooklyn.entity.basic.EntityFactory.class, new Function<Closure,brooklyn.entity.basic.EntityFactory>() {
-            @SuppressWarnings("unchecked")
-            @Override
-            public brooklyn.entity.basic.EntityFactory apply(Closure input) {
-                return new ClosureEntityFactory(input);
-            }
-        });
-        registerAdapter(Closure.class, Predicate.class, new Function<Closure,Predicate>() {
-            @Override
-            public Predicate<?> apply(final Closure closure) {
-                return new Predicate<Object>() {
-                    @Override public boolean apply(Object input) {
-                        return (Boolean) closure.call(input);
-                    }
-                };
-            }
-        });
-        registerAdapter(Closure.class, Function.class, new Function<Closure,Function>() {
-            @Override
-            public Function apply(final Closure closure) {
-                return new Function() {
-                    @Override public Object apply(Object input) {
-                        return closure.call(input);
-                    }
-                };
-            }
-        });
-        registerAdapter(Object.class, Duration.class, new Function<Object,Duration>() {
-            @Override
-            public Duration apply(final Object input) {
-                return brooklyn.util.time.Duration.of(input);
-            }
-        });
-        registerAdapter(Object.class, TimeDuration.class, new Function<Object,TimeDuration>() {
-            @SuppressWarnings("deprecation")
-            @Override
-            public TimeDuration apply(final Object input) {
-                log.warn("deprecated automatic coercion of Object to TimeDuration (set breakpoint in TypeCoercions to inspect, convert to Duration)");
-                return JavaGroovyEquivalents.toTimeDuration(input);
-            }
-        });
-        registerAdapter(TimeDuration.class, Long.class, new Function<TimeDuration,Long>() {
-            @Override
-            public Long apply(final TimeDuration input) {
-                log.warn("deprecated automatic coercion of TimeDuration to Long (set breakpoint in TypeCoercions to inspect, use Duration instead of Long!)");
-                return input.toMilliseconds();
-            }
-        });
-        registerAdapter(Integer.class, AtomicLong.class, new Function<Integer,AtomicLong>() {
-            @Override public AtomicLong apply(final Integer input) {
-                return new AtomicLong(input);
-            }
-        });
-        registerAdapter(Long.class, AtomicLong.class, new Function<Long,AtomicLong>() {
-            @Override public AtomicLong apply(final Long input) {
-                return new AtomicLong(input);
-            }
-        });
-        registerAdapter(String.class, AtomicLong.class, new Function<String,AtomicLong>() {
-            @Override public AtomicLong apply(final String input) {
-                return new AtomicLong(Long.parseLong(input.trim()));
-            }
-        });
-        registerAdapter(Integer.class, AtomicInteger.class, new Function<Integer,AtomicInteger>() {
-            @Override public AtomicInteger apply(final Integer input) {
-                return new AtomicInteger(input);
-            }
-        });
-        registerAdapter(String.class, AtomicInteger.class, new Function<String,AtomicInteger>() {
-            @Override public AtomicInteger apply(final String input) {
-                return new AtomicInteger(Integer.parseInt(input.trim()));
-            }
-        });
-        /** This always returns a {@link Double}, cast as a {@link Number}; 
-         * however primitives and boxers get exact typing due to call in #stringToPrimitive */
-        registerAdapter(String.class, Number.class, new Function<String,Number>() {
-            @Override
-            public Number apply(String input) {
-                return Double.valueOf(input);
-            }
-        });
-        registerAdapter(BigDecimal.class, Double.class, new Function<BigDecimal,Double>() {
-            @Override
-            public Double apply(BigDecimal input) {
-                return input.doubleValue();
-            }
-        });
-        registerAdapter(BigInteger.class, Long.class, new Function<BigInteger,Long>() {
-            @Override
-            public Long apply(BigInteger input) {
-                return input.longValue();
-            }
-        });
-        registerAdapter(BigInteger.class, Integer.class, new Function<BigInteger,Integer>() {
-            @Override
-            public Integer apply(BigInteger input) {
-                return input.intValue();
-            }
-        });
-        registerAdapter(String.class, BigDecimal.class, new Function<String,BigDecimal>() {
-            @Override
-            public BigDecimal apply(String input) {
-                return new BigDecimal(input);
-            }
-        });
-        registerAdapter(Double.class, BigDecimal.class, new Function<Double,BigDecimal>() {
-            @Override
-            public BigDecimal apply(Double input) {
-                return BigDecimal.valueOf(input);
-            }
-        });
-        registerAdapter(String.class, BigInteger.class, new Function<String,BigInteger>() {
-            @Override
-            public BigInteger apply(String input) {
-                return new BigInteger(input);
-            }
-        });
-        registerAdapter(Long.class, BigInteger.class, new Function<Long,BigInteger>() {
-            @Override
-            public BigInteger apply(Long input) {
-                return BigInteger.valueOf(input);
-            }
-        });
-        registerAdapter(Integer.class, BigInteger.class, new Function<Integer,BigInteger>() {
-            @Override
-            public BigInteger apply(Integer input) {
-                return BigInteger.valueOf(input);
-            }
-        });
-        registerAdapter(String.class, Date.class, new Function<String,Date>() {
-            @Override
-            public Date apply(final String input) {
-                return Time.parseDate(input);
-            }
-        });
-        registerAdapter(String.class, Class.class, new Function<String,Class>() {
-            @Override
-            public Class apply(final String input) {
-                try {
-                    return Class.forName(input);
-                } catch (ClassNotFoundException e) {
-                    throw Exceptions.propagate(e);
-                }
-            }
-        });
-        registerAdapter(String.class, AttributeSensor.class, new Function<String,AttributeSensor>() {
-            @Override
-            public AttributeSensor apply(final String input) {
-                Entity entity = BrooklynTaskTags.getContextEntity(Tasks.current());
-                if (entity!=null) {
-                    Sensor<?> result = entity.getEntityType().getSensor(input);
-                    if (result instanceof AttributeSensor) 
-                        return (AttributeSensor) result;
-                }
-                return Sensors.newSensor(Object.class, input);
-            }
-        });
-        registerAdapter(String.class, Sensor.class, new Function<String,Sensor>() {
-            @Override
-            public AttributeSensor apply(final String input) {
-                Entity entity = BrooklynTaskTags.getContextEntity(Tasks.current());
-                if (entity!=null) {
-                    Sensor<?> result = entity.getEntityType().getSensor(input);
-                    if (result != null) 
-                        return (AttributeSensor) result;
-                }
-                return Sensors.newSensor(Object.class, input);
-            }
-        });
-        registerAdapter(String.class, List.class, new Function<String,List>() {
-            @Override
-            public List<String> apply(final String input) {
-                return JavaStringEscapes.unwrapJsonishListIfPossible(input);
-            }
-        });
-        registerAdapter(String.class, Set.class, new Function<String,Set>() {
-            @Override
-            public Set<String> apply(final String input) {
-                return MutableSet.copyOf(JavaStringEscapes.unwrapJsonishListIfPossible(input)).asUnmodifiable();
-            }
-        });
-        registerAdapter(String.class, QuorumCheck.class, new Function<String,QuorumCheck>() {
-            @Override
-            public QuorumCheck apply(final String input) {
-                return QuorumChecks.of(input);
-            }
-        });
-        registerAdapter(Iterable.class, String[].class, new Function<Iterable, String[]>() {
-            @Nullable
-            @Override
-            public String[] apply(@Nullable Iterable list) {
-                if (list == null) return null;
-                String[] result = new String[Iterables.size(list)];
-                int count = 0;
-                for (Object element : list) {
-                    result[count++] = coerce(element, String.class);
-                }
-                return result;
-            }
-        });
-        registerAdapter(Iterable.class, Integer[].class, new Function<Iterable, Integer[]>() {
-            @Nullable
-            @Override
-            public Integer[] apply(@Nullable Iterable list) {
-                if (list == null) return null;
-                Integer[] result = new Integer[Iterables.size(list)];
-                int count = 0;
-                for (Object element : list) {
-                    result[count++] = coerce(element, Integer.class);
-                }
-                return result;
-            }
-        });
-        registerAdapter(Iterable.class, int[].class, new Function<Iterable, int[]>() {
-            @Nullable
-            @Override
-            public int[] apply(@Nullable Iterable list) {
-                if (list == null) return null;
-                int[] result = new int[Iterables.size(list)];
-                int count = 0;
-                for (Object element : list) {
-                    result[count++] = coerce(element, int.class);
-                }
-                return result;
-            }
-        });
-        registerAdapter(String.class, Map.class, new Function<String,Map>() {
-            @Override
-            public Map apply(final String input) {
-                Exception error = null;
-                
-                // first try wrapping in braces if needed
-                if (!input.trim().startsWith("{")) {
-                    try {
-                        return apply("{ "+input+" }");
-                    } catch (Exception e) {
-                        Exceptions.propagateIfFatal(e);
-                        // prefer this error
-                        error = e;
-                        // fall back to parsing without braces, e.g. if it's multiline
-                    }
-                }
-
-                try {
-                    return Yamls.getAs( Yamls.parseAll(input), Map.class );
-                } catch (Exception e) {
-                    Exceptions.propagateIfFatal(e);
-                    if (error!=null && input.indexOf('\n')==-1) {
-                        // prefer the original error if it wasn't braced and wasn't multiline
-                        e = error;
-                    }
-                    throw new IllegalArgumentException("Cannot parse string as map with flexible YAML parsing; "+
-                        (e instanceof ClassCastException ? "yaml treats it as a string" : 
-                        (e instanceof IllegalArgumentException && Strings.isNonEmpty(e.getMessage())) ? e.getMessage() :
-                        ""+e) );
-                }
-
-                // NB: previously we supported this also, when we did json above;
-                // yaml support is better as it supports quotes (and better than json because it allows dropping quotes)
-                // snake-yaml, our parser, also accepts key=value -- although i'm not sure this is strictly yaml compliant;
-                // our tests will catch it if snake behaviour changes, and we can reinstate this
-                // (but note it doesn't do quotes; see http://code.google.com/p/guava-libraries/issues/detail?id=412 for that):
-//                return ImmutableMap.copyOf(Splitter.on(",").trimResults().omitEmptyStrings().withKeyValueSeparator("=").split(input));
-            }
-        });
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/http/HttpTool.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/http/HttpTool.java b/core/src/main/java/brooklyn/util/http/HttpTool.java
deleted file mode 100644
index a812cfc..0000000
--- a/core/src/main/java/brooklyn/util/http/HttpTool.java
+++ /dev/null
@@ -1,387 +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 brooklyn.util.http;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-
-import java.net.URI;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.http.ConnectionReuseStrategy;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
-import org.apache.http.NameValuePair;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.Credentials;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpPut;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeSocketFactory;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
-import org.apache.http.conn.ssl.TrustStrategy;
-import org.apache.http.conn.ssl.X509HostnameVerifier;
-import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.client.LaxRedirectStrategy;
-import org.apache.http.message.BasicNameValuePair;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.util.EntityUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.crypto.SslTrustUtils;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.net.URLParamEncoder;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Function;
-import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Multimap;
-
-public class HttpTool {
-
-    private static final Logger LOG = LoggerFactory.getLogger(HttpTool.class);
-
-    /** Apache HTTP commons utility for trusting all.
-     * <p>
-     * For generic java HTTP usage, see {@link SslTrustUtils#trustAll(java.net.URLConnection)} 
-     * and static constants in the same class. */
-    public static class TrustAllStrategy implements TrustStrategy {
-        @Override
-        public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
-            return true;
-        }
-    }
-
-    public static HttpClientBuilder httpClientBuilder() {
-        return new HttpClientBuilder();
-    }
-    
-    public static class HttpClientBuilder {
-        private ClientConnectionManager clientConnectionManager;
-        private HttpParams httpParams;
-        private URI uri;
-        private Integer port;
-        private Credentials credentials;
-        private boolean laxRedirect;
-        private Boolean https;
-        private SchemeSocketFactory socketFactory;
-        private ConnectionReuseStrategy reuseStrategy;
-        private boolean trustAll;
-        private boolean trustSelfSigned;
-
-        public HttpClientBuilder clientConnectionManager(ClientConnectionManager val) {
-            this.clientConnectionManager = checkNotNull(val, "clientConnectionManager");
-            return this;
-        }
-        public HttpClientBuilder httpParams(HttpParams val) {
-            checkState(httpParams == null, "Must not call httpParams multiple times, or after other methods like connectionTimeout");
-            this.httpParams = checkNotNull(val, "httpParams");
-            return this;
-        }
-        public HttpClientBuilder connectionTimeout(Duration val) {
-            if (httpParams == null) httpParams = new BasicHttpParams();
-            long millis = checkNotNull(val, "connectionTimeout").toMilliseconds();
-            if (millis > Integer.MAX_VALUE) throw new IllegalStateException("HttpClient only accepts upto max-int millis for connectionTimeout, but given "+val);
-            HttpConnectionParams.setConnectionTimeout(httpParams, (int) millis);
-            return this;
-        }
-        public HttpClientBuilder socketTimeout(Duration val) {
-            if (httpParams == null) httpParams = new BasicHttpParams();
-            long millis = checkNotNull(val, "socketTimeout").toMilliseconds();
-            if (millis > Integer.MAX_VALUE) throw new IllegalStateException("HttpClient only accepts upto max-int millis for socketTimeout, but given "+val);
-            HttpConnectionParams.setSoTimeout(httpParams, (int) millis);
-            return this;
-        }
-        public HttpClientBuilder reuseStrategy(ConnectionReuseStrategy val) {
-            this.reuseStrategy = checkNotNull(val, "reuseStrategy");
-            return this;
-        }
-        public HttpClientBuilder uri(String val) {
-            return uri(URI.create(checkNotNull(val, "uri")));
-        }
-        public HttpClientBuilder uri(URI val) {
-            this.uri = checkNotNull(val, "uri");
-            if (https == null) https = ("https".equalsIgnoreCase(uri.getScheme()));
-            return this;
-        }
-        public HttpClientBuilder port(int val) {
-            this.port = val;
-            return this;
-        }
-        public HttpClientBuilder credentials(Credentials val) {
-            this.credentials = checkNotNull(val, "credentials");
-            return this;
-        }
-        public void credential(Optional<Credentials> val) {
-            if (val.isPresent()) credentials = val.get();
-        }
-        /** similar to curl --post301 -L` */
-        public HttpClientBuilder laxRedirect(boolean val) {
-            this.laxRedirect = val;
-            return this;
-        }
-        public HttpClientBuilder https(boolean val) {
-            this.https = val;
-            return this;
-        }
-        public HttpClientBuilder socketFactory(SchemeSocketFactory val) {
-            this.socketFactory = checkNotNull(val, "socketFactory");
-            return this;
-        }
-        public HttpClientBuilder trustAll() {
-            this.trustAll = true;
-            return this;
-        }
-        public HttpClientBuilder trustSelfSigned() {
-            this.trustSelfSigned = true;
-            return this;
-        }
-        public HttpClient build() {
-            final DefaultHttpClient httpClient = new DefaultHttpClient(clientConnectionManager);
-            httpClient.setParams(httpParams);
-    
-            // support redirects for POST (similar to `curl --post301 -L`)
-            // http://stackoverflow.com/questions/3658721/httpclient-4-error-302-how-to-redirect
-            if (laxRedirect) {
-                httpClient.setRedirectStrategy(new LaxRedirectStrategy());
-            }
-            if (reuseStrategy != null) {
-                httpClient.setReuseStrategy(reuseStrategy);
-            }
-            if (https == Boolean.TRUE || (uri!=null && uri.toString().startsWith("https:"))) {
-                try {
-                    if (port == null) {
-                        port = (uri != null && uri.getPort() >= 0) ? uri.getPort() : 443;
-                    }
-                    if (socketFactory == null) {
-                        if (trustAll) {
-                            TrustStrategy trustStrategy = new TrustAllStrategy();
-                            X509HostnameVerifier hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
-                            socketFactory = new SSLSocketFactory(trustStrategy, hostnameVerifier);
-                        } else if (trustSelfSigned) {
-                            TrustStrategy trustStrategy = new TrustSelfSignedStrategy();
-                            X509HostnameVerifier hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
-                            socketFactory = new SSLSocketFactory(trustStrategy, hostnameVerifier);
-                        } else {
-                            // Using default https scheme: based on default java truststore, which is pretty strict!
-                        }
-                    }
-                    if (socketFactory != null) {
-                        Scheme sch = new Scheme("https", port, socketFactory);
-                        httpClient.getConnectionManager().getSchemeRegistry().register(sch);
-                    }
-                } catch (Exception e) {
-                    LOG.warn("Error setting trust for uri {}", uri);
-                    throw Exceptions.propagate(e);
-                }
-            }
-    
-            // Set credentials
-            if (uri != null && credentials != null) {
-                String hostname = uri.getHost();
-                int port = uri.getPort();
-                httpClient.getCredentialsProvider().setCredentials(new AuthScope(hostname, port), credentials);
-            }
-            if (uri==null && credentials!=null) {
-                LOG.warn("credentials have no effect in builder unless URI for host is specified");
-            }
-    
-            return httpClient;
-        }
-    }
-
-    protected static abstract class HttpRequestBuilder<B extends HttpRequestBuilder<B, R>, R extends HttpRequest> {
-        protected R req;
-        
-        protected HttpRequestBuilder(R req) {
-            this.req = req;
-        }
-        @SuppressWarnings("unchecked")
-        protected B self() {
-            return (B) this;
-        }
-        public B headers(Map<String,String> headers) {
-            if (headers!=null) {
-                for (Map.Entry<String,String> entry : headers.entrySet()) {
-                    req.addHeader(entry.getKey(), entry.getValue());
-                }
-            }
-            return self();
-        }
-        public B headers(Multimap<String,String> headers) {
-            if (headers!=null) {
-                for (Map.Entry<String,String> entry : headers.entries()) {
-                    req.addHeader(entry.getKey(), entry.getValue());
-                }
-            }
-            return self();
-        }
-        public R build() {
-            return req;
-        }
-    }
-    
-    protected static abstract class HttpEntityEnclosingRequestBaseBuilder<B extends HttpEntityEnclosingRequestBaseBuilder<B,R>, R extends HttpEntityEnclosingRequestBase> extends HttpRequestBuilder<B, R> {
-        protected HttpEntityEnclosingRequestBaseBuilder(R req) {
-            super(req);
-        }
-        public B body(byte[] body) {
-            if (body != null) {
-                HttpEntity httpEntity = new ByteArrayEntity(body);
-                req.setEntity(httpEntity);
-            }
-            return self();
-        }
-    }
-    
-    public static class HttpGetBuilder extends HttpRequestBuilder<HttpGetBuilder, HttpGet> {
-        public HttpGetBuilder(URI uri) {
-            super(new HttpGet(uri));
-        }
-    }
-    
-    public static class HttpHeadBuilder extends HttpRequestBuilder<HttpHeadBuilder, HttpHead> {
-        public HttpHeadBuilder(URI uri) {
-            super(new HttpHead(uri));
-        }
-    }
-    
-    public static class HttpDeleteBuilder extends HttpRequestBuilder<HttpDeleteBuilder, HttpDelete> {
-        public HttpDeleteBuilder(URI uri) {
-            super(new HttpDelete(uri));
-        }
-    }
-    
-    public static class HttpPostBuilder extends HttpEntityEnclosingRequestBaseBuilder<HttpPostBuilder, HttpPost> {
-        HttpPostBuilder(URI uri) {
-            super(new HttpPost(uri));
-        }
-    }
-
-    public static class HttpFormPostBuilder extends HttpRequestBuilder<HttpFormPostBuilder, HttpPost> {
-        HttpFormPostBuilder(URI uri) {
-            super(new HttpPost(uri));
-        }
-
-        public HttpFormPostBuilder params(Map<String, String> params) {
-            if (params != null) {
-                Collection<NameValuePair> httpParams = new ArrayList<NameValuePair>(params.size());
-                for (Entry<String, String> param : params.entrySet()) {
-                    httpParams.add(new BasicNameValuePair(param.getKey(), param.getValue()));
-                }
-                req.setEntity(new UrlEncodedFormEntity(httpParams));
-            }
-            return self();
-        }
-    }
-
-    public static class HttpPutBuilder extends HttpEntityEnclosingRequestBaseBuilder<HttpPutBuilder, HttpPut> {
-        public HttpPutBuilder(URI uri) {
-            super(new HttpPut(uri));
-        }
-    }
-    
-    public static HttpToolResponse httpGet(HttpClient httpClient, URI uri, Map<String,String> headers) {
-        HttpGet req = new HttpGetBuilder(uri).headers(headers).build();
-        return execAndConsume(httpClient, req);
-    }
-
-    public static HttpToolResponse httpPost(HttpClient httpClient, URI uri, Map<String,String> headers, byte[] body) {
-        HttpPost req = new HttpPostBuilder(uri).headers(headers).body(body).build();
-        return execAndConsume(httpClient, req);
-    }
-
-    public static HttpToolResponse httpPut(HttpClient httpClient, URI uri, Map<String, String> headers, byte[] body) {
-        HttpPut req = new HttpPutBuilder(uri).headers(headers).body(body).build();
-        return execAndConsume(httpClient, req);
-    }
-
-    public static HttpToolResponse httpPost(HttpClient httpClient, URI uri, Map<String,String> headers, Map<String, String> params) {
-        HttpPost req = new HttpFormPostBuilder(uri).headers(headers).params(params).build();
-        return execAndConsume(httpClient, req);
-    }
-
-    public static HttpToolResponse httpDelete(HttpClient httpClient, URI uri, Map<String,String> headers) {
-        HttpDelete req = new HttpDeleteBuilder(uri).headers(headers).build();
-        return execAndConsume(httpClient, req);
-    }
-    
-    public static HttpToolResponse httpHead(HttpClient httpClient, URI uri, Map<String,String> headers) {
-        HttpHead req = new HttpHeadBuilder(uri).headers(headers).build();
-        return execAndConsume(httpClient, req);
-    }
-    
-    public static HttpToolResponse execAndConsume(HttpClient httpClient, HttpUriRequest req) {
-        long startTime = System.currentTimeMillis();
-        try {
-            HttpResponse httpResponse = httpClient.execute(req);
-            
-            try {
-                return new HttpToolResponse(httpResponse, startTime);
-            } finally {
-                EntityUtils.consume(httpResponse.getEntity());
-            }
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    
-    public static boolean isStatusCodeHealthy(int code) { return (code>=200 && code<=299); }
-
-    public static String toBasicAuthorizationValue(UsernamePasswordCredentials credentials) {
-        return "Basic "+Base64.encodeBase64String( (credentials.getUserName()+":"+credentials.getPassword()).getBytes() );
-    }
-
-    public static String encodeUrlParams(Map<?,?> data) {
-        if (data==null) return "";
-        Iterable<String> args = Iterables.transform(data.entrySet(), 
-            new Function<Map.Entry<?,?>,String>() {
-            @Override public String apply(Map.Entry<?,?> entry) {
-                Object k = entry.getKey();
-                Object v = entry.getValue();
-                return URLParamEncoder.encode(Strings.toString(k)) + (v != null ? "=" + URLParamEncoder.encode(Strings.toString(v)) : "");
-            }
-        });
-        return Joiner.on("&").join(args);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/http/HttpToolResponse.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/http/HttpToolResponse.java b/core/src/main/java/brooklyn/util/http/HttpToolResponse.java
deleted file mode 100644
index 1837a87..0000000
--- a/core/src/main/java/brooklyn/util/http/HttpToolResponse.java
+++ /dev/null
@@ -1,185 +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 brooklyn.util.http;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.event.feed.http.HttpPollValue;
-import brooklyn.util.guava.Maybe;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Objects;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.google.common.io.ByteStreams;
-
-public class HttpToolResponse implements HttpPollValue {
-
-    private static final Logger log = LoggerFactory.getLogger(HttpToolResponse.class);
-    
-    private final Object mutex = new Object();
-    private final HttpResponse response;
-    private final long startTime;
-    private final long durationMillisOfFirstResponse;
-    private final long durationMillisOfFullContent;
-    private int responseCode;
-    private String reasonPhrase;
-    private Map<String,List<String>> headerLists;
-    private byte[] content;
-
-
-    public HttpToolResponse(HttpResponse response, long startTime) {
-        this.response = response;
-        this.startTime = startTime; 
-        
-        try {
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            HttpEntity entity = response.getEntity();
-            if (entity != null) {
-                entity.getContentLength();
-                durationMillisOfFirstResponse = Duration.sinceUtc(startTime).toMilliseconds();
-
-                ByteStreams.copy(entity.getContent(), out);
-                content = out.toByteArray();
-
-                entity.getContentLength();
-            } else {
-                durationMillisOfFirstResponse = Duration.sinceUtc(startTime).toMilliseconds();
-                content = new byte[0];
-            }
-            durationMillisOfFullContent = Duration.sinceUtc(startTime).toMilliseconds();
-            if (log.isTraceEnabled())
-                log.trace("HttpPollValue latency "+Time.makeTimeStringRounded(durationMillisOfFirstResponse)+" / "+Time.makeTimeStringRounded(durationMillisOfFullContent)+", content size "+content.length);
-        } catch (IOException e) {
-            throw Throwables.propagate(e);
-        }
-    }
-
-    public HttpToolResponse(int responseCode, Map<String,? extends List<String>> headers, byte[] content,
-            long startTime, long durationMillisOfFirstResponse, long durationMillisOfFullContent) {
-        this.response = null;
-        this.responseCode = responseCode;
-        this.headerLists = ImmutableMap.copyOf(headers);
-        this.content = content;
-        this.startTime = startTime;
-        this.durationMillisOfFirstResponse = durationMillisOfFirstResponse;
-        this.durationMillisOfFullContent = durationMillisOfFullContent;
-    }
-    
-    public int getResponseCode() {
-        synchronized (mutex) {
-            if (responseCode == 0) {
-                responseCode = response.getStatusLine().getStatusCode();
-            }
-        }
-        return responseCode;
-    }
-
-    public String getReasonPhrase() {
-        synchronized (mutex) {
-            if (reasonPhrase == null) {
-                reasonPhrase = response.getStatusLine().getReasonPhrase();
-            }
-        }
-        return reasonPhrase;
-    }
-
-    /** returns the timestamp (millis since 1970) when this request was started */ 
-    public long getStartTime() {
-        return startTime;
-    }
-    
-    /** returns latency, in milliseconds, if value was initialized with a start time */
-    public long getLatencyFullContent() {
-        return durationMillisOfFullContent;
-    }
-    
-    /** returns latency, in milliseconds, before response started coming in */
-    public long getLatencyFirstResponse() {
-        return durationMillisOfFirstResponse;
-    }
-    
-    public Map<String, List<String>> getHeaderLists() {
-        synchronized (mutex) {
-            if (headerLists == null) {
-                Map<String, List<String>> headerListsMutable = Maps.newLinkedHashMap();
-                for (Header header : response.getAllHeaders()) {
-                    List<String> vals = headerListsMutable.get(header.getName());
-                    if (vals == null) {
-                        vals = new ArrayList<String>();
-                        headerListsMutable.put(header.getName(), vals);
-                    }
-                    vals.add(header.getValue());
-                }
-                headerLists = Collections.unmodifiableMap(headerListsMutable);
-            }
-        }
-        return headerLists;
-    }
-    
-    public byte[] getContent() {
-        synchronized (mutex) {
-            if (content == null) {
-                InputStream in = null;
-                try {
-                    in = response.getEntity().getContent();
-                    ByteArrayOutputStream out = new ByteArrayOutputStream();
-                    ByteStreams.copy(in, out);
-                    content = out.toByteArray();
-                } catch (IOException e) {
-                    throw Throwables.propagate(e);
-                } finally {
-                    Streams.closeQuietly(in);
-                }
-            }
-        }
-        return content;
-    }
-
-    public String getContentAsString() {
-        return new String(getContent());
-    }
-    
-    public Maybe<HttpResponse> getResponse() {
-        return Maybe.fromNullable(response);
-    }
-
-    @Override
-    public String toString() {
-        return Objects.toStringHelper(getClass())
-                .add("responseCode", responseCode)
-                .toString();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ConfigKeySelfExtracting.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ConfigKeySelfExtracting.java b/core/src/main/java/brooklyn/util/internal/ConfigKeySelfExtracting.java
deleted file mode 100644
index 5048b0e..0000000
--- a/core/src/main/java/brooklyn/util/internal/ConfigKeySelfExtracting.java
+++ /dev/null
@@ -1,41 +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 brooklyn.util.internal;
-
-import java.util.Map;
-
-import org.apache.brooklyn.api.management.ExecutionContext;
-
-import brooklyn.config.ConfigKey;
-
-/** Interface for resolving key values; typically implemented by the config key,
- * but discouraged for external usage.
- */
-public interface ConfigKeySelfExtracting<T> extends ConfigKey<T> {
-
-    /**
-     * Extracts the value for this config key from the given map.
-     */
-    T extractValue(Map<?,?> configMap, ExecutionContext exec);
-
-    /**
-     * @return True if there is an entry in the configMap that could be extracted
-     */
-    boolean isSet(Map<?,?> configMap);
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/Repeater.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/Repeater.java b/core/src/main/java/brooklyn/util/internal/Repeater.java
deleted file mode 100644
index ef149ba..0000000
--- a/core/src/main/java/brooklyn/util/internal/Repeater.java
+++ /dev/null
@@ -1,369 +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 brooklyn.util.internal;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.JavaGroovyEquivalents;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.Callables;
-
-/**
- * Simple DSL to repeat a fragment of code periodically until a condition is satisfied.
- *
- * In its simplest case, it is passed two {@link groovy.lang.Closure}s / {@link Callable} - 
- * the first is executed, then the second. If the second closure returns false, the loop
- * is repeated; if true, it finishes. Further customization can be applied to set the period 
- * between loops and place a maximum limit on how long the loop should run for.
- * <p>
- * It is configured in a <em>fluent</em> manner. For example, in Groovy:
- * <pre>
- * {@code
- * Repeater.create("Wait until the Frobnitzer is ready")
- *     .repeat {
- *         status = frobnitzer.getStatus()
- *     }
- *     .until {
- *         status == "Ready" || status == "Failed"
- *     }
- *     .limitIterationsTo(30)
- *     .run()
- * }
- * </pre>
- * 
- * Or in Java:
- * <pre>
- * {@code
- * Repeater.create("Wait until the Frobnitzer is ready")
- *     .until(new Callable<Boolean>() {
- *              public Boolean call() {
- *                  String status = frobnitzer.getStatus()
- *                  return "Ready".equals(status) || "Failed".equals(status);
- *              }})
- *     .limitIterationsTo(30)
- *     .run()
- * }
- * </pre>
- * 
- * @deprecated since 0.7.0, use {@link brooklyn.util.repeat.Repeater} instead
- */
-@Deprecated
-public class Repeater {
-    
-    // TODO Was converted to Java, from groovy. Needs thorough review and improvements
-    // to use idiomatic java
-    
-    private static final Logger log = LoggerFactory.getLogger(Repeater.class);
-
-    static { TimeExtras.init(); }
-
-    @SetFromFlag
-    private String description;
-    private Callable<?> body = Callables.returning(null);
-    private Callable<Boolean> exitCondition;
-    @SetFromFlag
-    private Long period = null;
-    @SetFromFlag("timeout")
-    private Long durationLimit = null;
-    private int iterationLimit = 0;
-    private boolean rethrowException = false;
-    private boolean rethrowExceptionImmediately = false;
-    private boolean warnOnUnRethrownException = true;
-
-    public Repeater() {
-        this(MutableMap.of(), null);
-    }
-
-    public Repeater(Map<?,?> flags) {
-        this(flags, null);
-    }
-
-    public Repeater(String description) {
-        this(MutableMap.of(), description);
-    }
-    
-    /**
-     * Construct a new instance of Repeater.
-     *
-     * @param flags       can include period, timeout, description
-     * @param description a description of the operation that will appear in debug logs.
-     */
-    public Repeater(Map<?,?> flags, String description) {
-        setFromFlags(flags);
-        this.description = JavaGroovyEquivalents.elvis(description, this.description, "Repeater");
-    }
-
-    public void setFromFlags(Map<?,?> flags) {
-        FlagUtils.setFieldsFromFlags(flags, this);
-    }
-    
-    public static Repeater create() {
-        return create(MutableMap.of());
-    }
-    public static Repeater create(Map<?,?> flags) {
-        return create(flags, null);
-    }
-    public static Repeater create(String description) {
-        return create(MutableMap.of(), description);
-    }
-    public static Repeater create(Map<?,?> flags, String description) {
-        return new Repeater(flags, description);
-    }
-
-    /**
-     * Sets the main body of the loop to be a no-op.
-     * 
-     * @return {@literal this} to aid coding in a fluent style.
-     */
-    public Repeater repeat() {
-        return repeat(Callables.returning(null));
-    }
-    
-    /**
-     * Sets the main body of the loop.
-     *
-     * @param body a closure or other Runnable that is executed in the main body of the loop.
-     * @return {@literal this} to aid coding in a fluent style.
-     */
-    public Repeater repeat(Runnable body) {
-        checkNotNull(body, "body must not be null");
-        this.body = (body instanceof Callable) ? (Callable<?>)body : Executors.callable(body);
-        return this;
-    }
-    
-    /**
-     * Sets the main body of the loop.
-     *
-     * @param body a closure or other Callable that is executed in the main body of the loop.
-     * @return {@literal this} to aid coding in a fluent style.
-     */
-    public Repeater repeat(Callable<?> body) {
-        checkNotNull(body, "body must not be null");
-        this.body = body;
-        return this;
-    }
-
-    /**
-     * Set how long to wait between loop iterations.
-     *
-     * @param period how long to wait between loop iterations.
-     * @param unit the unit of measurement of the period.
-     * @return {@literal this} to aid coding in a fluent style.
-     */
-    public Repeater every(long period, TimeUnit unit) {
-        Preconditions.checkArgument(period > 0, "period must be positive: %s", period);
-        checkNotNull(unit, "unit must not be null");
-        this.period = unit.toMillis(period);
-        return this;
-    }
-
-    /**
-     * @see #every(long, TimeUnit)
-     */
-    public Repeater every(Duration duration) {
-        Preconditions.checkNotNull(duration, "duration must not be null");
-        Preconditions.checkArgument(duration.toMilliseconds()>0, "period must be positive: %s", duration);
-        this.period = duration.toMilliseconds();
-        return this;
-    }
-    
-    public Repeater every(groovy.time.Duration duration) {
-        return every(Duration.of(duration));
-    }
-
-    /**
-     * @see #every(long, TimeUnit)
-     * @deprecated specify unit
-     */
-    public Repeater every(long duration) {
-        return every(duration, TimeUnit.MILLISECONDS);
-    }
-
-    /**
-     * Set code fragment that tests if the loop has completed.
-     *
-     * @param exitCondition a closure or other Callable that returns a boolean. If this code returns {@literal true} then the
-     * loop will stop executing.
-     * @return {@literal this} to aid coding in a fluent style.
-     */
-    public Repeater until(Callable<Boolean> exitCondition) {
-        Preconditions.checkNotNull(exitCondition, "exitCondition must not be null");
-        this.exitCondition = exitCondition;
-        return this;
-    }
-
-    /**
-     * If the exit condition check throws an exception, it will be recorded and the last exception will be thrown on failure.
-     *
-     * @return {@literal this} to aid coding in a fluent style.
-     */
-    public Repeater rethrowException() {
-        this.rethrowException = true;
-        return this;
-    }
-
-    /**
-     * If the repeated body or the exit condition check throws an exception, then propagate that exception immediately.
-     *
-     * @return {@literal this} to aid coding in a fluent style.
-     */
-    public Repeater rethrowExceptionImmediately() {
-        this.rethrowExceptionImmediately = true;
-        return this;
-    }
-
-    public Repeater suppressWarnings() {
-        this.warnOnUnRethrownException = false;
-        return this;
-    }
-
-    /**
-     * Set the maximum number of iterations.
-     *
-     * The loop will exit if the condition has not been satisfied after this number of iterations.
-     *
-     * @param iterationLimit the maximum number of iterations.
-     * @return {@literal this} to aid coding in a fluent style.
-     */
-    public Repeater limitIterationsTo(int iterationLimit) {
-        Preconditions.checkArgument(iterationLimit > 0, "iterationLimit must be positive: %s", iterationLimit);
-        this.iterationLimit = iterationLimit;
-        return this;
-    }
-
-    /**
-     * Set the amount of time to wait for the condition.
-     * The repeater will wait at least this long for the condition to be true,
-     * and will exit soon after even if the condition is false.
-     *
-     * @param deadline the time that the loop should wait.
-     * @param unit the unit of measurement of the period.
-     * @return {@literal this} to aid coding in a fluent style.
-     */
-    public Repeater limitTimeTo(long deadline, TimeUnit unit) {
-        Preconditions.checkArgument(deadline > 0, "deadline must be positive: %s", deadline);
-        Preconditions.checkNotNull(unit, "unit must not be null");
-        this.durationLimit = unit.toMillis(deadline);
-        return this;
-    }
-
-    /**
-     * @see #limitTimeTo(long, TimeUnit)
-     */
-    public Repeater limitTimeTo(Duration duration) {
-        Preconditions.checkNotNull(duration, "duration must not be null");
-        Preconditions.checkArgument(duration.toMilliseconds() > 0, "deadline must be positive: %s", duration);
-        this.durationLimit = duration.toMilliseconds();
-        return this;
-    }
-
-    /**
-     * Run the loop.
-     *
-     * @return true if the exit condition was satisfied; false if the loop terminated for any other reason.
-     */
-    public boolean run() {
-        Preconditions.checkState(body != null, "repeat() method has not been called to set the body");
-        Preconditions.checkState(exitCondition != null, "until() method has not been called to set the exit condition");
-        Preconditions.checkState(period != null, "every() method has not been called to set the loop period time units");
-
-        Throwable lastError = null;
-        int iterations = 0;
-        long endTime = -1;
-        if (durationLimit != null) {
-            endTime = System.currentTimeMillis() + durationLimit;
-        }
-
-        while (true) {
-            iterations++;
-
-            try {
-                body.call();
-            } catch (Exception e) {
-                log.warn(description, e);
-                if (rethrowExceptionImmediately) throw Exceptions.propagate(e);
-            }
-
-            boolean done = false;
-            try {
-                lastError = null;
-                done = exitCondition.call();
-            } catch (Exception e) {
-                if (log.isDebugEnabled()) log.debug(description, e);
-                lastError = e;
-                if (rethrowExceptionImmediately) throw Exceptions.propagate(e);
-            }
-            if (done) {
-                if (log.isDebugEnabled()) log.debug("{}: condition satisfied", description);
-                return true;
-            } else {
-                if (log.isDebugEnabled()) {
-                    String msg = String.format("%s: unsatisfied during iteration %s %s", description, iterations,
-                            (iterationLimit > 0 ? "(max "+iterationLimit+" attempts)" : "") + 
-                            (endTime > 0 ? "("+Time.makeTimeStringRounded(endTime - System.currentTimeMillis())+" remaining)" : ""));
-                    if (iterations == 1) {
-                        log.debug(msg);
-                    } else {
-                        log.trace(msg);
-                    }
-                }
-            }
-
-            if (iterationLimit > 0 && iterations == iterationLimit) {
-                if (log.isDebugEnabled()) log.debug("{}: condition not satisfied and exceeded iteration limit", description);
-                if (rethrowException && lastError != null) {
-                    log.warn("{}: error caught checking condition (rethrowing): {}", description, lastError.getMessage());
-                    throw Exceptions.propagate(lastError);
-                }
-                if (warnOnUnRethrownException && lastError != null)
-                    log.warn("{}: error caught checking condition: {}", description, lastError.getMessage());
-                return false;
-            }
-
-            if (endTime > 0) {
-                if (System.currentTimeMillis() > endTime) {
-                    if (log.isDebugEnabled()) log.debug("{}: condition not satisfied and deadline {} passed", 
-                            description, Time.makeTimeStringRounded(endTime - System.currentTimeMillis()));
-                    if (rethrowException && lastError != null) {
-                        log.error("{}: error caught checking condition: {}", description, lastError.getMessage());
-                        throw Exceptions.propagate(lastError);
-                    }
-                    return false;
-                }
-            }
-
-            Time.sleep(period);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/internal/ssh/BackoffLimitedRetryHandler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/internal/ssh/BackoffLimitedRetryHandler.java b/core/src/main/java/brooklyn/util/internal/ssh/BackoffLimitedRetryHandler.java
deleted file mode 100644
index 1e2b435..0000000
--- a/core/src/main/java/brooklyn/util/internal/ssh/BackoffLimitedRetryHandler.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 brooklyn.util.internal.ssh;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.exceptions.Exceptions;
-
-/**
- * Allow replayable request to be retried a limited number of times, and impose an exponential back-off
- * delay before returning.
- * <p>
- * Copied and modified from jclouds; original author was James Murty
- */
-public class BackoffLimitedRetryHandler {
-
-    private static final Logger LOG = LoggerFactory.getLogger(BackoffLimitedRetryHandler.class);
-
-    private final int retryCountLimit;
-
-    private final long delayStart;
-
-    public BackoffLimitedRetryHandler() {
-        this(5, 50L);
-    }
-    
-    public BackoffLimitedRetryHandler(int retryCountLimit, long delayStart) {
-        this.retryCountLimit = retryCountLimit;
-        this.delayStart = delayStart;
-    }
-    
-    public void imposeBackoffExponentialDelay(int failureCount, String commandDescription) {
-        imposeBackoffExponentialDelay(delayStart, 2, failureCount, retryCountLimit, commandDescription);
-    }
-
-    public void imposeBackoffExponentialDelay(long period, int pow, int failureCount, int max, String commandDescription) {
-        imposeBackoffExponentialDelay(period, period * 10l, pow, failureCount, max, commandDescription);
-    }
-
-    public void imposeBackoffExponentialDelay(long period,
-            long maxPeriod,
-            int pow,
-            int failureCount,
-            int max,
-            String commandDescription) {
-        long delayMs = (long) (period * Math.pow(failureCount, pow));
-        delayMs = (delayMs > maxPeriod) ? maxPeriod : delayMs;
-        if (LOG.isDebugEnabled()) LOG.debug("Retry {}/{}: delaying for {} ms: {}", 
-                new Object[] {failureCount, max, delayMs, commandDescription});
-        try {
-            Thread.sleep(delayMs);
-        } catch (InterruptedException e) {
-            Exceptions.propagate(e);
-        }
-    }
-
-}


[52/64] incubator-brooklyn git commit: brooklyn-software-database: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 07e7f96..c21df9d 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
@@ -33,7 +33,7 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.Effector;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.MethodEffector;
-import brooklyn.entity.database.DatastoreMixins;
+import org.apache.brooklyn.entity.database.DatastoreMixins;
 import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 f779de8..4fcfd2b 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
@@ -32,7 +32,7 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BrooklynConfigKeys;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.database.DatastoreMixins;
+import org.apache.brooklyn.entity.database.DatastoreMixins;
 import brooklyn.entity.java.UsesJavaMXBeans;
 import brooklyn.entity.java.UsesJmx;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 7806979..0e8d343 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
@@ -44,7 +44,7 @@ import com.google.common.collect.ImmutableSet;
 
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.Entities;
-import brooklyn.entity.database.DatastoreMixins;
+import org.apache.brooklyn.entity.database.DatastoreMixins;
 import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
 import brooklyn.entity.java.UsesJmx;
 import brooklyn.entity.software.SshEffectorTasks;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 d82e34b..acea855 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
@@ -27,7 +27,7 @@ import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.database.DatastoreMixins;
+import org.apache.brooklyn.entity.database.DatastoreMixins;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 c9b73e0..705ceca 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
@@ -17,8 +17,8 @@ import brooklyn.enricher.basic.SensorTransformingEnricher;
 import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.mysql.MySqlNode;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.java.JavaEntityMethods;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/usage/archetypes/quickstart/src/brooklyn-sample/src/test/java/com/acme/sample/brooklyn/sample/app/SampleUnitTest.java
----------------------------------------------------------------------
diff --git a/usage/archetypes/quickstart/src/brooklyn-sample/src/test/java/com/acme/sample/brooklyn/sample/app/SampleUnitTest.java b/usage/archetypes/quickstart/src/brooklyn-sample/src/test/java/com/acme/sample/brooklyn/sample/app/SampleUnitTest.java
index df15e0a..537b547 100644
--- a/usage/archetypes/quickstart/src/brooklyn-sample/src/test/java/com/acme/sample/brooklyn/sample/app/SampleUnitTest.java
+++ b/usage/archetypes/quickstart/src/brooklyn-sample/src/test/java/com/acme/sample/brooklyn/sample/app/SampleUnitTest.java
@@ -10,8 +10,8 @@ import org.testng.annotations.Test;
 import org.apache.brooklyn.api.entity.Entity;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
-import brooklyn.entity.database.mysql.MySqlNode;
+import org.apache.brooklyn.entity.database.DatastoreMixins.DatastoreCommon;
+import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.entity.webapp.JavaWebAppService;
 import org.apache.brooklyn.entity.webapp.WebAppService;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/usage/camp/src/test/resources/java-web-app-and-db-with-function-2.yaml
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/java-web-app-and-db-with-function-2.yaml b/usage/camp/src/test/resources/java-web-app-and-db-with-function-2.yaml
index bf90092..1f02444 100644
--- a/usage/camp/src/test/resources/java-web-app-and-db-with-function-2.yaml
+++ b/usage/camp/src/test/resources/java-web-app-and-db-with-function-2.yaml
@@ -34,7 +34,7 @@ services:
         - visitors
         - brooklyn
         - br00k11n
-- serviceType: brooklyn.entity.database.mysql.MySqlNode
+- serviceType: org.apache.brooklyn.entity.database.mysql.MySqlNode
   name: My DB
   id: db
   brooklyn.config:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/usage/camp/src/test/resources/java-web-app-and-db-with-function.yaml
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/java-web-app-and-db-with-function.yaml b/usage/camp/src/test/resources/java-web-app-and-db-with-function.yaml
index 249ab32..0f15729 100644
--- a/usage/camp/src/test/resources/java-web-app-and-db-with-function.yaml
+++ b/usage/camp/src/test/resources/java-web-app-and-db-with-function.yaml
@@ -28,7 +28,7 @@ services:
     java.sysprops: 
       brooklyn.example.db.url: $brooklyn:formatString("jdbc:%s%s?user=%s&password=%s",
          component("db").attributeWhenReady("datastore.url"), "visitors", "brooklyn", "br00k11n")
-- serviceType: brooklyn.entity.database.mysql.MySqlNode
+- serviceType: org.apache.brooklyn.entity.database.mysql.MySqlNode
   id: db
   name: My DB
   location: localhost

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/usage/camp/src/test/resources/java-web-app-and-db-with-policy.yaml
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/java-web-app-and-db-with-policy.yaml b/usage/camp/src/test/resources/java-web-app-and-db-with-policy.yaml
index 671f64a..dd799fc 100644
--- a/usage/camp/src/test/resources/java-web-app-and-db-with-policy.yaml
+++ b/usage/camp/src/test/resources/java-web-app-and-db-with-policy.yaml
@@ -37,7 +37,7 @@ services:
       minPoolSize: 1
       maxPoolSize: 5
       
-- type: brooklyn.entity.database.mysql.MySqlNode
+- type: org.apache.brooklyn.entity.database.mysql.MySqlNode
   id: db
   name: My DB
   location: localhost

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/usage/camp/src/test/resources/test-java-web-app-spec-and-db-with-function.yaml
----------------------------------------------------------------------
diff --git a/usage/camp/src/test/resources/test-java-web-app-spec-and-db-with-function.yaml b/usage/camp/src/test/resources/test-java-web-app-spec-and-db-with-function.yaml
index eb63758..f51f4d7 100644
--- a/usage/camp/src/test/resources/test-java-web-app-spec-and-db-with-function.yaml
+++ b/usage/camp/src/test/resources/test-java-web-app-spec-and-db-with-function.yaml
@@ -32,7 +32,7 @@ services:
         java.sysprops: 
           brooklyn.example.db.url: $brooklyn:formatString("jdbc:%s%s?user=%s\\&password=%s",
              component("db").attributeWhenReady("datastore.url"), "visitors", "brooklyn", "br00k11n")
-- serviceType: brooklyn.entity.database.mysql.MySqlNode
+- serviceType: org.apache.brooklyn.entity.database.mysql.MySqlNode
   id: db
   name: My DB
   brooklyn.config:

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/usage/launcher/src/test/resources/java-web-app-and-db-with-function.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/java-web-app-and-db-with-function.yaml b/usage/launcher/src/test/resources/java-web-app-and-db-with-function.yaml
index 1bf0172..d3c3a04 100644
--- a/usage/launcher/src/test/resources/java-web-app-and-db-with-function.yaml
+++ b/usage/launcher/src/test/resources/java-web-app-and-db-with-function.yaml
@@ -28,7 +28,7 @@ services:
     java.sysprops: 
       brooklyn.example.db.url: $brooklyn:formatString("jdbc:%s%s?user=%s\\&password=%s",
          component("db").attributeWhenReady("datastore.url"), "visitors", "brooklyn", "br00k11n")
-- serviceType: brooklyn.entity.database.mysql.MySqlNode
+- serviceType: org.apache.brooklyn.entity.database.mysql.MySqlNode
   id: db
   name: My DB
   location: localhost

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/usage/launcher/src/test/resources/mssql-test.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/mssql-test.yaml b/usage/launcher/src/test/resources/mssql-test.yaml
index 2b31f74..f8d15a5 100644
--- a/usage/launcher/src/test/resources/mssql-test.yaml
+++ b/usage/launcher/src/test/resources/mssql-test.yaml
@@ -17,7 +17,7 @@
 # under the License.
 #
 
-# Duplicate of software/database/src/main/resources/brooklyn/entity/database/mssql/mssql.yaml,
+# Duplicate of software/database/src/main/resources/org/apache/brooklyn/entity/database/mssql/mssql.yaml,
 # but with template for download url, etc
 
 name: mssql
@@ -35,11 +35,11 @@ services:
 - type: brooklyn.entity.basic.VanillaWindowsProcess
   brooklyn.config:
     templates.install:
-      classpath://brooklyn/entity/database/mssql/ConfigurationFile.ini: "C:\\ConfigurationFile.ini"
-      classpath://brooklyn/entity/database/mssql/installmssql.ps1: "C:\\installmssql.ps1"
-      classpath://brooklyn/entity/database/mssql/configuremssql.ps1: "C:\\configuremssql.ps1"
-      classpath://brooklyn/entity/database/mssql/launchmssql.bat: "C:\\launchmssql.bat"
-      classpath://brooklyn/entity/database/mssql/stopmssql.bat: "C:\\stopmssql.bat"
+      classpath://org/apache/brooklyn/entity/database/mssql/ConfigurationFile.ini: "C:\\ConfigurationFile.ini"
+      classpath://org/apache/brooklyn/entity/database/mssql/installmssql.ps1: "C:\\installmssql.ps1"
+      classpath://org/apache/brooklyn/entity/database/mssql/configuremssql.ps1: "C:\\configuremssql.ps1"
+      classpath://org/apache/brooklyn/entity/database/mssql/launchmssql.bat: "C:\\launchmssql.bat"
+      classpath://org/apache/brooklyn/entity/database/mssql/stopmssql.bat: "C:\\stopmssql.bat"
     install.command: powershell -command "C:\\installmssql.ps1"
     customize.command: powershell -command "C:\\configuremssql.ps1"
     launch.command: "C:\\launchmssql.bat"

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/usage/launcher/src/test/resources/postgres-gce-blueprint.yaml
----------------------------------------------------------------------
diff --git a/usage/launcher/src/test/resources/postgres-gce-blueprint.yaml b/usage/launcher/src/test/resources/postgres-gce-blueprint.yaml
index de4abd0..9f12a3c 100644
--- a/usage/launcher/src/test/resources/postgres-gce-blueprint.yaml
+++ b/usage/launcher/src/test/resources/postgres-gce-blueprint.yaml
@@ -18,5 +18,5 @@
 #
 name: PostgreSQL
 services:
-- serviceType: brooklyn.entity.database.postgresql.PostgreSqlNode
+- serviceType: org.apache.brooklyn.entity.database.postgresql.PostgreSqlNode
   location: gce-europe-west1

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 b5f0cf4..7b44dc5 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
@@ -24,9 +24,9 @@ import java.util.concurrent.Callable;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
-import brooklyn.entity.database.mysql.MySqlNode;
-import brooklyn.entity.database.mysql.MySqlNodeImpl;
-import brooklyn.entity.database.mysql.MySqlSshDriver;
+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 brooklyn.entity.software.SshEffectorTasks;
 import brooklyn.event.feed.function.FunctionFeed;
 import brooklyn.event.feed.function.FunctionPollConfig;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ac1a7c09/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 bc7b2c3..fbfc7c0 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
@@ -32,7 +32,7 @@ import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.StartableApplication;
-import brooklyn.entity.database.mysql.MySqlNode;
+import org.apache.brooklyn.entity.database.mysql.MySqlNode;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.java.JavaEntityMethods;
 import brooklyn.entity.trait.Startable;


[14/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/RepeaterTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/RepeaterTest.groovy b/core/src/test/java/brooklyn/util/internal/RepeaterTest.groovy
deleted file mode 100644
index 65976e1..0000000
--- a/core/src/test/java/brooklyn/util/internal/RepeaterTest.groovy
+++ /dev/null
@@ -1,255 +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 brooklyn.util.internal
-
-import static java.util.concurrent.TimeUnit.*
-import static org.testng.Assert.*
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit
-
-import org.testng.annotations.Test
-
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Stopwatch
-
-public class RepeaterTest {
-    static { TimeExtras.init() }
-
-    @Test
-    public void sanityTest() {
-        new Repeater("Sanity test")
-            .repeat()
-            .until { true }
-            .every(10 * MILLISECONDS);
-    }
-
-    @Test
-    public void sanityTestDescription() {
-        new Repeater()
-            .repeat()
-            .until { true }
-            .every(10 * MILLISECONDS);
-    }
-
-    @Test
-    public void sanityTestBuilder() {
-        Repeater.create("Sanity test")
-            .repeat()
-            .until { true }
-            .every(10 * MILLISECONDS);
-    }
-
-    @Test
-    public void sanityTestBuilderDescription() {
-        Repeater.create()
-            .repeat()
-            .until { true }
-            .every(10 * MILLISECONDS);
-    }
-
-    @Test(expectedExceptions = [ NullPointerException.class ])
-    public void repeatFailsIfClosureIsNull() {
-        new Repeater("repeatFailsIfClosureIsNull").repeat((Callable<?>)null);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test
-    public void repeatSucceedsIfClosureIsNonNull() {
-        new Repeater("repeatSucceedsIfClosureIsNonNull").repeat { true };
-    }
-
-    @Test(expectedExceptions = [ NullPointerException.class ])
-    public void untilFailsIfClosureIsNull() {
-        new Repeater("untilFailsIfClosureIsNull").until(null);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test
-    public void untilSucceedsIfClosureIsNonNull() {
-        new Repeater("untilSucceedsIfClosureIsNonNull").until { true };
-    }
-
-    @Test(expectedExceptions = [ IllegalArgumentException.class ])
-    public void everyFailsIfPeriodIsZero() {
-        new Repeater("everyFailsIfPeriodIsZero").every(0 * MILLISECONDS);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ IllegalArgumentException.class ])
-    public void everyFailsIfPeriodIsNegative() {
-        new Repeater("everyFailsIfPeriodIsNegative").every(-1 * MILLISECONDS);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ NullPointerException.class ])
-    public void everyFailsIfUnitsIsNull() {
-        new Repeater("everyFailsIfUnitsIsNull").every(10, null);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test
-    public void everySucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
-        new Repeater("repeatSucceedsIfClosureIsNonNull").every(10 * MILLISECONDS);
-    }
-
-    @Test(expectedExceptions = [ IllegalArgumentException.class ])
-    public void limitTimeToFailsIfPeriodIsZero() {
-        new Repeater("limitTimeToFailsIfPeriodIsZero").limitTimeTo(0, TimeUnit.MILLISECONDS);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ IllegalArgumentException.class ])
-    public void limitTimeToFailsIfPeriodIsNegative() {
-        new Repeater("limitTimeToFailsIfPeriodIsNegative").limitTimeTo(-1, TimeUnit.MILLISECONDS);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ NullPointerException.class ])
-    public void limitTimeToFailsIfUnitsIsNull() {
-        new Repeater("limitTimeToFailsIfUnitsIsNull").limitTimeTo(10, null);
-        fail "Expected exception was not thrown"
-    }
-
-    @Test
-    public void limitTimeToSucceedsIfPeriodIsPositiveAndUnitsIsNonNull() {
-        new Repeater("limitTimeToSucceedsIfClosureIsNonNull").limitTimeTo(10, TimeUnit.MILLISECONDS);
-    }
-
-    @Test
-    public void everyAcceptsDuration() {
-        new Repeater("everyAcceptsDuration").every(Duration.ONE_SECOND);
-    }
-
-    @Test
-    public void everyAcceptsLong() {
-        new Repeater("everyAcceptsLong").every(1000L);
-    }
-
-    @Test
-    public void everyAcceptsTimeUnit() {
-        new Repeater("everyAcceptsTimeUnit").every(1000000L, TimeUnit.MICROSECONDS);
-    }
-
-    @Test
-    public void runReturnsTrueIfExitConditionIsTrue() {
-        assertTrue new Repeater("runReturnsTrueIfExitConditionIsTrue")
-            .repeat()
-            .every(1 * MILLISECONDS)
-            .until { true }
-            .run();
-    }
-
-    @Test
-    public void runRespectsMaximumIterationLimitAndReturnsFalseIfReached() {
-        int iterations = 0;
-        assertFalse new Repeater("runRespectsMaximumIterationLimitAndReturnsFalseIfReached")
-            .repeat { iterations++ }
-            .every(1 * MILLISECONDS)
-            .until { false }
-            .limitIterationsTo(5)
-            .run();
-        assertEquals 5, iterations;
-    }
-
-    /**
-     * Check that the {@link Repeater} will stop after a time limit.
-     *
-     * The repeater is configured to run every 100ms and never stop until the limit is reached.
-     * This is given as {@link Repeater#limitTimeTo(groovy.time.Duration)} and the execution time
-     * is then checked to ensure it is between 100% and 400% of the specified value. Due to scheduling
-     * delays and other factors in a non RTOS system it is expected that the repeater will take much
-     * longer to exit occasionally.
-     *
-     * @see #runRespectsMaximumIterationLimitAndReturnsFalseIfReached()
-     */
-    @Test(groups="Integration")
-    public void runRespectsTimeLimitAndReturnsFalseIfReached() {
-        final long LIMIT = 2000l;
-        Repeater repeater = new Repeater("runRespectsTimeLimitAndReturnsFalseIfReached")
-            .repeat()
-            .every(100 * MILLISECONDS)
-            .until { false }
-            .limitTimeTo(LIMIT, TimeUnit.MILLISECONDS);
-
-        Stopwatch stopwatch = new Stopwatch().start();
-        boolean result = repeater.run();
-        stopwatch.stop();
-
-        assertFalse result;
-
-        long difference = stopwatch.elapsed(TimeUnit.MILLISECONDS);
-        assertTrue(difference >= LIMIT, "Difference was: " + difference);
-        assertTrue(difference < 4 * LIMIT, "Difference was: " + difference);
-    }
-
-    @Test(expectedExceptions = [ IllegalStateException.class ])
-    public void runFailsIfUntilWasNotSet() {
-        new Repeater("runFailsIfUntilWasNotSet")
-            .repeat()
-            .every(10 * MILLISECONDS)
-            .run();
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ IllegalStateException.class ])
-    public void runFailsIfEveryWasNotSet() {
-        new Repeater("runFailsIfEveryWasNotSet")
-            .repeat()
-            .until { true }
-            .run();
-        fail "Expected exception was not thrown"
-    }
-
-    @Test(expectedExceptions = [ UnsupportedOperationException.class ])
-    public void testRethrowsException() {
-        boolean result = new Repeater("throwRuntimeException")
-            .repeat()
-            .every(10 * MILLISECONDS)
-            .until { throw new UnsupportedOperationException("fail") }
-            .rethrowException()
-            .limitIterationsTo(2)
-            .run();
-        fail "Expected exception was not thrown"
-    }
-
-    @Test
-    public void testNoRethrowsException() {
-        try {
-	        boolean result = new Repeater("throwRuntimeException")
-	            .repeat()
-	            .every(10 * MILLISECONDS)
-	            .until { throw new UnsupportedOperationException("fail") }
-	            .limitIterationsTo(2)
-	            .run();
-	        assertFalse result
-        } catch (RuntimeException re) {
-            fail "Exception should not have been thrown: " + re.getMessage()
-        }
-    }
-	
-	public void testFlags() {
-		int count=0;
-		new Repeater(period: 5*MILLISECONDS, timeout: 100*MILLISECONDS).repeat({ count++ }).until({ count>100}).run();
-		assertTrue count>10
-		assertTrue count<30
-	}
-	
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java b/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java
deleted file mode 100644
index ecb8c7c..0000000
--- a/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java
+++ /dev/null
@@ -1,360 +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 brooklyn.util.internal;
-
-import static org.testng.Assert.assertEquals;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.codehaus.groovy.runtime.GStringImpl;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import brooklyn.entity.basic.Lifecycle;
-import brooklyn.util.collections.MutableSet;
-import brooklyn.util.flags.ClassCoercionException;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.text.StringPredicates;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.reflect.TypeToken;
-
-public class TypeCoercionsTest {
-
-    private static final Logger log = LoggerFactory.getLogger(TypeCoercionsTest.class);
-    
-    @Test
-    public void testCoerceCharSequenceToString() {
-        assertEquals(TypeCoercions.coerce(new StringBuilder("abc"), String.class), "abc");
-        assertEquals(TypeCoercions.coerce(new GStringImpl(new Object[0], new String[0]), String.class), "");
-    }
-    
-    @Test
-    public void testCoerceStringToPrimitive() {
-        assertEquals(TypeCoercions.coerce("1", Character.class), (Character)'1');
-        assertEquals(TypeCoercions.coerce(" ", Character.class), (Character)' ');
-        assertEquals(TypeCoercions.coerce("1", Short.class), (Short)((short)1));
-        assertEquals(TypeCoercions.coerce("1", Integer.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce("1", Long.class), (Long)1l);
-        assertEquals(TypeCoercions.coerce("1", Float.class), (Float)1f);
-        assertEquals(TypeCoercions.coerce("1", Double.class), (Double)1d);
-        assertEquals(TypeCoercions.coerce("true", Boolean.class), (Boolean)true);
-        assertEquals(TypeCoercions.coerce("False", Boolean.class), (Boolean)false);
-        assertEquals(TypeCoercions.coerce("true ", Boolean.class), (Boolean)true);
-
-        assertEquals(TypeCoercions.coerce("1", char.class), (Character)'1');
-        assertEquals(TypeCoercions.coerce("1", short.class), (Short)((short)1));
-        assertEquals(TypeCoercions.coerce("1", int.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce("1", long.class), (Long)1l);
-        assertEquals(TypeCoercions.coerce("1", float.class), (Float)1f);
-        assertEquals(TypeCoercions.coerce("1", double.class), (Double)1d);
-        assertEquals(TypeCoercions.coerce("TRUE", boolean.class), (Boolean)true);
-        assertEquals(TypeCoercions.coerce("false", boolean.class), (Boolean)false);
-    }
-
-    @Test
-    public void testCoercePrimitivesToSameType() {
-        assertEquals(TypeCoercions.coerce('1', Character.class), (Character)'1');
-        assertEquals(TypeCoercions.coerce((short)1, Short.class), (Short)((short)1));
-        assertEquals(TypeCoercions.coerce(1, Integer.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce(1l, Long.class), (Long)1l);
-        assertEquals(TypeCoercions.coerce(1f, Float.class), (Float)1f);
-        assertEquals(TypeCoercions.coerce(1d, Double.class), (Double)1d);
-        assertEquals(TypeCoercions.coerce(true, Boolean.class), (Boolean)true);
-    }
-    
-    @Test
-    public void testCastPrimitives() {
-        assertEquals(TypeCoercions.coerce(1L, Character.class), (Character)(char)1);
-        assertEquals(TypeCoercions.coerce(1L, Byte.class), (Byte)(byte)1);
-        assertEquals(TypeCoercions.coerce(1L, Short.class), (Short)(short)1);
-        assertEquals(TypeCoercions.coerce(1L, Integer.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce(1L, Long.class), (Long)(long)1);
-        assertEquals(TypeCoercions.coerce(1L, Float.class), (Float)(float)1);
-        assertEquals(TypeCoercions.coerce(1L, Double.class), (Double)(double)1);
-        
-        assertEquals(TypeCoercions.coerce(1L, char.class), (Character)(char)1);
-        assertEquals(TypeCoercions.coerce(1L, byte.class), (Byte)(byte)1);
-        assertEquals(TypeCoercions.coerce(1L, short.class), (Short)(short)1);
-        assertEquals(TypeCoercions.coerce(1L, int.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce(1L, long.class), (Long)(long)1);
-        assertEquals(TypeCoercions.coerce(1L, float.class), (Float)(float)1);
-        assertEquals(TypeCoercions.coerce(1L, double.class), (Double)(double)1);
-        
-        assertEquals(TypeCoercions.coerce((char)1, Integer.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce((byte)1, Integer.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce((short)1, Integer.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce((int)1, Integer.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce((long)1, Integer.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce((float)1, Integer.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce((double)1, Integer.class), (Integer)1);
-    }
-    
-    @Test
-    public void testCoercePrimitiveFailures() {
-        // error messages don't have to be this exactly, but they should include sufficient information...
-        assertCoercionFailsWithErrorMatching("maybe", boolean.class, StringPredicates.containsAllLiterals("String", "boolean", "maybe"));
-        assertCoercionFailsWithErrorMatching("NaN", int.class, StringPredicates.containsAllLiterals("int", "NaN"));
-        assertCoercionFailsWithErrorMatching('c', boolean.class, StringPredicates.containsAllLiterals("boolean", "(c)"));  // will say 'string' rather than 'char'
-        assertCoercionFailsWithErrorMatching(0, boolean.class, StringPredicates.containsAllLiterals("Integer", "boolean", "0"));
-    }
-    
-    protected void assertCoercionFailsWithErrorMatching(Object input, Class<?> type, Predicate<? super String> errorMessageRequirement) {
-        try {
-            Object result = TypeCoercions.coerce(input, type);
-            Assert.fail("Should have failed type coercion of "+input+" to "+type+", instead got: "+result);
-        } catch (Exception e) {
-            if (errorMessageRequirement==null || errorMessageRequirement.apply(e.toString()))
-                log.info("Primitive coercion failed as expected, with: "+e);
-            else
-                Assert.fail("Error from type coercion of "+input+" to "+type+" failed with wrong exception; expected match of "+errorMessageRequirement+" but got: "+e);
-        }
-        
-    }
-
-    @Test
-    public void testCastToNumericPrimitives() {
-        assertEquals(TypeCoercions.coerce(BigInteger.ONE, Integer.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce(BigInteger.ONE, int.class), (Integer)1);
-        assertEquals(TypeCoercions.coerce(BigInteger.valueOf(Long.MAX_VALUE), Long.class), (Long)Long.MAX_VALUE);
-        assertEquals(TypeCoercions.coerce(BigInteger.valueOf(Long.MAX_VALUE), long.class), (Long)Long.MAX_VALUE);
-        
-        assertEquals(TypeCoercions.coerce(BigDecimal.valueOf(0.5), Double.class), 0.5d, 0.00001d);
-        assertEquals(TypeCoercions.coerce(BigDecimal.valueOf(0.5), double.class), 0.5d, 0.00001d);
-    }
-
-    @Test
-    public void testCoerceStringToBigNumber() {
-    	assertEquals(TypeCoercions.coerce("0.5", BigDecimal.class), BigDecimal.valueOf(0.5));
-    	assertEquals(TypeCoercions.coerce("1", BigInteger.class), BigInteger.valueOf(1));
-    }
-
-    @Test
-    public void testCoerceStringToEnum() {
-        assertEquals(TypeCoercions.coerce("STARTING", Lifecycle.class), Lifecycle.STARTING);
-        assertEquals(TypeCoercions.coerce("Starting", Lifecycle.class), Lifecycle.STARTING);
-        assertEquals(TypeCoercions.coerce("starting", Lifecycle.class), Lifecycle.STARTING);
-        
-        assertEquals(TypeCoercions.coerce("LOWERCASE", PerverseEnum.class), PerverseEnum.lowercase);
-        assertEquals(TypeCoercions.coerce("CAMELCASE", PerverseEnum.class), PerverseEnum.camelCase);
-        assertEquals(TypeCoercions.coerce("upper", PerverseEnum.class), PerverseEnum.UPPER);
-        assertEquals(TypeCoercions.coerce("upper_with_underscore", PerverseEnum.class), PerverseEnum.UPPER_WITH_UNDERSCORE);
-        assertEquals(TypeCoercions.coerce("LOWER_WITH_UNDERSCORE", PerverseEnum.class), PerverseEnum.lower_with_underscore);
-    }
-    public static enum PerverseEnum {
-        lowercase,
-        camelCase,
-        UPPER,
-        UPPER_WITH_UNDERSCORE,
-        lower_with_underscore;
-    }
-    
-    @Test(expectedExceptions = ClassCoercionException.class)
-    public void testCoerceStringToEnumFailure() {
-        TypeCoercions.coerce("scrambled-eggs", Lifecycle.class);
-    }
-
-    @Test
-    public void testListToSetCoercion() {
-        Set<?> s = TypeCoercions.coerce(ImmutableList.of(1), Set.class);
-        Assert.assertEquals(s, ImmutableSet.of(1));
-    }
-    
-    @Test
-    public void testSetToListCoercion() {
-        List<?> s = TypeCoercions.coerce(ImmutableSet.of(1), List.class);
-        Assert.assertEquals(s, ImmutableList.of(1));
-    }
-    
-    @Test
-    public void testIterableToArrayCoercion() {
-        String[] s = TypeCoercions.coerce(ImmutableList.of("a", "b"), String[].class);
-        Assert.assertTrue(Arrays.equals(s, new String[] {"a", "b"}), "result="+Arrays.toString(s));
-        
-        Integer[] i = TypeCoercions.coerce(ImmutableList.of(1, 2), Integer[].class);
-        Assert.assertTrue(Arrays.equals(i, new Integer[] {1, 2}), "result="+Arrays.toString(i));
-        
-        int[] i2 = TypeCoercions.coerce(ImmutableList.of(1, 2), int[].class);
-        Assert.assertTrue(Arrays.equals(i2, new int[] {1, 2}), "result="+Arrays.toString(i2));
-        
-        int[] i3 = TypeCoercions.coerce(MutableSet.of("1", 2), int[].class);
-        Assert.assertTrue(Arrays.equals(i3, new int[] {1, 2}), "result="+Arrays.toString(i3));
-    }
-
-    @Test
-    public void testListEntryCoercion() {
-        List<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", "java.lang.Double"), new TypeToken<List<Class<?>>>() { });
-        Assert.assertEquals(s, ImmutableList.of(Integer.class, Double.class));
-    }
-    
-    @Test
-    public void testListEntryToSetCoercion() {
-        Set<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", "java.lang.Double"), new TypeToken<Set<Class<?>>>() { });
-        Assert.assertEquals(s, ImmutableSet.of(Integer.class, Double.class));
-    }
-    
-    @Test
-    public void testListEntryToCollectionCoercion() {
-        Collection<?> s = TypeCoercions.coerce(ImmutableList.of("java.lang.Integer", "java.lang.Double"), new TypeToken<Collection<Class<?>>>() { });
-        Assert.assertEquals(s, ImmutableList.of(Integer.class, Double.class));
-    }
-
-    @Test
-    public void testMapValueCoercion() {
-        Map<?,?> s = TypeCoercions.coerce(ImmutableMap.of("int", "java.lang.Integer", "double", "java.lang.Double"), new TypeToken<Map<String, Class<?>>>() { });
-        Assert.assertEquals(s, ImmutableMap.of("int", Integer.class, "double", Double.class));
-    }
-    
-    @Test
-    public void testMapKeyCoercion() {
-        Map<?,?> s = TypeCoercions.coerce(ImmutableMap.of("java.lang.Integer", "int", "java.lang.Double", "double"), new TypeToken<Map<Class<?>, String>>() { });
-        Assert.assertEquals(s, ImmutableMap.of(Integer.class, "int", Double.class, "double"));
-    }
-
-    @Test
-    public void testStringToListCoercion() {
-        List<?> s = TypeCoercions.coerce("a,b,c", List.class);
-        Assert.assertEquals(s, ImmutableList.of("a", "b", "c"));
-    }
-
-    @Test
-    @SuppressWarnings("serial")
-    public void testCoerceRecursivelyStringToGenericsCollection() {
-        assertEquals(TypeCoercions.coerce("1,2", new TypeToken<List<Integer>>() {}), ImmutableList.of(1, 2));
-    }
-    
-    @Test
-    public void testJsonStringToMapCoercion() {
-        Map<?,?> s = TypeCoercions.coerce("{ \"a\" : \"1\", b : 2 }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
-    }
-
-    @Test
-    public void testJsonStringWithoutQuotesToMapCoercion() {
-        Map<?,?> s = TypeCoercions.coerce("{ a : 1 }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 1));
-    }
-
-    @Test
-    public void testJsonComplexTypesToMapCoercion() {
-        Map<?,?> s = TypeCoercions.coerce("{ a : [1, \"2\", '\"3\"'], b: { c: d, 'e': \"f\" } }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", ImmutableList.<Object>of(1, "2", "\"3\""), 
-            "b", ImmutableMap.of("c", "d", "e", "f")));
-    }
-
-    @Test
-    public void testJsonStringWithoutBracesToMapCoercion() {
-        Map<?,?> s = TypeCoercions.coerce("a : 1", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 1));
-    }
-
-    @Test
-    public void testJsonStringWithoutBracesWithMultipleToMapCoercion() {
-        Map<?,?> s = TypeCoercions.coerce("a : 1, b : 2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", 2));
-    }
-
-    @Test
-    public void testKeyEqualsValueStringToMapCoercion() {
-        Map<?,?> s = TypeCoercions.coerce("a=1,b=2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", "2"));
-    }
-
-    @Test(expectedExceptions=IllegalArgumentException.class)
-    public void testJsonStringWithoutBracesOrSpaceDisallowedAsMapCoercion() {
-        // yaml requires spaces after the colon
-        Map<?,?> s = TypeCoercions.coerce("a:1,b:2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", 2));
-    }
-    
-    @Test
-    public void testEqualsInBracesMapCoercion() {
-        Map<?,?> s = TypeCoercions.coerce("{ a = 1, b = '2' }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", 1, "b", "2"));
-    }
-
-    @Test
-    public void testKeyEqualsOrColonValueWithBracesStringToMapCoercion() {
-        Map<?,?> s = TypeCoercions.coerce("{ a=1, b: 2 }", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
-    }
-
-    @Test
-    public void testKeyEqualsOrColonValueWithoutBracesStringToMapCoercion() {
-        Map<?,?> s = TypeCoercions.coerce("a=1, b: 2", Map.class);
-        Assert.assertEquals(s, ImmutableMap.of("a", "1", "b", 2));
-    }
-
-    @Test
-    public void testAs() {
-        Integer x = TypeCoercions.coerce(new WithAs("3"), Integer.class);
-        Assert.assertEquals(x, (Integer)3);
-    }
-
-    @Test
-    public void testFrom() {
-        WithFrom x = TypeCoercions.coerce("3", WithFrom.class);
-        Assert.assertEquals(x.value, 3);
-    }
-
-    @Test
-    public void testCoerceStringToNumber() {
-        assertEquals(TypeCoercions.coerce("1", Number.class), (Number) Double.valueOf(1));
-        assertEquals(TypeCoercions.coerce("1.0", Number.class), (Number) Double.valueOf(1.0));
-    }
-
-    @Test(expectedExceptions = ClassCoercionException.class)
-    public void testInvalidCoercionThrowsClassCoercionException() {
-        TypeCoercions.coerce(new Object(), TypeToken.of(Integer.class));
-    }
-
-    @Test
-    public void testCoercionFunction() {
-        assertEquals(TypeCoercions.function(Double.class).apply("1"), Double.valueOf(1));
-    }
-
-    public static class WithAs {
-        String value;
-        public WithAs(Object x) { value = ""+x; }
-        public Integer asInteger() {
-            return Integer.parseInt(value);
-        }
-    }
-
-    public static class WithFrom {
-        int value;
-        public static WithFrom fromString(String s) {
-            WithFrom result = new WithFrom();
-            result.value = Integer.parseInt(s);
-            return result;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/RecordingSshTool.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/RecordingSshTool.java b/core/src/test/java/brooklyn/util/internal/ssh/RecordingSshTool.java
deleted file mode 100644
index 8c556a6..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/RecordingSshTool.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 brooklyn.util.internal.ssh;
-
-import java.io.File;
-import java.io.InputStream;
-import java.util.List;
-import java.util.Map;
-
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-/** Mock tool */
-public class RecordingSshTool implements SshTool {
-    
-    public static class ExecCmd {
-        public final Map<String,?> props;
-        public final String summaryForLogging;
-        public final List<String> commands;
-        public final Map<?,?> env;
-        
-        ExecCmd(Map<String,?> props, String summaryForLogging, List<String> commands, Map env) {
-            this.props = props;
-            this.summaryForLogging = summaryForLogging;
-            this.commands = commands;
-            this.env = env;
-        }
-        
-        @Override
-        public String toString() {
-            return "ExecCmd["+summaryForLogging+": "+commands+"; "+props+"; "+env+"]";
-        }
-    }
-    
-    public static List<ExecCmd> execScriptCmds = Lists.newCopyOnWriteArrayList();
-    
-    private boolean connected;
-    
-    public RecordingSshTool(Map<?,?> props) {
-    }
-    @Override public void connect() {
-        connected = true;
-    }
-    @Override public void connect(int maxAttempts) {
-        connected = true;
-    }
-    @Override public void disconnect() {
-        connected = false;
-    }
-    @Override public boolean isConnected() {
-        return connected;
-    }
-    @Override public int execScript(Map<String, ?> props, List<String> commands, Map<String, ?> env) {
-        execScriptCmds.add(new ExecCmd(props, "", commands, env));
-        return 0;
-    }
-    @Override public int execScript(Map<String, ?> props, List<String> commands) {
-        return execScript(props, commands, ImmutableMap.<String,Object>of());
-    }
-    @Override public int execCommands(Map<String, ?> props, List<String> commands, Map<String, ?> env) {
-        execScriptCmds.add(new ExecCmd(props, "", commands, env));
-        return 0;
-    }
-    @Override public int execCommands(Map<String, ?> props, List<String> commands) {
-        return execCommands(props, commands, ImmutableMap.<String,Object>of());
-    }
-    @Override public int copyToServer(Map<String, ?> props, File localFile, String pathAndFileOnRemoteServer) {
-        return 0;
-    }
-    @Override public int copyToServer(Map<String, ?> props, InputStream contents, String pathAndFileOnRemoteServer) {
-        return 0;
-    }
-    @Override public int copyToServer(Map<String, ?> props, byte[] contents, String pathAndFileOnRemoteServer) {
-        return 0;
-    }
-    @Override public int copyFromServer(Map<String, ?> props, String pathAndFileOnRemoteServer, File local) {
-        return 0;
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/ShellToolAbstractTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/ShellToolAbstractTest.java b/core/src/test/java/brooklyn/util/internal/ssh/ShellToolAbstractTest.java
deleted file mode 100644
index b8b394b..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/ShellToolAbstractTest.java
+++ /dev/null
@@ -1,439 +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 brooklyn.util.internal.ssh;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Stopwatch;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
-public abstract class ShellToolAbstractTest {
-
-    protected List<ShellTool> tools = Lists.newArrayList();
-    protected List<String> filesCreated;
-    protected String localFilePath;
-    
-    protected ShellTool tool;
-    
-    protected ShellTool newTool() {
-        return newTool(MutableMap.<String,Object>of());
-    }
-    
-    protected ShellTool newTool(Map<String,?> flags) {
-        ShellTool t = newUnregisteredTool(flags);
-        tools.add(t);
-        return t;
-    }
-
-    protected abstract ShellTool newUnregisteredTool(Map<String,?> flags);
-    
-    protected ShellTool tool() { return tool; }
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        localFilePath = "/tmp/ssh-test-local-"+Identifiers.makeRandomId(8);
-        filesCreated = new ArrayList<String>();
-        filesCreated.add(localFilePath);
-
-        tool = newTool();
-        connect(tool);
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void afterMethod() throws Exception {
-        for (ShellTool t : tools) {
-            if (t instanceof SshTool) ((SshTool)t).disconnect();
-        }
-        for (String fileCreated : filesCreated) {
-            new File(fileCreated).delete();
-        }
-    }
-
-    protected static void connect(ShellTool tool) {
-        if (tool instanceof SshTool)
-            ((SshTool)tool).connect();
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecConsecutiveCommands() throws Exception {
-        String out = execScript("echo run1");
-        String out2 = execScript("echo run2");
-        
-        assertTrue(out.contains("run1"), "out="+out);
-        assertTrue(out2.contains("run2"), "out="+out);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecScriptChainOfCommands() throws Exception {
-        String out = execScript("export MYPROP=abc", "echo val is $MYPROP");
-
-        assertTrue(out.contains("val is abc"), "out="+out);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecScriptReturningNonZeroExitCode() throws Exception {
-        int exitcode = tool.execScript(MutableMap.<String,Object>of(), ImmutableList.of("exit 123"));
-        assertEquals(exitcode, 123);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecScriptReturningZeroExitCode() throws Exception {
-        int exitcode = tool.execScript(MutableMap.<String,Object>of(), ImmutableList.of("date"));
-        assertEquals(exitcode, 0);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecScriptCommandWithEnvVariables() throws Exception {
-        String out = execScript(ImmutableList.of("echo val is $MYPROP2"), ImmutableMap.of("MYPROP2", "myval"));
-
-        assertTrue(out.contains("val is myval"), "out="+out);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testScriptDataNotLost() throws Exception {
-        String out = execScript("echo `echo foo``echo bar`");
-
-        assertTrue(out.contains("foobar"), "out="+out);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecScriptWithSleepThenExit() throws Exception {
-        Stopwatch watch = Stopwatch.createStarted();
-        execScript("sleep 1", "exit 0");
-        assertTrue(watch.elapsed(TimeUnit.MILLISECONDS) > 900, "only slept "+Time.makeTimeStringRounded(watch));
-    }
-
-    // Really just tests that it returns; the command will be echo'ed automatically so this doesn't assert the command will have been executed
-    @Test(groups = {"Integration"})
-    public void testExecScriptBigCommand() throws Exception {
-        String bigstring = Strings.repeat("a", 10000);
-        String out = execScript("echo "+bigstring);
-        
-        assertTrue(out.contains(bigstring), "out="+out);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecScriptBigChainOfCommand() throws Exception {
-        String bigstring = Strings.repeat("abcdefghij", 100); // 1KB
-        List<String> cmds = Lists.newArrayList();
-        for (int i = 0; i < 10; i++) {
-            cmds.add("export MYPROP"+i+"="+bigstring);
-            cmds.add("echo val"+i+" is $MYPROP"+i);
-        }
-        String out = execScript(cmds);
-        
-        for (int i = 0; i < 10; i++) {
-            assertTrue(out.contains("val"+i+" is "+bigstring), "out="+out);
-        }
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecScriptAbortsOnCommandFailure() throws Exception {
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        int exitcode = tool.execScript(ImmutableMap.of("out", out), ImmutableList.of("export MYPROP=myval", "acmdthatdoesnotexist", "echo val is $MYPROP"));
-        String outstr = new String(out.toByteArray());
-
-        assertFalse(outstr.contains("val is myval"), "out="+out);
-        assertNotEquals(exitcode,  0);
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testExecScriptWithSleepThenBigCommand() throws Exception {
-        String bigstring = Strings.repeat("abcdefghij", 1000); // 10KB
-        String out = execScript("sleep 2", "export MYPROP="+bigstring, "echo val is $MYPROP");
-        assertTrue(out.contains("val is "+bigstring), "out="+out);
-    }
-    
-    @Test(groups = {"WIP", "Integration"})
-    public void testExecScriptBigConcurrentCommand() throws Exception {
-        ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
-        List<ListenableFuture<?>> futures = new ArrayList<ListenableFuture<?>>();
-        try {
-            for (int i = 0; i < 10; i++) {
-                final ShellTool localtool = newTool();
-                connect(localtool);
-                
-                futures.add(executor.submit(new Runnable() {
-                        public void run() {
-                            String bigstring = Strings.repeat("abcdefghij", 1000); // 10KB
-                            String out = execScript(localtool, ImmutableList.of("export MYPROP="+bigstring, "echo val is $MYPROP"));
-                            assertTrue(out.contains("val is "+bigstring), "outSize="+out.length()+"; out="+out);
-                        }}));
-            }
-            Futures.allAsList(futures).get();
-        } finally {
-            executor.shutdownNow();
-        }
-    }
-
-    @Test(groups = {"WIP", "Integration"})
-    public void testExecScriptBigConcurrentSleepyCommand() throws Exception {
-        ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
-        List<ListenableFuture<?>> futures = new ArrayList<ListenableFuture<?>>();
-        try {
-            long starttime = System.currentTimeMillis();
-            for (int i = 0; i < 10; i++) {
-                final ShellTool localtool = newTool();
-                connect(localtool);
-                
-                futures.add(executor.submit(new Runnable() {
-                        public void run() {
-                            String bigstring = Strings.repeat("abcdefghij", 1000); // 10KB
-                            String out = execScript(localtool, ImmutableList.of("sleep 2", "export MYPROP="+bigstring, "echo val is $MYPROP"));
-                            assertTrue(out.contains("val is "+bigstring), "out="+out);
-                        }}));
-            }
-            Futures.allAsList(futures).get();
-            long runtime = System.currentTimeMillis() - starttime;
-            
-            long OVERHEAD = 20*1000;
-            assertTrue(runtime < 2000+OVERHEAD, "runtime="+runtime);
-            
-        } finally {
-            executor.shutdownNow();
-        }
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecChainOfCommands() throws Exception {
-        String out = execCommands("MYPROP=abc", "echo val is $MYPROP");
-
-        assertEquals(out, "val is abc\n");
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecReturningNonZeroExitCode() throws Exception {
-        int exitcode = tool.execCommands(MutableMap.<String,Object>of(), ImmutableList.of("exit 123"));
-        assertEquals(exitcode, 123);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecReturningZeroExitCode() throws Exception {
-        int exitcode = tool.execCommands(MutableMap.<String,Object>of(), ImmutableList.of("date"));
-        assertEquals(exitcode, 0);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecCommandWithEnvVariables() throws Exception {
-        String out = execCommands(ImmutableList.of("echo val is $MYPROP2"), ImmutableMap.of("MYPROP2", "myval"));
-
-        assertEquals(out, "val is myval\n");
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecBigCommand() throws Exception {
-        String bigstring = Strings.repeat("abcdefghij", 1000); // 10KB
-        String out = execCommands("echo "+bigstring);
-
-        assertEquals(out, bigstring+"\n", "actualSize="+out.length()+"; expectedSize="+bigstring.length());
-    }
-
-    @Test(groups = {"Integration"})
-    public void testExecBigConcurrentCommand() throws Exception {
-        runExecBigConcurrentCommand(10, 0L);
-    }
-    
-    // TODO Fails I believe due to synchronization model in SshjTool of calling connect/disconnect.
-    // Even with a retry-count of 4, it still fails because some commands are calling disconnect
-    // while another concurrently executing command expects to be still connected.
-    @Test(groups = {"Integration", "WIP"})
-    public void testExecBigConcurrentCommandWithStaggeredStart() throws Exception {
-        // This test is to vary the concurrency of concurrent actions
-        runExecBigConcurrentCommand(50, 100L);
-    }
-    
-    protected void runExecBigConcurrentCommand(int numCommands, long staggeredDelayBeforeStart) throws Exception {
-        ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
-        List<ListenableFuture<?>> futures = new ArrayList<ListenableFuture<?>>();
-        try {
-            for (int i = 0; i < numCommands; i++) {
-                long delay = (long) (Math.random() * staggeredDelayBeforeStart);
-                if (i > 0) Time.sleep(delay);
-                
-                futures.add(executor.submit(new Runnable() {
-                        public void run() {
-                            String bigstring = Strings.repeat("abcdefghij", 1000); // 10KB
-                            String out = execCommands("echo "+bigstring);
-                            assertEquals(out, bigstring+"\n", "actualSize="+out.length()+"; expectedSize="+bigstring.length());
-                        }}));
-            }
-            Futures.allAsList(futures).get();
-        } finally {
-            executor.shutdownNow();
-        }
-    }
-
-    // fails if terminal enabled
-    @Test(groups = {"Integration"})
-    @Deprecated // tests deprecated code
-    public void testExecScriptCapturesStderr() throws Exception {
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        ByteArrayOutputStream err = new ByteArrayOutputStream();
-        String nonExistantCmd = "acmdthatdoesnotexist";
-        tool.execScript(ImmutableMap.of("out", out, "err", err), ImmutableList.of(nonExistantCmd));
-        assertTrue(new String(err.toByteArray()).contains(nonExistantCmd+": command not found"), "out="+out+"; err="+err);
-    }
-
-    // fails if terminal enabled
-    @Test(groups = {"Integration"})
-    @Deprecated // tests deprecated code
-    public void testExecCapturesStderr() throws Exception {
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        ByteArrayOutputStream err = new ByteArrayOutputStream();
-        String nonExistantCmd = "acmdthatdoesnotexist";
-        tool.execCommands(ImmutableMap.of("out", out, "err", err), ImmutableList.of(nonExistantCmd));
-        String errMsg = new String(err.toByteArray());
-        assertTrue(errMsg.contains(nonExistantCmd+": command not found\n"), "errMsg="+errMsg+"; out="+out+"; err="+err);
-        
-    }
-
-    @Test(groups = {"Integration"})
-    public void testScriptHeader() {
-        final ShellTool localtool = newTool();
-        String out = execScript(MutableMap.of("scriptHeader", "#!/bin/bash -e\necho hello world\n"), 
-                localtool, Arrays.asList("echo goodbye world"), null);
-        assertTrue(out.contains("goodbye world"), "no goodbye in output: "+out);
-        assertTrue(out.contains("hello world"), "no hello in output: "+out);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testStdErr() {
-        final ShellTool localtool = newTool();
-        Map<String,Object> props = new LinkedHashMap<String, Object>();
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        ByteArrayOutputStream err = new ByteArrayOutputStream();
-        props.put("out", out);
-        props.put("err", err);
-        int exitcode = localtool.execScript(props, Arrays.asList("echo hello err > /dev/stderr"), null);
-        assertFalse(out.toString().contains("hello err"), "hello found where it shouldn't have been, in stdout: "+out);
-        assertTrue(err.toString().contains("hello err"), "no hello in stderr: "+err);
-        assertEquals(0, exitcode);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testRunAsRoot() {
-        final ShellTool localtool = newTool();
-        Map<String,Object> props = new LinkedHashMap<String, Object>();
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        ByteArrayOutputStream err = new ByteArrayOutputStream();
-        props.put("out", out);
-        props.put("err", err);
-        props.put(SshTool.PROP_RUN_AS_ROOT.getName(), true);
-        int exitcode = localtool.execScript(props, Arrays.asList("whoami"), null);
-        assertTrue(out.toString().contains("root"), "not running as root; whoami is: "+out+" (err is '"+err+"')");
-        assertEquals(0, exitcode);
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testExecScriptEchosExecute() throws Exception {
-        String out = execScript("date");
-        assertTrue(out.toString().contains("Executed"), "Executed did not display: "+out);
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testExecScriptEchosDontExecuteWhenToldNoExtraOutput() throws Exception {
-        final ShellTool localtool = newTool();
-        Map<String,Object> props = new LinkedHashMap<String, Object>();
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        ByteArrayOutputStream err = new ByteArrayOutputStream();
-        props.put("out", out);
-        props.put("err", err);
-        props.put(SshTool.PROP_NO_EXTRA_OUTPUT.getName(), true);
-        int exitcode = localtool.execScript(props, Arrays.asList("echo hello world"), null);
-        assertFalse(out.toString().contains("Executed"), "Executed should not have displayed: "+out);
-        assertEquals(out.toString().trim(), "hello world");
-        assertEquals(0, exitcode);
-    }
-    
-    protected String execCommands(String... cmds) {
-        return execCommands(Arrays.asList(cmds));
-    }
-    
-    protected String execCommands(List<String> cmds) {
-        return execCommands(cmds, ImmutableMap.<String,Object>of());
-    }
-
-    protected String execCommands(List<String> cmds, Map<String,?> env) {
-        return execCommands(null, cmds, env);
-    }
-
-    protected String execCommands(ConfigBag config, List<String> cmds, Map<String,?> env) {
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        MutableMap<String,Object> flags = MutableMap.<String,Object>of("out", out);
-        if (config!=null) flags.add(config.getAllConfig());
-        tool.execCommands(flags, cmds, env);
-        return new String(out.toByteArray());
-    }
-
-    protected String execScript(String... cmds) {
-        return execScript(tool, Arrays.asList(cmds));
-    }
-
-    protected String execScript(ShellTool t, List<String> cmds) {
-        return execScript(ImmutableMap.<String,Object>of(), t, cmds, ImmutableMap.<String,Object>of());
-    }
-
-    protected String execScript(List<String> cmds) {
-        return execScript(cmds, ImmutableMap.<String,Object>of());
-    }
-    
-    protected String execScript(List<String> cmds, Map<String,?> env) {
-        return execScript(MutableMap.<String,Object>of(), tool, cmds, env);
-    }
-    
-    protected String execScript(Map<String, ?> props, ShellTool tool, List<String> cmds, Map<String,?> env) {
-        Map<String, Object> props2 = new LinkedHashMap<String, Object>(props);
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        props2.put("out", out);
-        int exitcode = tool.execScript(props2, cmds, env);
-        String outstr = new String(out.toByteArray());
-        assertEquals(exitcode, 0, outstr);
-        return outstr;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/SshToolAbstractIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/SshToolAbstractIntegrationTest.java b/core/src/test/java/brooklyn/util/internal/ssh/SshToolAbstractIntegrationTest.java
deleted file mode 100644
index 84b1029..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/SshToolAbstractIntegrationTest.java
+++ /dev/null
@@ -1,301 +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 brooklyn.util.internal.ssh;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.os.Os;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.io.Files;
-
-/**
- * Test the operation of the {@link SshTool} utility class; to be extended to test concrete implementations.
- * 
- * Requires keys set up, e.g. running:
- * 
- * <pre>
- * cd ~/.ssh
- * ssh-keygen
- * id_rsa_with_passphrase
- * mypassphrase
- * mypassphrase
- * </pre>
- * 
- */
-public abstract class SshToolAbstractIntegrationTest extends ShellToolAbstractTest {
-
-    private static final Logger log = LoggerFactory.getLogger(SshToolAbstractIntegrationTest.class);
-    
-    // FIXME need tests which take properties set in entities and brooklyn.properties;
-    // but not in this class because it is lower level than entities, Aled would argue.
-
-    // TODO No tests for retry logic and exception handing yet
-
-    public static final String SSH_KEY_WITH_PASSPHRASE = System.getProperty("sshPrivateKeyWithPassphrase", "~/.ssh/id_rsa_with_passphrase");
-    public static final String SSH_PASSPHRASE = System.getProperty("sshPrivateKeyPassphrase", "mypassphrase");
-
-    protected String remoteFilePath;
-
-    protected SshTool tool() { return (SshTool)tool; }
-    
-    protected abstract SshTool newUnregisteredTool(Map<String,?> flags);
-
-    @Override
-    protected SshTool newTool() {
-        return newTool(ImmutableMap.of("host", "localhost", "privateKeyFile", "~/.ssh/id_rsa"));
-    }
-    
-    @Override
-    protected SshTool newTool(Map<String,?> flags) {
-        return (SshTool) super.newTool(flags);
-    }
-    
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        super.setUp();
-        remoteFilePath = "/tmp/ssh-test-remote-"+Identifiers.makeRandomId(8);
-        filesCreated.add(remoteFilePath);
-    }
-    
-    protected void assertRemoteFileContents(String remotePath, String expectedContents) {
-        String catout = execCommands("cat "+remotePath);
-        assertEquals(catout, expectedContents);
-    }
-    
-    /**
-     * @param remotePath
-     * @param expectedPermissions Of the form, for example, "-rw-r--r--"
-     */
-    protected void assertRemoteFilePermissions(String remotePath, String expectedPermissions) {
-        String lsout = execCommands("ls -l "+remotePath);
-        assertTrue(lsout.contains(expectedPermissions), lsout);
-    }
-    
-    protected void assertRemoteFileLastModifiedIsNow(String remotePath) {
-        // Check default last-modified time is `now`.
-        // Be lenient in assertion, in case unlucky that clock ticked over to next hour/minute as test was running.
-        // TODO Code could be greatly improved, but low priority!
-        // Output format:
-        //   -rw-r--r--  1   aled  wheel  18  Apr 24  15:03 /tmp/ssh-test-remote-CvFN9zQA
-        //   [0]         [1] [2]   [3]    [4] [5] [6] [7]   [8]
-        
-        String lsout = execCommands("ls -l "+remotePath);
-        
-        String[] lsparts = lsout.split("\\s+");
-        int day = Integer.parseInt(lsparts[6]);
-        int hour = Integer.parseInt(lsparts[7].split(":")[0]);
-        int minute = Integer.parseInt(lsparts[7].split(":")[1]);
-        
-        Calendar expected = Calendar.getInstance();
-        int expectedDay = expected.get(Calendar.DAY_OF_MONTH);
-        int expectedHour = expected.get(Calendar.HOUR_OF_DAY);
-        int expectedMinute = expected.get(Calendar.MINUTE);
-        
-        assertEquals(day, expectedDay, "ls="+lsout+"; lsparts="+Arrays.toString(lsparts)+"; expected="+expected+"; expectedDay="+expectedDay+"; day="+day+"; zone="+expected.getTimeZone());
-        assertTrue(Math.abs(hour - expectedHour) <= 1, "ls="+lsout+"; lsparts="+Arrays.toString(lsparts)+"; expected="+expected+"; expectedHour="+expectedHour+"; hour="+hour+"; zone="+expected.getTimeZone());
-        assertTrue(Math.abs(minute - expectedMinute) <= 1, "ls="+lsout+"; lsparts="+Arrays.toString(lsparts)+"; expected="+expected+"; expectedMinute="+expectedMinute+"; minute="+minute+"; zone="+expected.getTimeZone());
-    }
-
-    @Test(groups = {"Integration"})
-    public void testCopyToServerFromBytes() throws Exception {
-        String contents = "echo hello world!\n";
-        byte[] contentBytes = contents.getBytes();
-        tool().copyToServer(MutableMap.<String,Object>of(), contentBytes, remoteFilePath);
-
-        assertRemoteFileContents(remoteFilePath, contents);
-        assertRemoteFilePermissions(remoteFilePath, "-rw-r--r--");
-        
-        // TODO would like to also assert lastModified time, but on jenkins the jvm locale
-        // and the OS locale are different (i.e. different timezones) so the file time-stamp 
-        // is several hours out.
-        //assertRemoteFileLastModifiedIsNow(remoteFilePath);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testCopyToServerFromInputStream() throws Exception {
-        String contents = "echo hello world!\n";
-        ByteArrayInputStream contentsStream = new ByteArrayInputStream(contents.getBytes());
-        tool().copyToServer(MutableMap.<String,Object>of(), contentsStream, remoteFilePath);
-
-        assertRemoteFileContents(remoteFilePath, contents);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testCopyToServerWithPermissions() throws Exception {
-        tool().copyToServer(ImmutableMap.of("permissions","0754"), "echo hello world!\n".getBytes(), remoteFilePath);
-
-        assertRemoteFilePermissions(remoteFilePath, "-rwxr-xr--");
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testCopyToServerWithLastModifiedDate() throws Exception {
-        long lastModificationTime = 1234567;
-        tool().copyToServer(ImmutableMap.of("lastModificationDate", lastModificationTime), "echo hello world!\n".getBytes(), remoteFilePath);
-
-        String lsout = execCommands("ls -l "+remoteFilePath);//+" | awk '{print \$6 \" \" \$7 \" \" \$8}'"])
-        //execCommands([ "ls -l "+remoteFilePath+" | awk '{print \$6 \" \" \$7 \" \" \$8}'"])
-        //varies depending on timezone
-        assertTrue(lsout.contains("Jan 15  1970") || lsout.contains("Jan 14  1970") || lsout.contains("Jan 16  1970"), lsout);
-        //assertLastModified(lsout, lastModifiedDate)
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testCopyFileToServerWithPermissions() throws Exception {
-        String contents = "echo hello world!\n";
-        Files.write(contents, new File(localFilePath), Charsets.UTF_8);
-        tool().copyToServer(ImmutableMap.of("permissions", "0754"), new File(localFilePath), remoteFilePath);
-
-        assertRemoteFileContents(remoteFilePath, contents);
-
-        String lsout = execCommands("ls -l "+remoteFilePath);
-        assertTrue(lsout.contains("-rwxr-xr--"), lsout);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testCopyFromServer() throws Exception {
-        String contentsWithoutLineBreak = "echo hello world!";
-        String contents = contentsWithoutLineBreak+"\n";
-        tool().copyToServer(MutableMap.<String,Object>of(), contents.getBytes(), remoteFilePath);
-        
-        tool().copyFromServer(MutableMap.<String,Object>of(), remoteFilePath, new File(localFilePath));
-
-        List<String> actual = Files.readLines(new File(localFilePath), Charsets.UTF_8);
-        assertEquals(actual, ImmutableList.of(contentsWithoutLineBreak));
-    }
-    
-    // TODO No config options in sshj or scp for auto-creating the parent directories
-    @Test(enabled=false, groups = {"Integration"})
-    public void testCopyFileToNonExistantDir() throws Exception {
-        String contents = "echo hello world!\n";
-        String remoteFileDirPath = "/tmp/ssh-test-remote-dir-"+Identifiers.makeRandomId(8);
-        String remoteFileInDirPath = remoteFileDirPath + File.separator + "ssh-test-remote-"+Identifiers.makeRandomId(8);
-        filesCreated.add(remoteFileInDirPath);
-        filesCreated.add(remoteFileDirPath);
-        
-        tool().copyToServer(MutableMap.<String,Object>of(), contents.getBytes(), remoteFileInDirPath);
-
-        assertRemoteFileContents(remoteFileInDirPath, contents);
-    }
-    
-
-    @Test(groups = {"Integration"})
-    public void testAllocatePty() {
-        final ShellTool localtool = newTool(MutableMap.of("host", "localhost", SshTool.PROP_ALLOCATE_PTY.getName(), true));
-        Map<String,Object> props = new LinkedHashMap<String, Object>();
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        ByteArrayOutputStream err = new ByteArrayOutputStream();
-        props.put("out", out);
-        props.put("err", err);
-        int exitcode = localtool.execScript(props, Arrays.asList("echo hello err > /dev/stderr"), null);
-        assertTrue(out.toString().contains("hello err"), "no hello in output: "+out+" (err is '"+err+"')");
-        assertFalse(err.toString().contains("hello err"), "hello found in stderr: "+err);
-        assertEquals(0, exitcode);
-    }
-
-    // Requires setting up an extra ssh key, with a passphrase, and adding it to ~/.ssh/authorized_keys
-    @Test(groups = {"Integration"})
-    public void testSshKeyWithPassphrase() throws Exception {
-        final SshTool localtool = newTool(ImmutableMap.<String,Object>builder()
-                .put(SshTool.PROP_HOST.getName(), "localhost")
-                .put(SshTool.PROP_PRIVATE_KEY_FILE.getName(), SSH_KEY_WITH_PASSPHRASE)
-                .put(SshTool.PROP_PRIVATE_KEY_PASSPHRASE.getName(), SSH_PASSPHRASE)
-                .build());
-        localtool.connect();
-        
-        assertEquals(tool.execScript(MutableMap.<String,Object>of(), ImmutableList.of("date")), 0);
-
-        // Also needs the negative test to prove that we're really using an ssh-key with a passphrase
-        try {
-            final SshTool localtool2 = newTool(ImmutableMap.<String,Object>builder()
-                    .put(SshTool.PROP_HOST.getName(), "localhost")
-                    .put(SshTool.PROP_PRIVATE_KEY_FILE.getName(), SSH_KEY_WITH_PASSPHRASE)
-                    .build());
-            localtool2.connect();
-            fail();
-        } catch (Exception e) {
-            SshException se = Exceptions.getFirstThrowableOfType(e, SshException.class);
-            if (se == null) throw e;
-        }
-    }
-
-    @Test(groups = {"Integration"})
-    public void testConnectWithInvalidUserThrowsException() throws Exception {
-        final ShellTool localtool = newTool(ImmutableMap.of("user", "wronguser", "host", "localhost", "privateKeyFile", "~/.ssh/id_rsa"));
-        tools.add(localtool);
-        try {
-            connect(localtool);
-            fail();
-        } catch (SshException e) {
-            if (!e.toString().contains("failed to connect")) throw e;
-        }
-    }
-
-    @Test(groups = {"Integration"})
-    public void testOutputAsExpected() throws Exception {
-        final String CONTENTS = "hello world\n"
-            + "bye bye\n";
-        execCommands("cat > "+Os.mergePaths(Os.tmp(), "test1")+" << X\n"
-            + CONTENTS
-            + "X\n");
-        String read = execCommands("echo START_FOO", "cat "+Os.mergePaths(Os.tmp(), "test1"), "echo END_FOO");
-        log.debug("read back data written, as:\n"+read);
-        String contents = Strings.getFragmentBetween(read, "START_FOO", "END_FOO");
-        Assert.assertEquals(CONTENTS.trim(), contents.trim());
-    }
-
-    @Test(groups = {"Integration"})
-    public void testScriptDirPropertiesIsRespected() {
-        // For explanation of (some of) the magic behind this command, see http://stackoverflow.com/a/229606/68898
-        final String command = "if [[ \"$0\" == \"/var/tmp/\"* ]]; then true; else false; fi";
-
-        SshTool sshTool = newTool(ImmutableMap.<String, Object>builder()
-                .put(SshTool.PROP_HOST.getName(), "localhost")
-                .build());
-        int rc = sshTool.execScript(ImmutableMap.<String, Object>builder()
-                .put(SshTool.PROP_SCRIPT_DIR.getName(), "/var/tmp")
-                .build(), ImmutableList.of(command));
-        assertEquals(rc, 0);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/SshToolAbstractPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/SshToolAbstractPerformanceTest.java b/core/src/test/java/brooklyn/util/internal/ssh/SshToolAbstractPerformanceTest.java
deleted file mode 100644
index be1441a..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/SshToolAbstractPerformanceTest.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 brooklyn.util.internal.ssh;
-
-import java.io.ByteArrayOutputStream;
-import java.lang.management.ManagementFactory;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-import javax.management.MBeanServer;
-import javax.management.ObjectName;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.ImmutableList;
-
-/**
- * Test the performance of different variants of invoking the sshj tool.
- * 
- * Intended for human-invocation and inspection, to see which parts are most expensive.
- */
-public abstract class SshToolAbstractPerformanceTest {
-
-    private static final Logger LOG = LoggerFactory.getLogger(SshToolAbstractPerformanceTest.class);
-    
-    private SshTool tool;
-    
-    protected abstract SshTool newSshTool(Map<String,?> flags);
-    
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (tool != null) tool.disconnect();
-    }
-
-    @Test(groups = {"Integration"})
-    public void testConsecutiveConnectAndDisconnect() throws Exception {
-        Runnable task = new Runnable() {
-            public void run() {
-                tool = newSshTool(MutableMap.of("host", "localhost"));
-                tool.connect();
-                tool.disconnect();
-            }
-        };
-        runMany(task, "connect-disconnect", 10);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testConsecutiveSmallCommands() throws Exception {
-        runExecManyCommands(ImmutableList.of("true"), false, "small-cmd", 10);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testConsecutiveSmallCommandsWithStdouterr() throws Exception {
-        runExecManyCommands(ImmutableList.of("true"), true, "small-cmd-with-stdout", 10);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testConsecutiveBigStdoutCommands() throws Exception {
-        runExecManyCommands(ImmutableList.of("head -c 100000 /dev/urandom"), true, "big-stdout", 10);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testConsecutiveBigStdinCommands() throws Exception {
-        String bigstr = Identifiers.makeRandomId(100000);
-        runExecManyCommands(ImmutableList.of("echo "+bigstr+" | wc -c"), true, "big-stdin", 10);
-    }
-
-    private void runExecManyCommands(final List<String> cmds, final boolean captureOutAndErr, String context, int iterations) throws Exception {
-        Runnable task = new Runnable() {
-                @Override public void run() {
-                    execScript(cmds, captureOutAndErr);
-                }};
-        runMany(task, context, iterations);
-    }
-
-    private void runMany(Runnable task, String context, int iterations) throws Exception {
-        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
-        ObjectName osMBeanName = ObjectName.getInstance(ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME);
-        long preCpuTime = (Long) mbeanServer.getAttribute(osMBeanName, "ProcessCpuTime");
-        Stopwatch stopwatch = Stopwatch.createStarted();
-        
-        for (int i = 0; i < iterations; i++) {
-            task.run();
-            
-            long postCpuTime = (Long) mbeanServer.getAttribute(osMBeanName, "ProcessCpuTime");
-            long elapsedTime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
-            double fractionCpu = (elapsedTime > 0) ? ((double)postCpuTime-preCpuTime) / TimeUnit.MILLISECONDS.toNanos(elapsedTime) : -1;
-            LOG.info("Executing {}; completed {}; took {}; fraction cpu {}", new Object[] {context, (i+1), Time.makeTimeStringRounded(elapsedTime), fractionCpu});
-        }
-    }
-
-    private int execScript(List<String> cmds, boolean captureOutandErr) {
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        ByteArrayOutputStream err = new ByteArrayOutputStream();
-        MutableMap<String,?> flags = (captureOutandErr) ? MutableMap.of("out", out, "err", err) : MutableMap.<String,Object>of();
-        
-        tool = newSshTool(MutableMap.of("host", "localhost"));
-        tool.connect();
-        int result = tool.execScript(flags, cmds);
-        tool.disconnect();
-        
-        int outlen = out.toByteArray().length;
-        int errlen = out.toByteArray().length;
-        if (LOG.isTraceEnabled()) LOG.trace("Executed: result={}; stdout={}; stderr={}", new Object[] {result, outlen, errlen});
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/cli/SshCliToolIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/cli/SshCliToolIntegrationTest.java b/core/src/test/java/brooklyn/util/internal/ssh/cli/SshCliToolIntegrationTest.java
deleted file mode 100644
index c8640e7..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/cli/SshCliToolIntegrationTest.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 brooklyn.util.internal.ssh.cli;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.io.ByteArrayOutputStream;
-import java.util.Arrays;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.internal.ssh.SshException;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.internal.ssh.SshToolAbstractIntegrationTest;
-import brooklyn.util.internal.ssh.cli.SshCliTool;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-/**
- * Test the operation of the {@link SshJschTool} utility class.
- */
-public class SshCliToolIntegrationTest extends SshToolAbstractIntegrationTest {
-
-    private static final Logger log = LoggerFactory.getLogger(SshCliToolIntegrationTest.class);
-    
-    protected SshTool newUnregisteredTool(Map<String,?> flags) {
-        return new SshCliTool(flags);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testFlags() throws Exception {
-        final SshTool localtool = newTool(ImmutableMap.of("sshFlags", "-vvv -tt", "host", "localhost"));
-        tools.add(localtool);
-        try {
-            localtool.connect();
-            Map<String,Object> props = new LinkedHashMap<String, Object>();
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            ByteArrayOutputStream err = new ByteArrayOutputStream();
-            props.put("out", out);
-            props.put("err", err);
-            int exitcode = localtool.execScript(props, Arrays.asList("echo hello err > /dev/stderr"), null);
-            Assert.assertEquals(0, exitcode, "exitCode="+exitcode+", but expected 0");
-            log.debug("OUT from ssh -vvv command is: "+out);
-            log.debug("ERR from ssh -vvv command is: "+err);
-            assertFalse(err.toString().contains("hello err"), "hello found where it shouldn't have been, in stderr (should have been tty merged to stdout): "+err);
-            assertTrue(out.toString().contains("hello err"), "no hello in stdout: "+err);
-            // look for word 'ssh' to confirm we got verbose output
-            assertTrue(err.toString().toLowerCase().contains("ssh"), "no mention of ssh in stderr: "+err);
-        } catch (SshException e) {
-            if (!e.toString().contains("failed to connect")) throw e;
-        }
-    }
-
-    // Need to have at least one test method here (rather than just inherited) for eclipse to recognize it
-    @Test(enabled = false)
-    public void testDummy() throws Exception {
-    }
-    
-    // TODO When running mvn on the command line (for Aled), this test hangs when prompting for a password (but works in the IDE!)
-    // Doing .connect() isn't enough; need to cause ssh or scp to be invoked
-    @Test(enabled=false, groups = {"Integration"})
-    public void testConnectWithInvalidUserThrowsException() throws Exception {
-        final SshTool localtool = newTool(ImmutableMap.of("user", "wronguser", "host", "localhost", "privateKeyFile", "~/.ssh/id_rsa"));
-        tools.add(localtool);
-        try {
-            localtool.connect();
-            int result = localtool.execScript(ImmutableMap.<String,Object>of(), ImmutableList.of("date"));
-            fail("exitCode="+result+", but expected exception");
-        } catch (SshException e) {
-            if (!e.toString().contains("failed to connect")) throw e;
-        }
-    }
-    
-    // TODO ssh-cli doesn't support pass-phrases yet
-    @Test(enabled=false, groups = {"Integration"})
-    public void testSshKeyWithPassphrase() throws Exception {
-        super.testSshKeyWithPassphrase();
-    }
-
-    // Setting last modified date not yet supported for cli-based ssh
-    @Override
-    @Test(enabled=false, groups = {"Integration"})
-    public void testCopyToServerWithLastModifiedDate() throws Exception {
-        super.testCopyToServerWithLastModifiedDate();
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testExecReturningNonZeroExitCode() throws Exception {
-        int exitcode = tool.execCommands(MutableMap.<String,Object>of(), ImmutableList.of("exit 123"));
-        assertEquals(exitcode, 123);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/cli/SshCliToolPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/cli/SshCliToolPerformanceTest.java b/core/src/test/java/brooklyn/util/internal/ssh/cli/SshCliToolPerformanceTest.java
deleted file mode 100644
index 4d2ba20..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/cli/SshCliToolPerformanceTest.java
+++ /dev/null
@@ -1,44 +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 brooklyn.util.internal.ssh.cli;
-
-import java.util.Map;
-
-import org.testng.annotations.Test;
-
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.internal.ssh.SshToolAbstractPerformanceTest;
-
-/**
- * Test the performance of different variants of invoking the sshj tool.
- * 
- * Intended for human-invocation and inspection, to see which parts are most expensive.
- */
-public class SshCliToolPerformanceTest extends SshToolAbstractPerformanceTest {
-
-    @Override
-    protected SshTool newSshTool(Map<String,?> flags) {
-        return new SshCliTool(flags);
-    }
-    
-    // Need to have at least one test method here (rather than just inherited) for eclipse to recognize it
-    @Test(enabled = false)
-    public void testDummy() throws Exception {
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/process/ProcessToolIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/process/ProcessToolIntegrationTest.java b/core/src/test/java/brooklyn/util/internal/ssh/process/ProcessToolIntegrationTest.java
deleted file mode 100644
index 64054ba..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/process/ProcessToolIntegrationTest.java
+++ /dev/null
@@ -1,69 +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 brooklyn.util.internal.ssh.process;
-
-import static org.testng.Assert.assertTrue;
-
-import java.util.Arrays;
-import java.util.Map;
-
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.internal.ssh.ShellToolAbstractTest;
-
-/**
- * Test the operation of the {@link ProcessTool} utility class.
- */
-public class ProcessToolIntegrationTest extends ShellToolAbstractTest {
-
-    @Override
-    protected ProcessTool newUnregisteredTool(Map<String,?> flags) {
-        return new ProcessTool(flags);
-    }
-
-    // ones here included as *non*-integration tests. must run on windows and linux.
-    // (also includes integration tests from parent)
-
-    @Test(groups="UNIX")
-    public void testPortableCommand() throws Exception {
-        String out = execScript("echo hello world");
-        assertTrue(out.contains("hello world"), "out="+out);
-    }
-
-    @Test(groups="Integration")
-    public void testLoginShell() {
-        // this detection scheme only works for commands; can't test whether it works for scripts without 
-        // requiring stuff in bash_profile / profile / etc, which gets hard to make portable;
-        // it is nearly the same code path on the impl so this is probably enough 
-        
-        final String LOGIN_SHELL_CHECK = "shopt -q login_shell && echo 'yes, login shell' || echo 'no, not login shell'";
-        ConfigBag config = ConfigBag.newInstance().configure(ProcessTool.PROP_NO_EXTRA_OUTPUT, true);
-        String out;
-        
-        out = execCommands(config, Arrays.asList(LOGIN_SHELL_CHECK), null);
-        Assert.assertEquals(out.trim(), "no, not login shell", "out = "+out);
-        
-        config.configure(ProcessTool.PROP_LOGIN_SHELL, true);
-        out = execCommands(config, Arrays.asList(LOGIN_SHELL_CHECK), null);
-        Assert.assertEquals(out.trim(), "yes, login shell", "out = "+out);
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/process/ProcessToolStaticsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/process/ProcessToolStaticsTest.java b/core/src/test/java/brooklyn/util/internal/ssh/process/ProcessToolStaticsTest.java
deleted file mode 100644
index 787c776..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/process/ProcessToolStaticsTest.java
+++ /dev/null
@@ -1,79 +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 brooklyn.util.internal.ssh.process;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.util.Arrays;
-import java.util.List;
-
-import org.testng.Assert;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.os.Os;
-
-public class ProcessToolStaticsTest {
-
-    ByteArrayOutputStream out;
-    ByteArrayOutputStream err;
-    
-    @BeforeMethod(alwaysRun=true)
-    public void clear() {
-        out = new ByteArrayOutputStream();
-        err = new ByteArrayOutputStream();
-    }
-    
-    private List<String> getTestCommand() {
-        if(Os.isMicrosoftWindows()) {
-            return Arrays.asList("cmd", "/c", "echo", "hello", "world");
-        } else {
-            return Arrays.asList("echo", "hello", "world");
-        }
-    }
-
-    @Test
-    public void testRunsWithStdout() throws Exception {
-        int code = ProcessTool.execSingleProcess(getTestCommand(), null, (File)null, out, err, this);
-        Assert.assertEquals(err.toString().trim(), "");
-        Assert.assertEquals(out.toString().trim(), "hello world");
-        Assert.assertEquals(code, 0);
-    }
-
-    @Test(groups="Integration") // *nix only
-    public void testRunsWithBashEnvVarAndStderr() throws Exception {
-        int code = ProcessTool.execSingleProcess(Arrays.asList("/bin/bash", "-c", "echo hello $NAME | tee /dev/stderr"), 
-                MutableMap.of("NAME", "BOB"), (File)null, out, err, this);
-        Assert.assertEquals(err.toString().trim(), "hello BOB", "err is: "+err);
-        Assert.assertEquals(out.toString().trim(), "hello BOB", "out is: "+out);
-        Assert.assertEquals(code, 0);
-    }
-
-    @Test(groups="Integration") // *nix only
-    public void testRunsManyCommandsWithBashEnvVarAndStderr() throws Exception {
-        int code = ProcessTool.execProcesses(Arrays.asList("echo hello $NAME", "export NAME=JOHN", "echo goodbye $NAME | tee /dev/stderr"), 
-                MutableMap.of("NAME", "BOB"), (File)null, out, err, " ; ", false, this);
-        Assert.assertEquals(err.toString().trim(), "goodbye JOHN", "err is: "+err);
-        Assert.assertEquals(out.toString().trim(), "hello BOB\ngoodbye JOHN", "out is: "+out);
-        Assert.assertEquals(code, 0);
-    }
-
-
-}


[44/64] incubator-brooklyn git commit: brooklyn-software-messaging: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.java
new file mode 100644
index 0000000..dcd249b
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQEc2LiveTest.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.entity.messaging.activemq;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import javax.jms.Connection;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.activemq.ActiveMQConnectionFactory;
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import brooklyn.entity.trait.Startable;
+
+import com.google.common.collect.ImmutableList;
+
+public class ActiveMQEc2LiveTest extends AbstractEc2LiveTest {
+
+    /**
+     * Test that can install+start, and use, ActiveMQ.
+     */
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        String queueName = "testQueue";
+        int number = 10;
+        String content = "01234567890123456789012345678901";
+
+        // Start broker with a configured queue
+        ActiveMQBroker activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class).configure("queue", queueName));
+        
+        app.start(ImmutableList.of(loc));
+        
+        EntityTestUtils.assertAttributeEqualsEventually(activeMQ, Startable.SERVICE_UP, true);
+
+        // Check queue created
+        assertEquals(ImmutableList.copyOf(activeMQ.getQueueNames()), ImmutableList.of(queueName));
+        assertEquals(activeMQ.getChildren().size(), 1);
+        assertEquals(activeMQ.getQueues().size(), 1);
+
+        // Get the named queue entity
+        ActiveMQQueue queue = activeMQ.getQueues().get(queueName);
+        assertNotNull(queue);
+
+        // Connect to broker using JMS and send messages
+        Connection connection = getActiveMQConnection(activeMQ);
+        clearQueue(connection, queueName);
+        EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, 0);
+        sendMessages(connection, number, queueName, content);
+
+        // Check messages arrived
+        EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, number);
+
+        connection.close();
+    }
+
+    private Connection getActiveMQConnection(ActiveMQBroker activeMQ) throws Exception {
+        int port = activeMQ.getAttribute(ActiveMQBroker.OPEN_WIRE_PORT);
+        String address = activeMQ.getAttribute(ActiveMQBroker.ADDRESS);
+        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(String.format("tcp://%s:%s", address, port));
+        Connection connection = factory.createConnection("admin", "activemq");
+        connection.start();
+        return connection;
+    }
+
+    private void sendMessages(Connection connection, int count, String queueName, String content) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        org.apache.activemq.command.ActiveMQQueue destination = (org.apache.activemq.command.ActiveMQQueue) session.createQueue(queueName);
+        MessageProducer messageProducer = session.createProducer(destination);
+
+        for (int i = 0; i < count; i++) {
+            TextMessage message = session.createTextMessage(content);
+            messageProducer.send(message);
+        }
+
+        session.close();
+    }
+
+    private int clearQueue(Connection connection, String queueName) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        org.apache.activemq.command.ActiveMQQueue destination = (org.apache.activemq.command.ActiveMQQueue) session.createQueue(queueName);
+        MessageConsumer messageConsumer = session.createConsumer(destination);
+
+        int received = 0;
+        while (messageConsumer.receive(500) != null) received++;
+
+        session.close();
+
+        return received;
+    }
+    
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQGoogleComputeLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQGoogleComputeLiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQGoogleComputeLiveTest.java
new file mode 100644
index 0000000..6ed13ec
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQGoogleComputeLiveTest.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.entity.messaging.activemq;
+
+import brooklyn.entity.AbstractGoogleComputeLiveTest;
+import brooklyn.entity.trait.Startable;
+
+import com.google.common.collect.ImmutableList;
+
+import org.apache.activemq.ActiveMQConnectionFactory;
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.testng.annotations.Test;
+
+import javax.jms.Connection;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+public class ActiveMQGoogleComputeLiveTest extends AbstractGoogleComputeLiveTest {
+
+    /**
+     * Test that can install+start, and use, ActiveMQ.
+     */
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        String queueName = "testQueue";
+        int number = 10;
+        String content = "01234567890123456789012345678901";
+
+        // Start broker with a configured queue
+        ActiveMQBroker activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class).configure("queue", queueName));
+        
+        app.start(ImmutableList.of(loc));
+        
+        EntityTestUtils.assertAttributeEqualsEventually(activeMQ, Startable.SERVICE_UP, true);
+
+        // Check queue created
+        assertEquals(ImmutableList.copyOf(activeMQ.getQueueNames()), ImmutableList.of(queueName));
+        assertEquals(activeMQ.getChildren().size(), 1);
+        assertEquals(activeMQ.getQueues().size(), 1);
+
+        // Get the named queue entity
+        ActiveMQQueue queue = activeMQ.getQueues().get(queueName);
+        assertNotNull(queue);
+
+        // Connect to broker using JMS and send messages
+        Connection connection = getActiveMQConnection(activeMQ);
+        clearQueue(connection, queueName);
+        EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, 0);
+        sendMessages(connection, number, queueName, content);
+
+        // Check messages arrived
+        EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, number);
+
+        connection.close();
+    }
+
+    private Connection getActiveMQConnection(ActiveMQBroker activeMQ) throws Exception {
+        int port = activeMQ.getAttribute(ActiveMQBroker.OPEN_WIRE_PORT);
+        String address = activeMQ.getAttribute(ActiveMQBroker.ADDRESS);
+        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(String.format("tcp://%s:%s", address, port));
+        Connection connection = factory.createConnection("admin", "activemq");
+        connection.start();
+        return connection;
+    }
+
+    private void sendMessages(Connection connection, int count, String queueName, String content) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        org.apache.activemq.command.ActiveMQQueue destination = (org.apache.activemq.command.ActiveMQQueue) session.createQueue(queueName);
+        MessageProducer messageProducer = session.createProducer(destination);
+
+        for (int i = 0; i < count; i++) {
+            TextMessage message = session.createTextMessage(content);
+            messageProducer.send(message);
+        }
+
+        session.close();
+    }
+
+    private int clearQueue(Connection connection, String queueName) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        org.apache.activemq.command.ActiveMQQueue destination = (org.apache.activemq.command.ActiveMQQueue) session.createQueue(queueName);
+        MessageConsumer messageConsumer = session.createConsumer(destination);
+
+        int received = 0;
+        while (messageConsumer.receive(500) != null) received++;
+
+        session.close();
+
+        return received;
+    }
+    
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.java
new file mode 100644
index 0000000..26980c7
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQIntegrationTest.java
@@ -0,0 +1,258 @@
+/*
+ * 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.entity.messaging.activemq;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import javax.jms.Connection;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.activemq.ActiveMQConnectionFactory;
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.test.entity.TestApplication;
+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 brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.java.UsesJmx;
+import brooklyn.entity.java.UsesJmx.JmxAgentModes;
+import brooklyn.entity.trait.Startable;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test the operation of the {@link ActiveMQBroker} class.
+ */
+public class ActiveMQIntegrationTest {
+    private static final Logger log = LoggerFactory.getLogger(ActiveMQIntegrationTest.class);
+
+    private TestApplication app;
+    private Location testLocation;
+    private ActiveMQBroker activeMQ;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setup() throws Exception {
+        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        testLocation = app.newLocalhostProvisioningLocation();
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void shutdown() throws Exception {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    /**
+     * Test that the broker starts up and sets SERVICE_UP correctly.
+     */
+    @Test(groups = "Integration")
+    public void canStartupAndShutdown() throws Exception {
+        activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class));
+
+        activeMQ.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ, Startable.SERVICE_UP, true);
+        log.info("JMX URL is "+activeMQ.getAttribute(UsesJmx.JMX_URL));
+        activeMQ.stop();
+        assertFalse(activeMQ.getAttribute(Startable.SERVICE_UP));
+    }
+
+    /**
+     * Test that the broker starts up and sets SERVICE_UP correctly,
+     * when a jmx port is supplied
+     */
+    @Test(groups = "Integration")
+    public void canStartupAndShutdownWithCustomJmx() throws Exception {
+        activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class)
+            .configure("jmxPort", "11099+"));
+       
+        activeMQ.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ, Startable.SERVICE_UP, true);
+        log.info("JMX URL is "+activeMQ.getAttribute(UsesJmx.JMX_URL));
+        activeMQ.stop();
+        assertFalse(activeMQ.getAttribute(Startable.SERVICE_UP));
+    }
+
+    @Test(groups = "Integration")
+    public void canStartupAndShutdownWithCustomBrokerName() throws Exception {
+        activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class)
+            .configure("jmxPort", "11099+")
+            .configure("brokerName", "bridge"));
+
+        activeMQ.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ, Startable.SERVICE_UP, true);
+        log.info("JMX URL is "+activeMQ.getAttribute(UsesJmx.JMX_URL));
+        activeMQ.stop();
+        assertFalse(activeMQ.getAttribute(Startable.SERVICE_UP));
+    }
+
+    
+    @Test(groups = "Integration")
+    public void canStartTwo() throws Exception {
+        ActiveMQBroker activeMQ1 = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class));
+        ActiveMQBroker activeMQ2 = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class));
+
+        activeMQ1.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ1, Startable.SERVICE_UP, true);
+        log.info("JMX URL is "+activeMQ1.getAttribute(UsesJmx.JMX_URL));
+
+        activeMQ2.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ2, Startable.SERVICE_UP, true);
+        log.info("JMX URL is "+activeMQ2.getAttribute(UsesJmx.JMX_URL));
+    }
+
+    /**
+     * Test that setting the 'queue' property causes a named queue to be created.
+     */
+    @Test(groups = "Integration")
+    public void testCreatingQueuesDefault() throws Exception {
+        String url = testCreatingQueuesInternal(null);
+        // localhost default is jmxmp
+        Assert.assertTrue(url.contains("jmxmp"), "url="+url);
+    }
+
+    @Test(groups = "Integration")
+    public void testCreatingQueuesRmi() throws Exception {
+        String url = testCreatingQueuesInternal(JmxAgentModes.JMX_RMI_CUSTOM_AGENT);
+        Assert.assertTrue(url.contains("rmi://"), "url="+url);
+        Assert.assertFalse(url.contains("rmi:///jndi"), "url="+url);
+        Assert.assertFalse(url.contains("jmxmp"), "url="+url);
+    }
+
+    @Test(groups = "Integration")
+    public void testCreatingQueuesJmxmp() throws Exception {
+        String url = testCreatingQueuesInternal(JmxAgentModes.JMXMP);
+        // localhost default is rmi
+        Assert.assertTrue(url.contains("jmxmp"), "url="+url);
+        Assert.assertFalse(url.contains("rmi"), "url="+url);
+    }
+
+    @Test(groups = "Integration")
+    public void testCreatingQueuesNoAgent() throws Exception {
+        String url = testCreatingQueuesInternal(JmxAgentModes.NONE);
+        // localhost default is rmi
+        Assert.assertTrue(url.contains("service:jmx:rmi"), "url="+url);
+        Assert.assertFalse(url.contains("jmxmp"), "url="+url);
+    }
+
+    public String testCreatingQueuesInternal(JmxAgentModes mode) throws Exception {
+        String queueName = "testQueue";
+        int number = 20;
+        String content = "01234567890123456789012345678901";
+
+        // Start broker with a configured queue
+        // FIXME Not yet using app.createAndManageChild because later in test do activeMQ.queueNames,
+        // which is not on interface
+        activeMQ = app.createAndManageChild(EntitySpec.create(ActiveMQBroker.class)
+            .configure("queue", queueName)
+            .configure(UsesJmx.JMX_AGENT_MODE, mode));
+        
+        activeMQ.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 10*60*1000), activeMQ, Startable.SERVICE_UP, true);
+
+        String jmxUrl = activeMQ.getAttribute(UsesJmx.JMX_URL);
+        log.info("JMX URL ("+mode+") is "+jmxUrl);
+        
+        try {
+            // Check queue created
+            assertFalse(activeMQ.getQueueNames().isEmpty());
+            assertEquals(activeMQ.getQueueNames().size(), 1);
+            assertTrue(activeMQ.getQueueNames().contains(queueName));
+            assertEquals(activeMQ.getChildren().size(), 1);
+            assertFalse(activeMQ.getQueues().isEmpty());
+            assertEquals(activeMQ.getQueues().size(), 1);
+
+            // Get the named queue entity
+            ActiveMQQueue queue = activeMQ.getQueues().get(queueName);
+            assertNotNull(queue);
+            assertEquals(queue.getName(), queueName);
+
+            // Connect to broker using JMS and send messages
+            Connection connection = getActiveMQConnection(activeMQ);
+            clearQueue(connection, queueName);
+            EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, 0);
+            sendMessages(connection, number, queueName, content);
+            // Check messages arrived
+            EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, number);
+
+            // Clear the messages
+            assertEquals(clearQueue(connection, queueName), number);
+
+            // Check messages cleared
+            EntityTestUtils.assertAttributeEqualsEventually(queue, ActiveMQQueue.QUEUE_DEPTH_MESSAGES, 0);
+
+            connection.close();
+
+            // Close the JMS connection
+        } finally {
+            // Stop broker
+            activeMQ.stop();
+        }
+        
+        return jmxUrl;
+    }
+
+    private Connection getActiveMQConnection(ActiveMQBroker activeMQ) throws Exception {
+        int port = activeMQ.getAttribute(ActiveMQBroker.OPEN_WIRE_PORT);
+        String address = activeMQ.getAttribute(ActiveMQBroker.ADDRESS);
+        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://"+address+":"+port);
+        Connection connection = factory.createConnection("admin", "activemq");
+        connection.start();
+        return connection;
+    }
+
+    private void sendMessages(Connection connection, int count, String queueName, String content) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue destination = session.createQueue(queueName);
+        MessageProducer messageProducer = session.createProducer(destination);
+
+        for (int i = 0; i < count; i++) {
+            TextMessage message = session.createTextMessage(content);
+            messageProducer.send(message);
+        }
+
+        session.close();
+    }
+
+    private int clearQueue(Connection connection, String queueName) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue destination = session.createQueue(queueName);
+        MessageConsumer messageConsumer = session.createConsumer(destination);
+
+        int received = 0;
+        while (messageConsumer.receive(500) != null) received++;
+
+        session.close();
+        
+        return received;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaIntegrationTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaIntegrationTest.java
new file mode 100644
index 0000000..4253569
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaIntegrationTest.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.entity.messaging.kafka;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.entity.messaging.activemq.ActiveMQBroker;
+import brooklyn.entity.trait.Startable;
+
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+
+import brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.time.Duration;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * Test the operation of the {@link ActiveMQBroker} class.
+ *
+ * TODO test that sensors update.
+ */
+public class KafkaIntegrationTest {
+
+    private TestApplication app;
+    private Location testLocation;
+
+    @BeforeMethod(alwaysRun = true)
+    public void setup() {
+        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        LocationSpec<LocalhostMachineProvisioningLocation> locationSpec = LocationSpec.create(LocalhostMachineProvisioningLocation.class);
+        testLocation = app.getManagementContext().getLocationManager().createLocation(locationSpec);
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void shutdown() {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    /**
+     * Test that we can start a zookeeper.
+     */
+    @Test(groups = "Integration")
+    public void testZookeeper() {
+        final KafkaZooKeeper zookeeper = app.createAndManageChild(EntitySpec.create(KafkaZooKeeper.class));
+
+        zookeeper.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 60*1000), zookeeper, Startable.SERVICE_UP, true);
+
+        zookeeper.stop();
+        assertFalse(zookeeper.getAttribute(Startable.SERVICE_UP));
+    }
+
+    /**
+     * Test that we can start a  broker and zookeeper together.
+     */
+    @Test(groups = "Integration")
+    public void testBrokerPlusZookeeper() {
+        final KafkaZooKeeper zookeeper = app.createAndManageChild(EntitySpec.create(KafkaZooKeeper.class));
+        final KafkaBroker broker = app.createAndManageChild(EntitySpec.create(KafkaBroker.class).configure(KafkaBroker.ZOOKEEPER, zookeeper));
+
+        zookeeper.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 60*1000), zookeeper, Startable.SERVICE_UP, true);
+
+        broker.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(ImmutableMap.of("timeout", 60*1000), broker, Startable.SERVICE_UP, true);
+
+        zookeeper.stop();
+        assertFalse(zookeeper.getAttribute(Startable.SERVICE_UP));
+
+        broker.stop();
+        assertFalse(broker.getAttribute(Startable.SERVICE_UP));
+    }
+
+    /**
+     * Test that we can start a cluster with zookeeper and one broker.
+     *
+     * Connects to the zookeeper controller and tests sending and receiving messages on a topic.
+     */
+    @Test(groups = "Integration")
+    public void testTwoBrokerCluster() throws InterruptedException {
+        final KafkaCluster cluster = app.createAndManageChild(EntitySpec.create(KafkaCluster.class)
+                .configure(KafkaCluster.INITIAL_SIZE, 2));
+
+        cluster.start(ImmutableList.of(testLocation));
+        Asserts.succeedsEventually(MutableMap.of("timeout", Duration.TWO_MINUTES), new Callable<Void>() {
+            @Override
+            public Void call() {
+                assertTrue(cluster.getAttribute(Startable.SERVICE_UP));
+                assertTrue(cluster.getZooKeeper().getAttribute(Startable.SERVICE_UP));
+                assertEquals(cluster.getCurrentSize().intValue(), 2);
+                return null;
+            }
+        });
+
+        Entities.dumpInfo(cluster);
+
+        final KafkaSupport support = new KafkaSupport(cluster);
+
+        support.sendMessage("brooklyn", "TEST_MESSAGE");
+
+        Asserts.succeedsEventually(MutableMap.of("timeout", Duration.FIVE_SECONDS), new Runnable() {
+            @Override
+            public void run() {
+                String message = support.getMessage("brooklyn");
+                assertEquals(message, "TEST_MESSAGE");
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaLiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaLiveTest.java
new file mode 100644
index 0000000..c24c7e6
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaLiveTest.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.entity.messaging.kafka;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.concurrent.Callable;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.trait.Startable;
+import brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.collect.ImmutableList;
+
+public class KafkaLiveTest extends AbstractEc2LiveTest {
+
+    /**
+     * Test that can install, start and use a Kafka cluster with two brokers.
+     */
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        final KafkaCluster cluster = app.createAndManageChild(EntitySpec.create(KafkaCluster.class)
+                .configure("startTimeout", 300) // 5 minutes
+                .configure("initialSize", 2));
+        app.start(ImmutableList.of(loc));
+
+        Asserts.succeedsEventually(MutableMap.of("timeout", 300000l), new Callable<Void>() {
+            @Override
+            public Void call() {
+                assertTrue(cluster.getAttribute(Startable.SERVICE_UP));
+                assertTrue(cluster.getZooKeeper().getAttribute(Startable.SERVICE_UP));
+                assertEquals(cluster.getCurrentSize().intValue(), 2);
+                return null;
+            }
+        });
+
+        Entities.dumpInfo(cluster);
+
+        KafkaSupport support = new KafkaSupport(cluster);
+
+        support.sendMessage("brooklyn", "TEST_MESSAGE");
+        String message = support.getMessage("brooklyn");
+        assertEquals(message, "TEST_MESSAGE");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaSupport.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaSupport.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaSupport.java
new file mode 100644
index 0000000..0a4f3f2
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/kafka/KafkaSupport.java
@@ -0,0 +1,109 @@
+/*
+ * 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.entity.messaging.kafka;
+
+import brooklyn.entity.basic.EntityPredicates;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.kafka.clients.consumer.KafkaConsumer;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.Producer;
+import org.apache.kafka.clients.producer.ProducerRecord;
+
+import java.security.InvalidParameterException;
+import java.util.Properties;
+
+import static java.lang.String.format;
+
+/**
+ * Kafka test framework for integration and live tests, using the Kafka Java API.
+ */
+public class KafkaSupport {
+
+    private final KafkaCluster cluster;
+
+    public KafkaSupport(KafkaCluster cluster) {
+        this.cluster = cluster;
+    }
+
+    /**
+     * Send a message to the {@link KafkaCluster} on the given topic.
+     */
+    public void sendMessage(String topic, String message) {
+        Optional<Entity> anyBrokerNodeInCluster = Iterables.tryFind(cluster.getCluster().getChildren(), Predicates.and(
+                Predicates.instanceOf(KafkaBroker.class),
+                EntityPredicates.attributeEqualTo(KafkaBroker.SERVICE_UP, true)));
+        if (anyBrokerNodeInCluster.isPresent()) {
+            KafkaBroker broker = (KafkaBroker)anyBrokerNodeInCluster.get();
+
+            Properties props = new Properties();
+
+            props.put("metadata.broker.list", format("%s:%d", broker.getAttribute(KafkaBroker.HOSTNAME), broker.getKafkaPort()));
+            props.put("bootstrap.servers", format("%s:%d", broker.getAttribute(KafkaBroker.HOSTNAME), broker.getKafkaPort()));
+            props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
+            props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
+
+            Producer<String, String> producer = new KafkaProducer<>(props);
+            ((KafkaZooKeeper)cluster.getZooKeeper()).createTopic(topic);
+
+            ProducerRecord<String, String> data = new ProducerRecord<>(topic, message);
+            producer.send(data);
+            producer.close();
+        } else {
+            throw new InvalidParameterException("No kafka broker node found");
+        }
+    }
+
+    /**
+     * Retrieve the next message on the given topic from the {@link KafkaCluster}.
+     */
+    public String getMessage(String topic) {
+        ZooKeeperNode zookeeper = cluster.getZooKeeper();
+        Optional<Entity> anyBrokerNodeInCluster = Iterables.tryFind(cluster.getCluster().getChildren(), Predicates.and(
+                Predicates.instanceOf(KafkaBroker.class),
+                EntityPredicates.attributeEqualTo(KafkaBroker.SERVICE_UP, true)));
+        if (anyBrokerNodeInCluster.isPresent()) {
+            KafkaBroker broker = (KafkaBroker)anyBrokerNodeInCluster.get();
+
+            Properties props = new Properties();
+
+            props.put("bootstrap.servers", format("%s:%d", broker.getAttribute(KafkaBroker.HOSTNAME), broker.getKafkaPort()));
+            props.put("zookeeper.connect", format(zookeeper.getHostname(), zookeeper.getZookeeperPort()));
+            props.put("group.id", "brooklyn");
+            props.put("partition.assignment.strategy", "RoundRobin");
+            props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
+            props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
+
+            KafkaConsumer consumer = new KafkaConsumer(props);
+
+            consumer.subscribe(topic);
+            // FIXME unimplemented KafkaConsumer.poll
+//            Object consumerRecords = consumer.poll(Duration.seconds(3).toMilliseconds()).get(topic);
+            return "TEST_MESSAGE";
+        } else {
+            throw new InvalidParameterException("No kafka broker node found");
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/qpid/QpidEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/qpid/QpidEc2LiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/qpid/QpidEc2LiveTest.java
new file mode 100644
index 0000000..c01faab
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/qpid/QpidEc2LiveTest.java
@@ -0,0 +1,46 @@
+/*
+ * 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.entity.messaging.qpid;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+
+import com.google.common.collect.ImmutableList;
+
+public class QpidEc2LiveTest extends AbstractEc2LiveTest {
+
+    // TODO Also check can connect (e.g. to send/receive messages)
+    
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        QpidBroker qpid = app.createAndManageChild(EntitySpec.create(QpidBroker.class)
+                .configure("jmxPort", "9909+")
+                .configure("rmiRegistryPort", "9910+"));
+        
+        qpid.start(ImmutableList.of(loc));
+        EntityTestUtils.assertAttributeEqualsEventually(qpid, QpidBroker.SERVICE_UP, true);
+    }
+    
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/qpid/QpidIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/qpid/QpidIntegrationTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/qpid/QpidIntegrationTest.java
new file mode 100644
index 0000000..fcb1033
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/qpid/QpidIntegrationTest.java
@@ -0,0 +1,254 @@
+/*
+ * 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.entity.messaging.qpid;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.test.HttpTestUtils;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.configuration.ClientProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.trait.Startable;
+import brooklyn.test.Asserts;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Test the operation of the {@link QpidBroker} class.
+ */
+public class QpidIntegrationTest {
+    private static final Logger log = LoggerFactory.getLogger(QpidIntegrationTest.class);
+
+    private TestApplication app;
+    private Location testLocation;
+    private QpidBroker qpid;
+
+    @BeforeMethod(groups = "Integration")
+    public void setup() {
+        String workingDir = System.getProperty("user.dir");
+        log.info("Qpid working dir: {}", workingDir);
+        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        testLocation = app.newLocalhostProvisioningLocation();
+    }
+
+    @AfterMethod(alwaysRun=true)
+    public void shutdown() {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    /**
+     * Test that the broker starts up with JMX and RMI ports configured, and sets SERVICE_UP correctly.
+     */
+    @Test(groups = "Integration")
+    public void canStartupAndShutdown() {
+        qpid = app.createAndManageChild(EntitySpec.create(QpidBroker.class)
+                .configure("jmxPort", "9909+")
+                .configure("rmiRegistryPort", "9910+"));
+        qpid.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(qpid, Startable.SERVICE_UP, true);
+        qpid.stop();
+        assertFalse(qpid.getAttribute(Startable.SERVICE_UP));
+    }
+
+    /**
+     * Test that the broker starts up with HTTP management enabled, and we can connect to the URL.
+     */
+    @Test(groups = "Integration")
+    public void canStartupAndShutdownWithHttpManagement() {
+        qpid = app.createAndManageChild(EntitySpec.create(QpidBroker.class)
+                .configure("httpManagementPort", "8888+"));
+        qpid.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(qpid, Startable.SERVICE_UP, true);
+        String httpUrl = "http://"+qpid.getAttribute(QpidBroker.HOSTNAME)+":"+qpid.getAttribute(QpidBroker.HTTP_MANAGEMENT_PORT)+"/management";
+        HttpTestUtils.assertHttpStatusCodeEventuallyEquals(httpUrl, 200);
+        // TODO check actual REST output
+        qpid.stop();
+        assertFalse(qpid.getAttribute(Startable.SERVICE_UP));
+    }
+
+    /**
+     * Test that the broker starts up and sets SERVICE_UP correctly when plugins are configured.
+     * 
+     * FIXME the custom plugin was written against qpid 0.14, so that's the version we need to run
+     * this test against. However, v0.14 is no longer available from the download site.
+     * We should update this plugin so it works with the latest qpid.
+     */
+    @Test(enabled = false, groups = "Integration")
+    public void canStartupAndShutdownWithPlugin() {
+        Map<String,String> qpidRuntimeFiles = MutableMap.<String,String>builder()
+                .put("classpath://qpid-test-config.xml", "etc/config.xml")
+                .put("http://developers.cloudsoftcorp.com/brooklyn/repository-test/0.7.0/QpidBroker/qpid-test-plugin.jar", "lib/plugins/sample-plugin.jar")
+                .build();
+        qpid = app.createAndManageChild(EntitySpec.create(QpidBroker.class)
+                .configure(SoftwareProcess.RUNTIME_FILES, qpidRuntimeFiles)
+                .configure(QpidBroker.SUGGESTED_VERSION, "0.14"));
+        qpid.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(qpid, Startable.SERVICE_UP, true);
+        qpid.stop();
+        assertFalse(qpid.getAttribute(Startable.SERVICE_UP));
+    }
+
+    /**
+     * Test that setting the 'queue' property causes a named queue to be created.
+     *
+     * This test is disabled, pending further investigation. Issue with AMQP 0-10 queue names.
+     * 
+     * FIXME disabled becausing failing in jenkins CI (in QpidIntegrationTest.getQpidConnection()).
+     *     url=amqp://admin:********@brooklyn/localhost?brokerlist='tcp://localhost:5672'
+     * Was previously enabled, dispite comment above about "test is disabled".	
+     */
+    @Test(enabled = false, groups = { "Integration", "WIP" })
+    public void testCreatingQueues() {
+        final String queueName = "testQueue";
+        final int number = 20;
+        final String content = "01234567890123456789012345678901";
+
+        // Start broker with a configured queue
+        // FIXME Can't use app.createAndManageChild, because of QpidDestination reffing impl directly
+        qpid = app.createAndManageChild(EntitySpec.create(QpidBroker.class)
+                .configure("queue", queueName));
+        qpid.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(qpid, Startable.SERVICE_UP, true);
+
+        try {
+            // Check queue created
+            assertFalse(qpid.getQueueNames().isEmpty());
+            assertEquals(qpid.getQueueNames().size(), 1);
+            assertTrue(qpid.getQueueNames().contains(queueName));
+            assertEquals(qpid.getChildren().size(), 1);
+            assertFalse(qpid.getQueues().isEmpty());
+            assertEquals(qpid.getQueues().size(), 1);
+
+            // Get the named queue entity
+            final QpidQueue queue = qpid.getQueues().get(queueName);
+            assertNotNull(queue);
+
+            // Connect to broker using JMS and send messages
+            Connection connection = getQpidConnection(qpid);
+            clearQueue(connection, queue.getQueueName());
+            Asserts.succeedsEventually(new Runnable() {
+                @Override
+                public void run() {
+                    assertEquals(queue.getAttribute(QpidQueue.QUEUE_DEPTH_MESSAGES), Integer.valueOf(0));
+                }
+            });
+            sendMessages(connection, number, queue.getQueueName(), content);
+
+            // Check messages arrived
+            Asserts.succeedsEventually(new Runnable() {
+                @Override
+                public void run() {
+                    assertEquals(queue.getAttribute(QpidQueue.QUEUE_DEPTH_MESSAGES), Integer.valueOf(number));
+                    assertEquals(queue.getAttribute(QpidQueue.QUEUE_DEPTH_BYTES), Integer.valueOf(number * content.length()));
+                }
+            });
+
+            //TODO clearing the queue currently returns 0
+//            // Clear the messages -- should get 20
+//            assertEquals clearQueue(connection, queue.queueName), 20
+//
+//            // Check messages cleared
+//            executeUntilSucceeds {
+//                assertEquals queue.getAttribute(QpidQueue.QUEUE_DEPTH_MESSAGES), 0
+//                assertEquals queue.getAttribute(QpidQueue.QUEUE_DEPTH_BYTES), 0
+//            }
+
+            // Close the JMS connection
+            connection.close();
+        } catch (JMSException jmse) {
+            log.warn("JMS exception caught", jmse);
+            throw Exceptions.propagate(jmse);
+        } finally {
+            // Stop broker
+            qpid.stop();
+            qpid = null;
+            app = null;
+        }
+    }
+
+    private Connection getQpidConnection(QpidBroker qpid) {
+        int port = qpid.getAttribute(Attributes.AMQP_PORT);
+        System.setProperty(ClientProperties.AMQP_VERSION, "0-10");
+        System.setProperty(ClientProperties.DEST_SYNTAX, "ADDR");
+        String connectionUrl = String.format("amqp://admin:admin@brooklyn/localhost?brokerlist='tcp://localhost:%d'", port);
+        try {
+            AMQConnectionFactory factory = new AMQConnectionFactory(connectionUrl);
+            Connection connection = factory.createConnection();
+            connection.start();
+            return connection;
+        } catch (Exception e) {
+            log.error(String.format("Error connecting to qpid: %s", connectionUrl), e);
+            throw Exceptions.propagate(e);
+        }
+    }
+
+    private void sendMessages(Connection connection, int count, String queueName, String content) throws JMSException {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue destination = session.createQueue(queueName);
+        MessageProducer messageProducer = session.createProducer(destination);
+
+        for (int i = 0; i < count; i++) {
+            TextMessage message = session.createTextMessage(content);
+            messageProducer.send(message);
+        }
+
+        session.close();
+    }
+
+    private int clearQueue(Connection connection, String queueName) throws JMSException {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue destination = session.createQueue(queueName);
+        MessageConsumer messageConsumer = session.createConsumer(destination);
+
+        int received = 0;
+        while (messageConsumer.receive(500) != null) received++;
+
+        session.close();
+
+        return received;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitEc2LiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitEc2LiveTest.java
new file mode 100644
index 0000000..461ef1a
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitEc2LiveTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.entity.messaging.rabbit;
+
+import static org.testng.Assert.assertEquals;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.SkipException;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import org.apache.brooklyn.entity.messaging.MessageBroker;
+import org.apache.brooklyn.entity.messaging.amqp.AmqpExchange;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.Connection;
+import com.rabbitmq.client.ConnectionFactory;
+import com.rabbitmq.client.QueueingConsumer;
+
+public class RabbitEc2LiveTest extends AbstractEc2LiveTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RabbitEc2LiveTest.class);
+
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        RabbitBroker rabbit = app.createAndManageChild(EntitySpec.create(RabbitBroker.class));
+        rabbit.start(ImmutableList.of(loc));
+        EntityTestUtils.assertAttributeEqualsEventually(rabbit, RabbitBroker.SERVICE_UP, true);
+
+        byte[] content = "MessageBody".getBytes(Charsets.UTF_8);
+        String queue = "queueName";
+        Channel producer = null;
+        Channel consumer = null;
+        try {
+            producer = getAmqpChannel(rabbit);
+            consumer = getAmqpChannel(rabbit);
+
+            producer.queueDeclare(queue, true, false, false, Maps.<String,Object>newHashMap());
+            producer.queueBind(queue, AmqpExchange.DIRECT, queue);
+            producer.basicPublish(AmqpExchange.DIRECT, queue, null, content);
+            
+            QueueingConsumer queueConsumer = new QueueingConsumer(consumer);
+            consumer.basicConsume(queue, true, queueConsumer);
+        
+            QueueingConsumer.Delivery delivery = queueConsumer.nextDelivery();
+            assertEquals(delivery.getBody(), content);
+        } finally {
+            if (producer != null) producer.close();
+            if (consumer != null) consumer.close();
+        }
+    }
+
+    private Channel getAmqpChannel(RabbitBroker rabbit) throws Exception {
+        String uri = rabbit.getAttribute(MessageBroker.BROKER_URL);
+        LOG.warn("connecting to rabbit {}", uri);
+        ConnectionFactory factory = new ConnectionFactory();
+        factory.setUri(uri);
+        Connection conn = factory.newConnection();
+        Channel channel = conn.createChannel();
+        return channel;
+    }
+
+    @Override
+    public void test_CentOS_5() throws SkipException {
+        // Not supported. The EPEL repository described here at [1] does not contain erlang, and the
+        // Erlang repository at [1] requires old versions of rpmlib. Additionally, [2] suggests that
+        // Centos 5 is not supported
+        // [1]:http://www.rabbitmq.com/install-rpm.html
+        // [2]: https://www.erlang-solutions.com/downloads/download-erlang-otp
+        throw new SkipException("Centos 5 is not supported");
+    }
+
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods  
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.java
new file mode 100644
index 0000000..f9bcd5c
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/rabbit/RabbitIntegrationTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.entity.messaging.rabbit;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import java.io.IOException;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.test.entity.TestApplication;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.basic.ApplicationBuilder;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.entity.messaging.MessageBroker;
+import org.apache.brooklyn.entity.messaging.amqp.AmqpExchange;
+import brooklyn.entity.trait.Startable;
+
+import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.Connection;
+import com.rabbitmq.client.ConnectionFactory;
+import com.rabbitmq.client.QueueingConsumer;
+
+/**
+ * Test the operation of the {@link RabbitBroker} class.
+ * 
+ * TODO If you're having problems running this test successfully, here are a few tips:
+ * 
+ *  - Is `erl` on your path for a non-interactive ssh session?
+ *    Look in rabbit's $RUN_DIR/console-err.log (e.g. /tmp/brooklyn-aled/apps/someappid/entities/RabbitBroker_2.8.7_JROYTcSL/console-err.log)
+ *    I worked around that by adding to my ~/.brooklyn/brooklyn.properties:
+ *      brooklyn.ssh.config.scriptHeader=#!/bin/bash -e\nif [ -f ~/.bashrc ] ; then . ~/.bashrc ; fi\nif [ -f ~/.profile ] ; then . ~/.profile ; fi\necho $PATH > /tmp/mypath.txt
+ *    
+ *  - Is the hostname resolving properly?
+ *    Look in $RUN_DIR/console-out.log; is there a message like:
+ *      ERROR: epmd error for host "Aleds-MacBook-Pro": timeout (timed out establishing tcp connection)
+ *    I got around that with disabling my wifi and running when not connected to the internet.
+ */
+public class RabbitIntegrationTest {
+    private static final Logger log = LoggerFactory.getLogger(RabbitIntegrationTest.class);
+
+    private TestApplication app;
+    private Location testLocation;
+    private RabbitBroker rabbit;
+
+    @BeforeMethod(groups = "Integration")
+    public void setup() {
+        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        testLocation = new LocalhostMachineProvisioningLocation();
+    }
+
+    @AfterMethod(alwaysRun = true)
+    public void shutdown() {
+        if (app != null) Entities.destroyAll(app.getManagementContext());
+    }
+
+    /**
+     * Test that the broker starts up and sets SERVICE_UP correctly.
+     */
+    @Test(groups = {"Integration", "WIP"})
+    public void canStartupAndShutdown() throws Exception {
+        rabbit = app.createAndManageChild(EntitySpec.create(RabbitBroker.class));
+        rabbit.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(rabbit, Startable.SERVICE_UP, true);
+        rabbit.stop();
+        assertFalse(rabbit.getAttribute(Startable.SERVICE_UP));
+    }
+
+    /**
+     * Test that an AMQP client can connect to and use the broker.
+     */
+    @Test(groups = {"Integration", "WIP"})
+    public void testClientConnection() throws Exception {
+        rabbit = app.createAndManageChild(EntitySpec.create(RabbitBroker.class));
+        rabbit.start(ImmutableList.of(testLocation));
+        EntityTestUtils.assertAttributeEqualsEventually(rabbit, Startable.SERVICE_UP, true);
+
+        byte[] content = "MessageBody".getBytes(Charsets.UTF_8);
+        String queue = "queueName";
+        Channel producer = null;
+        Channel consumer = null;
+        try {
+            producer = getAmqpChannel(rabbit);
+            consumer = getAmqpChannel(rabbit);
+
+            producer.queueDeclare(queue, true, false, false, ImmutableMap.<String,Object>of());
+            producer.queueBind(queue, AmqpExchange.DIRECT, queue);
+            producer.basicPublish(AmqpExchange.DIRECT, queue, null, content);
+            
+            QueueingConsumer queueConsumer = new QueueingConsumer(consumer);
+            consumer.basicConsume(queue, true, queueConsumer);
+        
+            QueueingConsumer.Delivery delivery = queueConsumer.nextDelivery(60 * 1000l); // one minute timeout
+            assertEquals(delivery.getBody(), content);
+        } finally {
+            closeSafely(producer, 10*1000);
+            closeSafely(consumer, 10*1000);
+        }
+    }
+
+    /**
+     * Closes the channel, guaranteeing the call won't hang this thread forever!
+     * 
+     * Saw this during jenkins testing:
+     * "main" prio=10 tid=0x00007f69c8008000 nid=0x5d70 in Object.wait() [0x00007f69d1318000]
+     *         java.lang.Thread.State: WAITING (on object monitor)
+     *         at java.lang.Object.wait(Native Method)
+     *         - waiting on <0x00000000e0947cf8> (a com.rabbitmq.utility.BlockingValueOrException)
+     *         at java.lang.Object.wait(Object.java:502)
+     *         at com.rabbitmq.utility.BlockingCell.get(BlockingCell.java:50)
+     *         - locked <0x00000000e0947cf8> (a com.rabbitmq.utility.BlockingValueOrException)
+     *         at com.rabbitmq.utility.BlockingCell.get(BlockingCell.java:65)
+     *         - locked <0x00000000e0947cf8> (a com.rabbitmq.utility.BlockingValueOrException)
+     *         at com.rabbitmq.utility.BlockingCell.uninterruptibleGet(BlockingCell.java:111)
+     *         - locked <0x00000000e0947cf8> (a com.rabbitmq.utility.BlockingValueOrException)
+     *         at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:37)
+     *         at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:349)
+     *         at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:543)
+     *         at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:480)
+     *         at com.rabbitmq.client.impl.ChannelN.close(ChannelN.java:473)
+     *         at com.rabbitmq.client.Channel$close.call(Unknown Source)
+     *         at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
+     *         at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
+     *         at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
+     *         at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callSafe(AbstractCallSite.java:75)
+     *         at org.apache.brooklyn.entity.messaging.rabbit.RabbitIntegrationTest.testClientConnection(RabbitIntegrationTest.groovy:107)
+     */
+    private void closeSafely(final Channel channel, int timeoutMs) throws InterruptedException {
+        if (channel == null) return;
+        Thread t = new Thread(new Runnable() {
+                @Override public void run() {
+                    try {
+                        channel.close();
+                    } catch (IOException e) {
+                        log.error("Error closing RabbitMQ Channel; continuing", e);
+                    }
+                }});
+        try {
+            t.start();
+            t.join(timeoutMs);
+            
+            if (t.isAlive()) {
+                log.error("Timeout when closing RabbitMQ Channel "+channel+"; aborting close and continuing");
+            }
+        } finally {
+            t.interrupt();
+            t.join(1*1000);
+            if (t.isAlive()) t.stop();
+        }
+    }
+    
+    private Channel getAmqpChannel(RabbitBroker rabbit) throws Exception {
+        String uri = rabbit.getAttribute(MessageBroker.BROKER_URL);
+        log.warn("connecting to rabbit {}", uri);
+        ConnectionFactory factory = new ConnectionFactory();
+        factory.setUri(uri);
+        Connection conn = factory.newConnection();
+        Channel channel = conn.createChannel();
+        return channel;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/LocalhostLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/LocalhostLiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/LocalhostLiveTest.java
new file mode 100644
index 0000000..89afe00
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/LocalhostLiveTest.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.entity.messaging.storm;
+
+import org.testng.annotations.Test;
+
+@Test(groups="Live")
+public class LocalhostLiveTest extends StormAbstractCloudLiveTest {
+
+    private static final String NAMED_LOCATION = "localhost";
+
+    public String getLocation() {
+        return NAMED_LOCATION;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/SoftLayerLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/SoftLayerLiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/SoftLayerLiveTest.java
new file mode 100644
index 0000000..17cb7d2
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/SoftLayerLiveTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.entity.messaging.storm;
+
+import org.testng.annotations.Test;
+
+@Test(groups="Live")
+public class SoftLayerLiveTest extends StormAbstractCloudLiveTest {
+
+    private static final String NAMED_LOCATION = "softlayer";
+
+    @Override
+    public String getLocation() {
+        return NAMED_LOCATION;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..c85b4fa
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.entity.messaging.storm;
+
+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 brooklyn.event.basic.DependentConfiguration.attributeWhenReady;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.file.ArchiveBuilder;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import backtype.storm.Config;
+import backtype.storm.StormSubmitter;
+import backtype.storm.generated.AlreadyAliveException;
+import backtype.storm.generated.InvalidTopologyException;
+import backtype.storm.generated.StormTopology;
+import backtype.storm.testing.TestWordSpout;
+import backtype.storm.topology.TopologyBuilder;
+import brooklyn.entity.BrooklynAppLiveTestSupport;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.Entities;
+import org.apache.brooklyn.entity.messaging.storm.topologies.ExclamationBolt;
+import brooklyn.entity.trait.Startable;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperEnsemble;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.os.Os;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+
+public abstract class StormAbstractCloudLiveTest extends BrooklynAppLiveTestSupport {
+
+    protected static final Logger log = LoggerFactory
+            .getLogger(StormAbstractCloudLiveTest.class);
+    private Location location;
+    private ZooKeeperEnsemble zooKeeperEnsemble;
+    private Storm nimbus;
+    private Storm supervisor;
+    private Storm ui;
+
+    @BeforeClass(alwaysRun = true)
+    public void beforeClass() throws Exception {
+        mgmt = new LocalManagementContext();
+        location = mgmt.getLocationRegistry()
+                .resolve(getLocation(), getFlags());
+        super.setUp();
+    }
+
+    @AfterClass(alwaysRun = true)
+    public void afterClass() throws Exception {
+        // Entities.destroyAll(mgmt);
+    }
+
+    public abstract String getLocation();
+
+    public Map<String, ?> getFlags() {
+        return MutableMap.of();
+    }
+
+    @Test(groups = {"Live","WIP"})  // needs repair to avoid hard dependency on Andrea's environment
+    public void deployStorm() throws Exception {
+        try {
+            zooKeeperEnsemble = app.createAndManageChild(EntitySpec.create(
+                    ZooKeeperEnsemble.class).configure(
+                    ZooKeeperEnsemble.INITIAL_SIZE, 3));
+            nimbus = app.createAndManageChild(EntitySpec
+                    .create(Storm.class)
+                    .configure(Storm.ROLE, NIMBUS)
+                    .configure(NIMBUS_HOSTNAME, "localhost")
+                    .configure(ZOOKEEPER_ENSEMBLE, zooKeeperEnsemble)
+                    );
+            supervisor = app.createAndManageChild(EntitySpec
+                    .create(Storm.class)
+                    .configure(Storm.ROLE, SUPERVISOR)
+                    .configure(ZOOKEEPER_ENSEMBLE, zooKeeperEnsemble)
+                    .configure(NIMBUS_HOSTNAME,
+                            attributeWhenReady(nimbus, Attributes.HOSTNAME)));
+            ui = app.createAndManageChild(EntitySpec
+                    .create(Storm.class)
+                    .configure(Storm.ROLE, UI)
+                    .configure(ZOOKEEPER_ENSEMBLE, zooKeeperEnsemble)
+                    .configure(NIMBUS_HOSTNAME,
+                            attributeWhenReady(nimbus, Attributes.HOSTNAME)));
+            log.info("Started Storm deployment on '" + getLocation() + "'");
+            app.start(ImmutableList.of(location));
+            Entities.dumpInfo(app);
+            EntityTestUtils.assertAttributeEqualsEventually(app, Startable.SERVICE_UP, true);
+            EntityTestUtils.assertAttributeEqualsEventually(zooKeeperEnsemble, Startable.SERVICE_UP, true);
+            EntityTestUtils.assertAttributeEqualsEventually(nimbus, Startable.SERVICE_UP, true);
+            EntityTestUtils.assertAttributeEqualsEventually(supervisor, Startable.SERVICE_UP, true);
+            EntityTestUtils.assertAttributeEqualsEventually(ui, Startable.SERVICE_UP, true);
+            
+            StormTopology stormTopology = createTopology();
+            submitTopology(stormTopology, "myExclamation", 3, true, 60000);
+        } catch (Exception e) {
+            log.error("Failed to deploy Storm", e);
+            Assert.fail();
+            throw e;
+        }
+    }
+
+    private StormTopology createTopology()
+            throws AlreadyAliveException, InvalidTopologyException {
+        TopologyBuilder builder = new TopologyBuilder();
+
+        builder.setSpout("word", new TestWordSpout(), 10);
+        builder.setBolt("exclaim1", new ExclamationBolt(), 3).shuffleGrouping("word");
+        builder.setBolt("exclaim2", new ExclamationBolt(), 2).shuffleGrouping("exclaim1");
+        
+        return builder.createTopology();
+    }
+
+    public boolean submitTopology(StormTopology stormTopology, String topologyName, int numOfWorkers, boolean debug, long timeoutMs) {
+        if (log.isDebugEnabled()) log.debug("Connecting to NimbusClient: {}", nimbus.getConfig(Storm.NIMBUS_HOSTNAME));
+        Config conf = new Config();
+        conf.setDebug(debug);
+        conf.setNumWorkers(numOfWorkers);
+
+        // TODO - confirm this creats the JAR correctly
+        String jar = createJar(
+            new File(Os.mergePaths(ResourceUtils.create(this).getClassLoaderDir(), "org/apache/brooklyn/entity/messaging/storm/topologies")),
+            "org/apache/brooklyn/entity/messaging/storm/");
+        System.setProperty("storm.jar", jar);
+        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) Time.sleep(Duration.ONE_SECOND);
+            if (log.isTraceEnabled()) log.trace("trying connection to {} at time {}", nimbus.getConfig(Storm.NIMBUS_HOSTNAME), currentTime);
+
+            try {
+                StormSubmitter.submitTopology(topologyName, conf, stormTopology);
+                return true;
+            } catch (Exception e) {
+                if (shouldRetryOn(e)) {
+                    if (log.isDebugEnabled()) log.debug("Attempt {} failed connecting to {} ({})", new Object[] {attempt + 1, nimbus.getConfig(Storm.NIMBUS_HOSTNAME), e.getMessage()});
+                    lastError = e;
+                } else {
+                    throw Throwables.propagate(e);
+                }
+            }
+            attempt++;
+        }
+        log.warn("unable to connect to Nimbus client: ", lastError);
+        Assert.fail();
+        return false;
+    }
+    
+    private boolean shouldRetryOn(Exception e) {
+        if (e.getMessage().equals("org.apache.thrift7.transport.TTransportException: java.net.ConnectException: Connection refused"))  return true;
+        return false;
+    }
+    
+    private String createJar(File dir, String parentDirInJar) {
+        if (dir.isDirectory()) {
+            File jarFile = ArchiveBuilder.jar().addAt(dir, parentDirInJar).create(Os.newTempDir(getClass())+"/topologies.jar");
+            return jarFile.getAbsolutePath();
+        } else {
+            return dir.getAbsolutePath(); // An existing Jar archive?
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormEc2LiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormEc2LiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormEc2LiveTest.java
new file mode 100644
index 0000000..5339616
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormEc2LiveTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.entity.messaging.storm;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.AbstractEc2LiveTest;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.trait.Startable;
+import org.apache.brooklyn.entity.zookeeper.ZooKeeperNode;
+
+import com.google.common.collect.ImmutableList;
+
+public class StormEc2LiveTest extends AbstractEc2LiveTest {
+
+    /**
+     * Test that can install, start and use a Storm cluster: 1 nimbus, 1 zookeeper, 1 supervisor (worker node).
+     */
+    @Override
+    protected void doTest(Location loc) throws Exception {
+        ZooKeeperNode zookeeper = app.createAndManageChild(EntitySpec.create(ZooKeeperNode.class));
+        Storm nimbus = app.createAndManageChild(EntitySpec.create(Storm.class).configure("storm.role",
+                Storm.Role.NIMBUS));
+        Storm supervisor = app.createAndManageChild(EntitySpec.create(Storm.class).configure("storm.role",
+                Storm.Role.SUPERVISOR));
+        Storm ui = app.createAndManageChild(EntitySpec.create(Storm.class).configure("storm.role",
+                Storm.Role.UI));        
+        app.start(ImmutableList.of(loc));
+        Entities.dumpInfo(app);
+        
+        EntityTestUtils.assertAttributeEqualsEventually(zookeeper, Startable.SERVICE_UP, true);
+        EntityTestUtils.assertAttributeEqualsEventually(nimbus, Startable.SERVICE_UP, true);
+        EntityTestUtils.assertAttributeEqualsEventually(supervisor, Startable.SERVICE_UP, true);
+        EntityTestUtils.assertAttributeEqualsEventually(ui, Startable.SERVICE_UP, true);
+    }
+
+    @Test(enabled=false)
+    public void testDummy() {} // Convince testng IDE integration that this really does have test methods
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormGceLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormGceLiveTest.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormGceLiveTest.java
new file mode 100644
index 0000000..7b84846
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormGceLiveTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.entity.messaging.storm;
+
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+import brooklyn.util.collections.MutableMap;
+
+@Test(groups="Live")
+public class StormGceLiveTest extends StormAbstractCloudLiveTest {
+
+    private static final String NAMED_LOCATION = "gce-europe-west1";
+    private static final String LOCATION_ID = "gce-europe-west1-a";
+    private static final String URI = "https://www.googleapis.com/compute/v1beta15/projects/google/global/images/centos-6-v20130325";
+    private static final String IMAGE_ID = "centos-6-v20130325";
+
+    @Override
+    public String getLocation() {
+        return NAMED_LOCATION;
+    }
+
+    @Override
+    public Map<String, ?> getFlags() {
+        return MutableMap.of(
+                "locationId", LOCATION_ID,
+                "imageId", IMAGE_ID,
+                "uri", URI + IMAGE_ID,
+                "groupId", "storm-test",
+                "stopIptables", "true"
+        );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/topologies/ExclamationBolt.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/topologies/ExclamationBolt.java b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/topologies/ExclamationBolt.java
new file mode 100644
index 0000000..a10a30e
--- /dev/null
+++ b/software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/topologies/ExclamationBolt.java
@@ -0,0 +1,51 @@
+/*
+ * 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.entity.messaging.storm.topologies;
+
+import java.util.Map;
+
+import backtype.storm.task.OutputCollector;
+import backtype.storm.task.TopologyContext;
+import backtype.storm.topology.IRichBolt;
+import backtype.storm.topology.OutputFieldsDeclarer;
+import backtype.storm.topology.base.BaseRichBolt;
+import backtype.storm.tuple.Fields;
+import backtype.storm.tuple.Tuple;
+import backtype.storm.tuple.Values;
+
+public class ExclamationBolt extends BaseRichBolt {
+    OutputCollector _collector;
+
+    @Override
+    public void prepare(Map conf, TopologyContext context,
+            OutputCollector collector) {
+        _collector = collector;
+    }
+
+    @Override
+    public void execute(Tuple tuple) {
+        _collector.emit(tuple, new Values(tuple.getString(0) + "!!!"));
+        _collector.ack(tuple);
+    }
+
+    @Override
+    public void declareOutputFields(OutputFieldsDeclarer declarer) {
+        declarer.declare(new Fields("word"));
+    }
+}
\ No newline at end of file



[49/64] incubator-brooklyn git commit: brooklyn-software-messaging: add org.apache package prefix

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitSshDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitSshDriver.java
deleted file mode 100644
index 470221e..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitSshDriver.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 brooklyn.entity.messaging.rabbit;
-
-import static brooklyn.util.ssh.BashCommands.*;
-import static java.lang.String.format;
-
-import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.lifecycle.ScriptHelper;
-import brooklyn.entity.messaging.amqp.AmqpServer;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.net.Networking;
-import brooklyn.util.os.Os;
-
-/**
- * TODO javadoc
- */
-public class RabbitSshDriver extends AbstractSoftwareProcessSshDriver implements RabbitDriver {
-
-    private static final Logger log = LoggerFactory.getLogger(RabbitSshDriver.class);
-
-    // See http://fedoraproject.org/wiki/EPEL/FAQ#howtouse
-    private static final Map<String, String> CENTOS_VERSION_TO_EPEL_VERSION = ImmutableMap.of(
-        "5", "5-4",
-        "6", "6-8",
-        "7", "7-5"
-    );
-
-    public RabbitSshDriver(RabbitBrokerImpl entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    protected String getLogFileLocation() { return getRunDir()+"/"+entity.getId()+".log"; }
-
-    public Integer getAmqpPort() { return entity.getAttribute(AmqpServer.AMQP_PORT); }
-
-    public String getVirtualHost() { return entity.getAttribute(AmqpServer.VIRTUAL_HOST_NAME); }
-
-    public String getErlangVersion() { return entity.getConfig(RabbitBroker.ERLANG_VERSION); }
-
-    @Override
-    public RabbitBrokerImpl getEntity() {
-        return (RabbitBrokerImpl) super.getEntity();
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("rabbitmq_server-%s", getVersion()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-        // Version and architecture are only required for download of epel package on RHEL/Centos systems so pick sensible
-        // defaults if unavailable
-        String osMajorVersion = getMachine().getOsDetails().getVersion();
-        if (Strings.isNullOrEmpty(osMajorVersion)) {
-            osMajorVersion = "7";
-        } else {
-            osMajorVersion = osMajorVersion.indexOf(".") > 0 ? osMajorVersion.substring(0, osMajorVersion.indexOf('.')) : osMajorVersion;
-            if (!CENTOS_VERSION_TO_EPEL_VERSION.keySet().contains(osMajorVersion)) {
-                osMajorVersion = "7";
-            }
-        }
-        String epelVersion = CENTOS_VERSION_TO_EPEL_VERSION.get(osMajorVersion);
-        String osArchitecture = getMachine().getOsDetails().getArch();
-        if (Strings.isNullOrEmpty(osArchitecture)) {
-            osArchitecture = "x86_64";
-        }
-
-        List<String> commands = ImmutableList.<String>builder()
-                // EPEL repository for erlang install required on some Centos distributions
-                .add(chainGroup("which yum", sudo("yum -y update ca-certificates"), sudo("rpm -Uvh " +
-                        format("http://download.fedoraproject.org/pub/epel/%s/%s/epel-release-%s.noarch.rpm", osMajorVersion, osArchitecture, epelVersion))))
-                .add(ifExecutableElse0("zypper", chainGroup(
-                        ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/SLE_11_SP3 erlang_sles_11")),
-                        ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/openSUSE_11.4 erlang_suse_11")),
-                        ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/openSUSE_12.3 erlang_suse_12")),
-                        ok(sudo("zypper --non-interactive addrepo http://download.opensuse.org/repositories/devel:/languages:/erlang/openSUSE_13.1 erlang_suse_13")))))
-                .add(installPackage( // NOTE only 'port' states the version of Erlang used, maybe remove this constraint?
-                        ImmutableMap.of(
-                                "apt", "erlang-nox erlang-dev",
-                                "port", "erlang@"+getErlangVersion()+"+ssl"),
-                        "erlang"))
-                .addAll(commandsToDownloadUrlsAs(urls, saveAs))
-                .add(installExecutable("tar"))
-                .add(format("tar xvzf %s",saveAs))
-                .build();
-
-        newScript(INSTALLING).
-                failOnNonZeroResultCode().
-                body.append(commands).execute();
-    }
-
-    @Override
-    public void customize() {
-        Networking.checkPortsValid(MutableMap.of("amqpPort", getAmqpPort()));
-        ScriptHelper scriptHelper = newScript(CUSTOMIZING);
-
-        scriptHelper.body.append(
-                format("cp -R %s/* .", getExpandedInstallDir())
-        );
-
-        if (Boolean.TRUE.equals(entity.getConfig(RabbitBroker.ENABLE_MANAGEMENT_PLUGIN))) {
-            scriptHelper.body.append(
-                    "./sbin/rabbitmq-plugins enable rabbitmq_management"
-            );
-        }
-        scriptHelper.failOnNonZeroResultCode();
-        scriptHelper.execute();
-
-        copyTemplate(entity.getConfig(RabbitBroker.CONFIG_TEMPLATE_URL), getConfigPath() + ".config");
-    }
-
-    @Override
-    public void launch() {
-        newScript(MutableMap.of("usePidFile", false), LAUNCHING)
-            .body.append(
-                "nohup ./sbin/rabbitmq-server > console-out.log 2> console-err.log &",
-                "for i in {1..10}\n" +
-                    "do\n" +
-                     "    grep 'broker running' console-out.log && exit\n" +
-                     "    sleep 1\n" +
-                     "done",
-                "echo \"Couldn't determine if rabbitmq-server is running\"",
-                "exit 1"
-            ).execute();
-    }
-
-    @Override
-    public void configure() {
-        newScript(CUSTOMIZING)
-            .body.append(
-                "./sbin/rabbitmqctl add_vhost "+getEntity().getVirtualHost(),
-                "./sbin/rabbitmqctl set_permissions -p "+getEntity().getVirtualHost()+" guest \".*\" \".*\" \".*\""
-            ).execute();
-    }
-
-
-    public String getPidFile() { return "rabbitmq.pid"; }
-
-    @Override
-    public boolean isRunning() {
-        return newScript(MutableMap.of("usePidFile", false), CHECK_RUNNING)
-                .body.append("./sbin/rabbitmqctl -q status")
-                .execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        newScript(MutableMap.of("usePidFile", false), STOPPING)
-                .body.append("./sbin/rabbitmqctl stop")
-                .execute();
-    }
-
-
-    @Override
-    public void kill() {
-        stop(); // TODO No pid file to easily do `kill -9`
-    }
-
-    @Override
-    public Map<String, String> getShellEnvironment() {
-        return MutableMap.<String, String>builder()
-                .putAll(super.getShellEnvironment())
-                .put("RABBITMQ_HOME", getRunDir())
-                .put("RABBITMQ_LOG_BASE", getRunDir())
-                .put("RABBITMQ_NODENAME", getEntity().getId())
-                .put("RABBITMQ_NODE_PORT", getAmqpPort().toString())
-                .put("RABBITMQ_PID_FILE", getRunDir()+"/"+getPidFile())
-                .put("RABBITMQ_CONFIG_FILE", getConfigPath())
-                .build();
-    }
-
-    private String getConfigPath() {
-        return getRunDir() + "/rabbitmq";
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/storm/Storm.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/Storm.java b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/Storm.java
deleted file mode 100644
index ced7bef..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/Storm.java
+++ /dev/null
@@ -1,105 +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 brooklyn.entity.messaging.storm;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.config.render.RendererHints;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.java.UsesJmx;
-import brooklyn.entity.zookeeper.ZooKeeperEnsemble;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a Storm node (UI, Nimbus or Supervisor).
- */
-@Catalog(name="Storm Node", description="Apache Storm is a distributed realtime computation system. "
-        + "Storm makes it easy to reliably process unbounded streams of data, doing for realtime processing "
-        + "what Hadoop did for batch processing")
-@ImplementedBy(StormImpl.class)
-public interface Storm extends SoftwareProcess, UsesJmx {
-
-    @SetFromFlag("version")
-    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "0.8.2");
-
-    @SetFromFlag("nimbusHostname")
-    ConfigKey<String> NIMBUS_HOSTNAME = ConfigKeys.newStringConfigKey("storm.nimbus.hostname");
-    
-    @SetFromFlag("nimbusEntity")
-    ConfigKey<Entity> NIMBUS_ENTITY = ConfigKeys.newConfigKey(Entity.class, "storm.nimbus.entity");
-
-    @SetFromFlag("downloadUrl")
-    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
-            SoftwareProcess.DOWNLOAD_URL, "https://dl.dropboxusercontent.com/s/fl4kr7w0oc8ihdw/storm-${version}.zip");
-
-    ConfigKey<Object> START_MUTEX = ConfigKeys.newConfigKey(Object.class, "storm.start.mutex");
-
-    @SetFromFlag("role")
-    ConfigKey<Role> ROLE = ConfigKeys.newConfigKey(Role.class, "storm.role", "The Storm server role");
-
-    @SetFromFlag("localDir")
-    ConfigKey<String> LOCAL_DIR = ConfigKeys.newStringConfigKey("storm.local.dir", "Setting for Storm local dir");
-    
-    @SetFromFlag("uiPort")
-    PortAttributeSensorAndConfigKey UI_PORT = new PortAttributeSensorAndConfigKey("storm.ui.port", "Storm UI port", "8080+");
-
-    @SetFromFlag("thriftPort")
-    PortAttributeSensorAndConfigKey THRIFT_PORT = new PortAttributeSensorAndConfigKey("storm.thrift.port", "Storm Thrift port", "6627");
-
-    @SetFromFlag("zookeeperEnsemble")
-    ConfigKey<ZooKeeperEnsemble> ZOOKEEPER_ENSEMBLE = ConfigKeys.newConfigKey(ZooKeeperEnsemble.class,
-            "storm.zookeeper.ensemble", "Zookeeper ensemble entity");
-
-    @SetFromFlag("stormConfigTemplateUrl")
-    ConfigKey<String> STORM_CONFIG_TEMPLATE_URL = ConfigKeys.newStringConfigKey("storm.config.templateUrl",
-            "Template file (in freemarker format) for the storm.yaml config file",
-            "classpath://brooklyn/entity/messaging/storm/storm.yaml");
-
-    @SetFromFlag("zeromqVersion")
-    ConfigKey<String> ZEROMQ_VERSION = ConfigKeys.newStringConfigKey("storm.zeromq.version", "zeromq version", "2.1.7");
-
-    AttributeSensor<Boolean> SERVICE_UP_JMX = Sensors.newBooleanSensor("storm.service.jmx.up", "Whether JMX is up for this service");
-
-    String getStormConfigTemplateUrl();
-
-    String getHostname();
-
-    Role getRole();
-    
-    enum Role { NIMBUS, SUPERVISOR, UI }
-
-    AttributeSensor<String> STORM_UI_URL = StormUiUrl.STORM_UI_URL;
-    
-    class StormUiUrl {
-        public static final AttributeSensor<String> STORM_UI_URL = Sensors.newStringSensor("storm.ui.url", "URL");
-
-        static {
-            RendererHints.register(STORM_UI_URL, RendererHints.namedActionWithUrl());
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeployment.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeployment.java b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeployment.java
deleted file mode 100644
index fda29fd..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeployment.java
+++ /dev/null
@@ -1,42 +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 brooklyn.entity.messaging.storm;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.trait.Startable;
-
-@Catalog(name="Storm Deployment", description="A Storm cluster. Apache Storm is a distributed realtime computation system. "
-        + "Storm makes it easy to reliably process unbounded streams of data, doing for realtime processing "
-        + "what Hadoop did for batch processing")
-@ImplementedBy(StormDeploymentImpl.class)
-public interface StormDeployment extends Entity, Startable {
-
-    @SetFromFlag("supervisors.count")
-    ConfigKey<Integer> SUPERVISORS_COUNT = ConfigKeys.newConfigKey("storm.supervisors.count", "Number of supervisor nodes", 3);
-
-    @SetFromFlag("zookeepers.count")
-    ConfigKey<Integer> ZOOKEEPERS_COUNT = ConfigKeys.newConfigKey("storm.zookeepers.count", "Number of zookeeper nodes", 1);
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeploymentImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
deleted file mode 100644
index cf90db8..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
+++ /dev/null
@@ -1,77 +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 brooklyn.entity.messaging.storm;
-
-import static brooklyn.entity.messaging.storm.Storm.ROLE;
-import static brooklyn.entity.messaging.storm.Storm.Role.NIMBUS;
-import static brooklyn.entity.messaging.storm.Storm.Role.SUPERVISOR;
-import static brooklyn.entity.messaging.storm.Storm.Role.UI;
-
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.core.util.ResourceUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.enricher.Enrichers;
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.BasicStartableImpl;
-import brooklyn.entity.group.DynamicCluster;
-import brooklyn.entity.zookeeper.ZooKeeperEnsemble;
-
-public class StormDeploymentImpl extends BasicStartableImpl implements StormDeployment {
-
-    @SuppressWarnings("unused")
-    private static final Logger log = LoggerFactory.getLogger(StormDeploymentImpl.class);
-
-    @Override
-    public void init() {
-        super.init();
-        new ResourceUtils(this).checkUrlExists(Storm.STORM_CONFIG_TEMPLATE_URL.getDefaultValue());
-        
-        setDefaultDisplayName("Storm Deployment");
-        
-        ZooKeeperEnsemble zooKeeperEnsemble = addChild(EntitySpec.create(
-            ZooKeeperEnsemble.class).configure(
-                ZooKeeperEnsemble.INITIAL_SIZE, getConfig(ZOOKEEPERS_COUNT)));
-        
-        setConfig(Storm.ZOOKEEPER_ENSEMBLE, zooKeeperEnsemble);
-        
-        Storm nimbus = addChild(EntitySpec.create(Storm.class).configure(ROLE, NIMBUS));
-        
-        setConfig(Storm.NIMBUS_ENTITY, nimbus);
-        setConfig(Storm.START_MUTEX, new Object());
-        
-        addChild(EntitySpec.create(DynamicCluster.class)
-            .configure(DynamicCluster.MEMBER_SPEC, 
-                EntitySpec.create(Storm.class).configure(ROLE, SUPERVISOR))
-            .configure(DynamicCluster.INITIAL_SIZE, getConfig(SUPERVISORS_COUNT))
-            .displayName("Storm Supervisor Cluster"));
-        
-        Storm ui = addChild(EntitySpec.create(Storm.class).configure(ROLE, UI));
-        
-        addEnricher(Enrichers.builder()
-                .propagating(Storm.STORM_UI_URL)
-                .from(ui)
-                .build());
-        addEnricher(Enrichers.builder()
-                .propagating(Attributes.HOSTNAME)
-                .from(nimbus)
-                .build());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDriver.java
deleted file mode 100644
index ddf7481..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDriver.java
+++ /dev/null
@@ -1,27 +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 brooklyn.entity.messaging.storm;
-
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-
-public interface StormDriver extends JavaSoftwareProcessDriver {
-
-    String getJvmOptsLine();
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormImpl.java
deleted file mode 100644
index 57c09e6..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormImpl.java
+++ /dev/null
@@ -1,118 +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 brooklyn.entity.messaging.storm;
-
-import javax.management.ObjectName;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.java.JavaAppUtils;
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.event.feed.jmx.JmxHelper;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-public class StormImpl extends SoftwareProcessImpl implements Storm {
-
-    private static final Logger log = LoggerFactory.getLogger(StormImpl.class);
-
-    public static final ObjectName STORM_MBEAN = JmxHelper.createObjectName("backtype.storm.daemon.nimbus:type=*");
-
-    private JmxHelper jmxHelper;
-    private volatile JmxFeed jmxFeed;
-    
-    public StormImpl() {}
-    
-    @Override
-    public String getHostname() { return getAttribute(HOSTNAME); }
-
-    @Override
-    public Role getRole() { return getConfig(ROLE); }
-
-    @Override
-    public String getStormConfigTemplateUrl() { return getConfig(STORM_CONFIG_TEMPLATE_URL); }   
-    
-    @Override
-    public Class<?> getDriverInterface() {
-        return StormDriver.class;
-    }
-
-    public String getRoleName() { return getRole().name().toLowerCase(); }
-
-    @Override
-    protected void preStart() {
-        setDefaultDisplayName("Storm Node ("+ getRoleName()+")");
-        super.preStart();
-    }
-    
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-
-        // give it plenty of time to start before we advertise ourselves
-        Time.sleep(Duration.TEN_SECONDS);
-
-        if (getRole() == Role.UI) {
-            setAttribute(STORM_UI_URL, "http://"+getAttribute(Attributes.HOSTNAME)+":"+getAttribute(UI_PORT)+"/");
-        }
-
-        if (((JavaSoftwareProcessDriver)getDriver()).isJmxEnabled()) {
-            jmxHelper = new JmxHelper(this);
-//            jmxFeed = JmxFeed.builder()
-//                    .entity(this)
-//                    .period(3000, TimeUnit.MILLISECONDS)
-//                    .helper(jmxHelper)
-//                    .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP_JMX)
-//                            .objectName(STORM_MBEAN)
-//                            .attributeName("Initialized")
-//                            .onSuccess(Functions.forPredicate(Predicates.notNull()))
-//                            .onException(Functions.constant(false)))
-//                    // TODO SERVICE_UP should really be a combo of JMX plus is running
-//                    .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP)
-//                            .objectName(STORM_MBEAN)
-//                            .attributeName("Initialized")
-//                            .onSuccess(Functions.forPredicate(Predicates.notNull()))
-//                            .onException(Functions.constant(false)))
-//                    .build();
-            jmxFeed = JavaAppUtils.connectMXBeanSensors(this);
-            
-            // FIXME for now we do service up based on pid check -- we get a warning that:
-            // JMX object backtype.storm.daemon.nimbus:type=* not found at service:jmx:jmxmp://108.59.82.105:31001
-            // (JMX is up fine, but no such object there)
-            connectServiceUpIsRunning();
-         } else {
-            // if not using JMX
-            log.warn("Storm running without JMX monitoring; limited visibility of service available");
-            connectServiceUpIsRunning();
-        }
-    }
-
-    @Override
-    public void disconnectSensors() {
-        super.disconnectSensors();
-        disconnectServiceUpIsRunning();
-        if (jmxFeed != null) jmxFeed.stop();
-        if (jmxHelper !=null) jmxHelper.terminate();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormSshDriver.java b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormSshDriver.java
deleted file mode 100644
index 76d5bfd..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormSshDriver.java
+++ /dev/null
@@ -1,272 +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 brooklyn.entity.messaging.storm;
-
-import static java.lang.String.format;
-
-import java.util.List;
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.basic.EntityLocal;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
-import brooklyn.entity.zookeeper.ZooKeeperEnsemble;
-import brooklyn.event.basic.DependentConfiguration;
-import org.apache.brooklyn.location.basic.Machines;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.net.Networking;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Supplier;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-public class StormSshDriver extends JavaSoftwareProcessSshDriver implements StormDriver {
-
-    private static final Logger log = LoggerFactory.getLogger(StormSshDriver.class);
-
-    public StormSshDriver(EntityLocal entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    public String getRoleName() {
-        return entity.getConfig(Storm.ROLE).name().toLowerCase();
-    }
-
-    public String getZeromqVersion() {
-        return entity.getConfig(Storm.ZEROMQ_VERSION);
-    }
-
-    public String getLocalDir() {
-        return Optional.fromNullable(entity.getConfig(Storm.LOCAL_DIR)).or(Os.mergePathsUnix(getRunDir(), "storm"));
-    }
-
-    public String getNimbusHostname() {
-        String result = entity.getConfig(Storm.NIMBUS_HOSTNAME);
-        if (result != null) return result;
-
-        Entity nimbus = entity.getConfig(Storm.NIMBUS_ENTITY);
-        if (nimbus == null) {
-            log.warn("No nimbus hostname available; using 'localhost'");
-            return "localhost";
-        }
-        return Entities.submit(entity, DependentConfiguration.attributeWhenReady(nimbus, Attributes.HOSTNAME)).getUnchecked();
-    }
-
-    public Integer getUiPort() {
-        return entity.getAttribute(Storm.UI_PORT);
-    }
-
-    public Map<String, Integer> getPortMap() {
-        return MutableMap.of("uiPort", getUiPort());
-    }
-
-    @Override
-    protected List<String> getCustomJavaConfigOptions() {
-        List<String> result = super.getCustomJavaConfigOptions();
-        if ("nimbus".equals(getRoleName()) || "supervisor".equals(getRoleName())) {
-            result.add("-verbose:gc");
-            result.add("-XX:+PrintGCTimeStamps");
-            result.add("-XX:+PrintGCDetails");
-        }
-
-        if ("ui".equals(getRoleName())) {
-            result.add("-Xmx768m");
-        }
-
-        return result;
-    }
-
-    public String getJvmOptsLine() {
-        return Optional.fromNullable(getShellEnvironment().get("JAVA_OPTS")).or("");
-    }
-    
-    public List<String> getZookeeperServers() {
-        ZooKeeperEnsemble zooKeeperEnsemble = entity.getConfig(Storm.ZOOKEEPER_ENSEMBLE);
-        Supplier<List<String>> supplier = Entities.attributeSupplierWhenReady(zooKeeperEnsemble, ZooKeeperEnsemble.ZOOKEEPER_SERVERS);
-        return supplier.get();
-    }
-
-    public String getStormConfigTemplateUrl() {
-        return entity.getConfig(Storm.STORM_CONFIG_TEMPLATE_URL);
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("storm-%s", getVersion()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-        
-        ImmutableList.Builder<String> commands= ImmutableList.<String> builder();
-        if (!getLocation().getOsDetails().isMac()) {
-            commands.add(BashCommands.installPackage(ImmutableMap.of(
-                        "yum", "libuuid-devel",
-                        "apt", "build-essential uuid-dev pkg-config libtool automake"), 
-                    "libuuid-devel"));
-            commands.add(BashCommands.ifExecutableElse0("yum", BashCommands.sudo("yum -y groupinstall 'Development Tools'")));
-        }
-        commands.add(BashCommands.installPackage(ImmutableMap.of("yum", "git"), "git"))
-                .add(BashCommands.INSTALL_UNZIP)
-                .addAll(installNativeDependencies())
-                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
-                .add("unzip " + saveAs)
-                .add("mkdir -p " + getLocalDir())
-                .add("chmod 777 " + getLocalDir()); // FIXME
-        newScript(INSTALLING)
-                .body.append(commands.build())
-                .gatherOutput()
-                .execute();
-    }
-
-    public String getPidFile() {
-        return Os.mergePathsUnix(getRunDir(), format("%s.pid", getRoleName()));
-    }
-
-    @Override
-    protected String getLogFileLocation() {
-        return Os.mergePathsUnix(getRunDir(), "logs", format("%s.log", getRoleName()));
-    }
-
-    @Override
-    public void launch() {
-        boolean needsSleep = false;
-        if (getRoleName().equals("supervisor")) {
-            Entity nimbus = entity.getConfig(Storm.NIMBUS_ENTITY);
-            if (nimbus == null) {
-                log.warn("No nimbus entity available; not blocking before starting supervisors");
-            } else {
-                Entities.waitForServiceUp(nimbus, entity.getConfig(SoftwareProcess.START_TIMEOUT));
-                needsSleep = true;
-            }
-        }
-
-        String subnetHostname = Machines.findSubnetOrPublicHostname(entity).get();
-        log.info("Launching " + entity + " with role " + getRoleName() + " and " + "hostname (public) " 
-                + getEntity().getAttribute(Attributes.HOSTNAME) + ", " + "hostname (subnet) " + subnetHostname + ")");
-
-        // ensure only one node at a time tries to start
-        // attempting to eliminate the causes of:
-        // 2013-12-12 09:21:45 supervisor [ERROR] Error on initialization of server mk-supervisor
-        // org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for /assignments
-        // TODO use SoftwareProcess#START_LATCH instead here?
-
-        Object startMutex = Optional.fromNullable(entity.getConfig(Storm.START_MUTEX)).or(new Object());
-        synchronized (startMutex) {
-            if (needsSleep) {
-                // give 10s extra to make sure nimbus is ready; we see weird zookeeper no /assignments node error otherwise
-                // (this could be optimized by recording nimbus service_up time)
-                Time.sleep(Duration.TEN_SECONDS);
-            }
-            newScript(MutableMap.of(USE_PID_FILE, getPidFile()), LAUNCHING)
-                    .body.append(format("nohup ./bin/storm %s > %s 2>&1 &", getRoleName(), getLogFileLocation()))
-                    .execute();
-        }
-    }
-
-    @Override
-    public boolean isRunning() {
-        return newScript(MutableMap.of(USE_PID_FILE, getPidFile()), CHECK_RUNNING).execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        newScript(MutableMap.of(USE_PID_FILE, getPidFile()), STOPPING).execute();
-    }
-
-    @Override
-    public void customize() {
-        log.debug("Customizing {}", entity);
-        Networking.checkPortsValid(getPortMap());
-
-        newScript(CUSTOMIZING)
-                .body.append(format("cp -R %s/* .", getExpandedInstallDir()))
-                .execute();
-
-        String destinationConfigFile = Os.mergePathsUnix(getRunDir(), "conf/storm.yaml");
-        copyTemplate(getStormConfigTemplateUrl(), destinationConfigFile);
-    }
-
-    protected List<String> installNativeDependencies() {
-        String zeromqUrl = format("http://download.zeromq.org/zeromq-%s.tar.gz", getZeromqVersion());
-        String targz = format("zeromq-%s.tar.gz", getZeromqVersion());
-        String jzmq = "https://github.com/nathanmarz/jzmq.git";
-
-        ImmutableList.Builder<String> commands = ImmutableList.<String>builder();
-        if (getLocation().getOsDetails().isMac()) {
-            commands.add("export PATH=$PATH:/usr/local/bin")
-                   .add("export JAVA_HOME=$(/usr/libexec/java_home)")
-                   .add("cd " + getInstallDir())
-                   .add(BashCommands.installPackage(ImmutableMap.of("brew", "automake"), "make"))
-                   .add(BashCommands.installPackage(ImmutableMap.of("brew", "libtool"), "libtool"))
-                   .add(BashCommands.installPackage(ImmutableMap.of("brew", "pkg-config"), "pkg-config"))
-                   .add(BashCommands.installPackage(ImmutableMap.of("brew", "zeromq"), "zeromq"))
-                   .add("git clone https://github.com/asmaier/jzmq")
-                   .add("cd jzmq")
-                   .add("./autogen.sh")
-                   .add("./configure")
-                   .add("make")
-                   .add((BashCommands.sudo("make install")))
-                   .add("cd " + getInstallDir());
-        } else {
-            commands.add("export JAVA_HOME=$(dirname $(readlink -m `which java`))/../../ || export JAVA_HOME=/usr/lib/jvm/java")
-                   .add("cd " + getInstallDir())
-                   .add(BashCommands.commandToDownloadUrlAs(zeromqUrl, targz))
-                   .add("tar xzf " + targz)
-                   .add(format("cd zeromq-%s", getZeromqVersion()))
-                   .add("./configure")
-                   .add("make")
-                   .add((BashCommands.sudo("make install")))
-                   // install jzmq
-                   .add("cd " + getInstallDir())
-                   .add("git clone " + jzmq)
-                   .add("cd jzmq")
-                   .add("./autogen.sh")
-                   .add("./configure")
-                           
-                   // hack needed on ubuntu 12.04; ignore if it fails
-                   // see https://github.com/zeromq/jzmq/issues/114
-                   .add(BashCommands.ok(
-                       "pushd src ; touch classdist_noinst.stamp ; CLASSPATH=.:./.:$CLASSPATH "
-                       + "javac -d . org/zeromq/ZMQ.java org/zeromq/App.java org/zeromq/ZMQForwarder.java org/zeromq/EmbeddedLibraryTools.java org/zeromq/ZMQQueue.java org/zeromq/ZMQStreamer.java org/zeromq/ZMQException.java"))
-                   .add(BashCommands.ok("popd"))
-
-                   .add("make")
-                   .add((BashCommands.sudo("make install")))
-                   .add("cd " + getInstallDir());
-        }
-        return commands.build();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/zookeeper/AbstractZooKeeperImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/zookeeper/AbstractZooKeeperImpl.java b/software/messaging/src/main/java/brooklyn/entity/zookeeper/AbstractZooKeeperImpl.java
deleted file mode 100644
index 6e14a42..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/zookeeper/AbstractZooKeeperImpl.java
+++ /dev/null
@@ -1,109 +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 brooklyn.entity.zookeeper;
-
-import java.util.concurrent.TimeUnit;
-
-import javax.management.ObjectName;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-import brooklyn.event.feed.jmx.JmxAttributePollConfig;
-import brooklyn.event.feed.jmx.JmxFeed;
-import brooklyn.event.feed.jmx.JmxHelper;
-
-import com.google.common.base.Functions;
-import com.google.common.base.Objects.ToStringHelper;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Apache ZooKeeper instance.
- */
-public abstract class AbstractZooKeeperImpl extends SoftwareProcessImpl implements ZooKeeperNode {
-
-    @SuppressWarnings("unused")
-    private static final Logger log = LoggerFactory.getLogger(AbstractZooKeeperImpl.class);
-    private static final ObjectName ZOOKEEPER_MBEAN = JmxHelper.createObjectName("org.apache.ZooKeeperService:name0=StandaloneServer_port-1");
-
-    private volatile JmxFeed jmxFeed;
-
-    public AbstractZooKeeperImpl() {
-    }
-
-    @Override
-    public Integer getZookeeperPort() { return getAttribute(ZOOKEEPER_PORT); }
-
-    @Override
-    public String getHostname() { return getAttribute(HOSTNAME); }
-
-    @Override
-    public void waitForServiceUp(long duration, TimeUnit units) {
-        super.waitForServiceUp(duration, units);
-
-        if (((JavaSoftwareProcessDriver)getDriver()).isJmxEnabled()) {
-            // Wait for the MBean to exist
-            JmxHelper helper = new JmxHelper(this);
-            try {
-                helper.assertMBeanExistsEventually(ZOOKEEPER_MBEAN, units.toMillis(duration));
-            } finally {
-                helper.terminate();
-            }
-        }
-    }
-
-    @Override
-    protected void connectSensors() {
-        connectServiceUpIsRunning();
-
-        if (((JavaSoftwareProcessDriver)getDriver()).isJmxEnabled()) {
-            jmxFeed = JmxFeed.builder()
-                .entity(this)
-                .period(500, TimeUnit.MILLISECONDS)
-                .pollAttribute(new JmxAttributePollConfig<Long>(OUTSTANDING_REQUESTS)
-                        .objectName(ZOOKEEPER_MBEAN)
-                        .attributeName("OutstandingRequests")
-                        .onFailureOrException(Functions.constant(-1l)))
-                .pollAttribute(new JmxAttributePollConfig<Long>(PACKETS_RECEIVED)
-                        .objectName(ZOOKEEPER_MBEAN)
-                        .attributeName("PacketsReceived")
-                        .onFailureOrException(Functions.constant(-1l)))
-                .pollAttribute(new JmxAttributePollConfig<Long>(PACKETS_SENT)
-                        .objectName(ZOOKEEPER_MBEAN)
-                        .attributeName("PacketsSent")
-                        .onFailureOrException(Functions.constant(-1l)))
-                .build();
-        }
-    }
-
-    @Override
-    public void disconnectSensors() {
-        super.disconnectSensors();
-        disconnectServiceUpIsRunning();
-        if (jmxFeed != null) jmxFeed.stop();
-    }
-
-    @Override
-    protected ToStringHelper toStringHelper() {
-        return super.toStringHelper()
-                .add("zookeeperPort", getZookeeperPort());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperDriver.java b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperDriver.java
deleted file mode 100644
index 7dca734..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperDriver.java
+++ /dev/null
@@ -1,27 +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 brooklyn.entity.zookeeper;
-
-import brooklyn.entity.java.JavaSoftwareProcessDriver;
-
-public interface ZooKeeperDriver extends JavaSoftwareProcessDriver {
-
-    Integer getZooKeeperPort();
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java
deleted file mode 100644
index e5869c5..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsemble.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 brooklyn.entity.zookeeper;
-
-import java.util.List;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.group.DynamicCluster;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.Sensors;
-
-import com.google.common.reflect.TypeToken;
-
-@Catalog(name="ZooKeeper ensemble", description="A cluster of ZooKeeper servers. "
-        + "Apache ZooKeeper enables highly reliable distributed coordination.")
-@ImplementedBy(ZooKeeperEnsembleImpl.class)
-public interface ZooKeeperEnsemble extends DynamicCluster {
-
-    @SetFromFlag("clusterName")
-    BasicAttributeSensorAndConfigKey<String> CLUSTER_NAME = new BasicAttributeSensorAndConfigKey<String>(String
-            .class, "zookeeper.cluster.name", "Name of the Zookeeper cluster", "BrooklynZookeeperCluster");
-
-    @SetFromFlag("initialSize")
-    public static final ConfigKey<Integer> INITIAL_SIZE = ConfigKeys.newConfigKeyWithDefault(DynamicCluster.INITIAL_SIZE, 3);
-
-    @SuppressWarnings("serial")
-    AttributeSensor<List<String>> ZOOKEEPER_SERVERS = Sensors.newSensor(new TypeToken<List<String>>() { },
-            "zookeeper.servers", "Hostnames to connect to cluster with");
-
-    String getClusterName();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java
deleted file mode 100644
index eedcfe8..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsembleImpl.java
+++ /dev/null
@@ -1,105 +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 brooklyn.entity.zookeeper;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.proxying.EntitySpec;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.policy.PolicySpec;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.Attributes;
-import brooklyn.entity.basic.EntityInternal;
-import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
-import brooklyn.entity.group.DynamicClusterImpl;
-
-import com.google.common.collect.Lists;
-
-public class ZooKeeperEnsembleImpl extends DynamicClusterImpl implements ZooKeeperEnsemble {
-
-    private static final Logger log = LoggerFactory.getLogger(ZooKeeperEnsembleImpl.class);
-    private static final AtomicInteger myId = new AtomicInteger();
-    
-    private MemberTrackingPolicy policy;
-
-    public ZooKeeperEnsembleImpl() {}
-
-    /**
-     * Sets the default {@link #MEMBER_SPEC} to describe the ZooKeeper nodes.
-     */
-    @Override
-    protected EntitySpec<?> getMemberSpec() {
-        return getConfig(MEMBER_SPEC, EntitySpec.create(ZooKeeperNode.class));
-    }
-
-    @Override
-    public String getClusterName() {
-        return getAttribute(CLUSTER_NAME);
-    }
-
-    @Override
-    public void init() {
-        log.info("Initializing the ZooKeeper Ensemble");
-        super.init();
-
-        policy = addPolicy(PolicySpec.create(MemberTrackingPolicy.class)
-                .displayName("Members tracker")
-                .configure("group", this));
-    }
-
-    public static class MemberTrackingPolicy extends AbstractMembershipTrackingPolicy {
-        @Override
-        protected void onEntityChange(Entity member) {
-        }
-
-        @Override
-        protected void onEntityAdded(Entity member) {
-            if (member.getAttribute(ZooKeeperNode.MY_ID) == null) {
-                ((EntityInternal) member).setAttribute(ZooKeeperNode.MY_ID, myId.incrementAndGet());
-            }
-        }
-
-        @Override
-        protected void onEntityRemoved(Entity member) {
-        }
-    };
-
-    @Override
-    protected void initEnrichers() {
-        super.initEnrichers();
-        
-    }
-    
-    @Override
-    public void start(Collection<? extends Location> locations) {
-        super.start(locations);
-        
-        List<String> zookeeperServers = Lists.newArrayList();
-        for (Entity zookeeper : getMembers()) {
-            zookeeperServers.add(zookeeper.getAttribute(Attributes.HOSTNAME));
-        }
-        setAttribute(ZOOKEEPER_SERVERS, zookeeperServers);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNode.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNode.java b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNode.java
deleted file mode 100644
index 504a894..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNode.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 brooklyn.entity.zookeeper;
-
-import org.apache.brooklyn.api.catalog.Catalog;
-import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.core.util.flags.SetFromFlag;
-
-import brooklyn.config.ConfigKey;
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.SoftwareProcess;
-import brooklyn.event.basic.BasicAttributeSensor;
-import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Apache ZooKeeper instance.
- */
-@Catalog(name="ZooKeeper Node", description="Apache ZooKeeper is a server which enables "
-        + "highly reliable distributed coordination.")
-@ImplementedBy(ZooKeeperNodeImpl.class)
-public interface ZooKeeperNode extends SoftwareProcess {
-
-    @SetFromFlag("version")
-    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "3.4.5");
-    @SetFromFlag("zookeeperPort")
-    PortAttributeSensorAndConfigKey ZOOKEEPER_PORT = new PortAttributeSensorAndConfigKey("zookeeper.port", "Zookeeper port", "2181+");
-    @SetFromFlag("zookeeperLeaderPort")
-    PortAttributeSensorAndConfigKey ZOOKEEPER_LEADER_PORT = new PortAttributeSensorAndConfigKey("zookeeper.leader.port", "Zookeeper leader ports", "2888+");
-    @SetFromFlag("zookeeperElectionPort")
-    PortAttributeSensorAndConfigKey ZOOKEEPER_ELECTION_PORT = new PortAttributeSensorAndConfigKey("zookeeper.election.port", "Zookeeper election ports", "3888+");
-    @SetFromFlag("downloadUrl")
-    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
-            SoftwareProcess.DOWNLOAD_URL, "http://apache.fastbull.org/zookeeper/zookeeper-${version}/zookeeper-${version}.tar.gz");
-    /**
-     * Location of the ZK configuration file template to be copied to the server.
-     */
-    @SetFromFlag("zookeeperConfig")
-    ConfigKey<String> ZOOKEEPER_CONFIG_TEMPLATE = ConfigKeys.newStringConfigKey(
-            "zookeeper.configTemplate", "Zookeeper configuration template (in freemarker format)",
-            "classpath://brooklyn/entity/messaging/zookeeper/zoo.cfg");
-    AttributeSensor<Long> OUTSTANDING_REQUESTS = new BasicAttributeSensor<Long>(Long.class, "zookeeper.outstandingRequests", "Outstanding request count");
-    AttributeSensor<Long> PACKETS_RECEIVED = new BasicAttributeSensor<Long>(Long.class, "zookeeper.packets.received", "Total packets received");
-    AttributeSensor<Long> PACKETS_SENT = new BasicAttributeSensor<Long>(Long.class, "zookeeper.packets.sent", "Total packets sent");
-    AttributeSensor<Integer> MY_ID = new BasicAttributeSensor<Integer>(Integer.class, "zookeeper.myid", "ZooKeeper node's myId");
-
-    Integer getZookeeperPort();
-
-    String getHostname();
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNodeImpl.java b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNodeImpl.java
deleted file mode 100644
index 0346d02..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNodeImpl.java
+++ /dev/null
@@ -1,33 +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 brooklyn.entity.zookeeper;
-
-/**
- * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single standalone zookeeper instance.
- */
-public class ZooKeeperNodeImpl extends AbstractZooKeeperImpl implements ZooKeeperNode {
-
-    public ZooKeeperNodeImpl() {}
-
-    @Override
-    public Class<?> getDriverInterface() {
-        return ZooKeeperDriver.class;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperSshDriver.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperSshDriver.java b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperSshDriver.java
deleted file mode 100644
index 2683682..0000000
--- a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperSshDriver.java
+++ /dev/null
@@ -1,163 +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 brooklyn.entity.zookeeper;
-
-import static java.lang.String.format;
-
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
-import org.apache.brooklyn.api.entity.Entity;
-
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.net.Networking;
-import brooklyn.util.os.Os;
-import brooklyn.util.ssh.BashCommands;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-public class ZooKeeperSshDriver extends JavaSoftwareProcessSshDriver implements ZooKeeperDriver {
-
-    public ZooKeeperSshDriver(ZooKeeperNodeImpl entity, SshMachineLocation machine) {
-        super(entity, machine);
-    }
-
-    @Override
-    protected String getLogFileLocation() { return Os.mergePathsUnix(getRunDir(), "console.out"); }
-
-    protected Map<String, Integer> getPortMap() {
-        return MutableMap.of("zookeeperPort", getZooKeeperPort());
-    }
-
-    protected String getConfigFileName() {
-        return entity.getConfig(ZooKeeperNode.ZOOKEEPER_CONFIG_TEMPLATE);
-    }
-
-    protected int getMyId() {
-        return entity.getAttribute(ZooKeeperNode.MY_ID);
-    }
-
-    // FIXME All for one, and one for all! If any node fails then we're stuck waiting for its hostname/port forever.
-    // Need a way to terminate the wait based on the entity going on-fire etc.
-    // FIXME Race in getMemebers. Should we change DynamicCluster.grow to create the members and only then call start on them all?
-    public List<ZooKeeperServerConfig> getZookeeperServers() throws ExecutionException, InterruptedException {
-        ZooKeeperEnsemble ensemble = (ZooKeeperEnsemble) entity.getParent();
-        List<ZooKeeperServerConfig> result = Lists.newArrayList();
-
-        for (Entity member : ensemble.getMembers()) {
-            Integer myid = Entities.attributeSupplierWhenReady(member, ZooKeeperNode.MY_ID).get();
-            String hostname = Entities.attributeSupplierWhenReady(member, ZooKeeperNode.HOSTNAME).get();
-            Integer port = Entities.attributeSupplierWhenReady(member, ZooKeeperNode.ZOOKEEPER_PORT).get();
-            Integer leaderPort = Entities.attributeSupplierWhenReady(member, ZooKeeperNode.ZOOKEEPER_LEADER_PORT).get();
-            Integer electionPort = Entities.attributeSupplierWhenReady(member, ZooKeeperNode.ZOOKEEPER_ELECTION_PORT).get();
-            result.add(new ZooKeeperServerConfig(myid, hostname, port, leaderPort, electionPort));
-        }
-        return result;
-    }
-
-    @Override
-    public Integer getZooKeeperPort() {
-        return getEntity().getAttribute(ZooKeeperNode.ZOOKEEPER_PORT);
-    }
-
-    @Override
-    public boolean isRunning() {
-        return newScript(MutableMap.of(USE_PID_FILE, getPidFile()), CHECK_RUNNING).execute() == 0;
-    }
-
-    @Override
-    public void stop() {
-        newScript(ImmutableMap.of(USE_PID_FILE, getPidFile()), STOPPING).execute();     
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(format("zookeeper-%s", getVersion()))));
-    }
-
-    @Override
-    public void install() {
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-
-        List<String> commands = ImmutableList.<String> builder()
-                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
-                .add(BashCommands.INSTALL_TAR)
-                .add("tar xzfv " + saveAs)
-                .build();
-
-        newScript(INSTALLING)
-                .body.append(commands)
-                .execute();
-    }
-
-    @Override
-    public void customize() {
-        log.debug("Customizing {}", entity);
-        Networking.checkPortsValid(getPortMap());
-        newScript(CUSTOMIZING)
-                .body.append(
-                        format("cp -R %s/* .", getExpandedInstallDir()),
-                        format("mkdir %s/zookeeper", getRunDir()),
-                        format("echo %d > %s/zookeeper/myid", getMyId(), getRunDir())
-                    )
-                .execute();
-
-        String destinationConfigFile = Os.mergePathsUnix(getRunDir(), "conf/zoo.cfg");
-        copyTemplate(getConfigFileName(), destinationConfigFile);
-    }
-
-    public String getPidFile() { return Os.mergePathsUnix(getRunDir(), "zookeeper.pid"); }
-
-    @Override
-    public void launch() {
-        newScript(MutableMap.of(USE_PID_FILE, getPidFile()), LAUNCHING)
-                .body.append(format("nohup java $JAVA_OPTS -cp zookeeper-%s.jar:lib/*:conf org.apache.zookeeper.server.quorum.QuorumPeerMain conf/zoo.cfg > %s 2>&1 &", getVersion(), getLogFileLocation()))
-                .execute();
-    }
-
-    public static class ZooKeeperServerConfig {
-        private final Integer myid;
-        private final String hostname;
-        private final Integer port;
-        private final Integer leaderPort;
-        private final Integer electionPort;
-
-        public ZooKeeperServerConfig(Integer myid, String hostname, Integer port, Integer leaderPort, Integer electionPort) {
-            this.myid = myid;
-            this.hostname = hostname;
-            this.port = port;
-            this.leaderPort = leaderPort;
-            this.electionPort = electionPort;
-        }
-
-        public Integer getMyid() { return myid; }
-        public String getHostname() { return hostname; }
-        public Integer getPort() { return port; }
-        public Integer getLeaderPort() { return leaderPort; }
-        public Integer getElectionPort() { return electionPort; }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..2d22e03
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/MessageBroker.java
@@ -0,0 +1,34 @@
+/*
+ * 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.entity.messaging;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.event.AttributeSensor;
+
+import brooklyn.event.basic.Sensors;
+
+/**
+ * Marker interface identifying message brokers.
+ */
+public interface MessageBroker extends Entity {
+    AttributeSensor<String> BROKER_URL = Sensors.newStringSensor("broker.url", "Broker Connection URL");
+
+    /** Setup the URL for external connections to the broker. */
+    void setBrokerUrl();
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..9c1aca5
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Queue.java
@@ -0,0 +1,51 @@
+/*
+ * 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.entity.messaging;
+
+import org.apache.brooklyn.api.event.AttributeSensor;
+
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.Sensors;
+
+/**
+ * An interface that describes a messaging queue.
+ */
+public interface Queue {
+    BasicAttributeSensorAndConfigKey<String> QUEUE_NAME = new BasicAttributeSensorAndConfigKey<String>(String.class, "queue.name", "Queue name");
+
+    AttributeSensor<Integer> QUEUE_DEPTH_BYTES = Sensors.newIntegerSensor("queue.depth.bytes", "Queue depth in bytes");
+    AttributeSensor<Integer> QUEUE_DEPTH_MESSAGES = Sensors.newIntegerSensor("queue.depth.messages", "Queue depth in messages");
+    
+    /**
+     * Create the queue.
+     *
+     * TODO make this an effector
+     */
+    abstract void create();
+
+    /**
+     * Delete the queue.
+     *
+     * TODO make this an effector
+     */
+    abstract void delete();
+
+    String getQueueName();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..ac71226
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/Topic.java
@@ -0,0 +1,46 @@
+/*
+ * 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.entity.messaging;
+
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+
+/**
+ * An interface that describes a messaging topic.
+ */
+public interface Topic {
+    BasicAttributeSensorAndConfigKey<String> TOPIC_NAME = new BasicAttributeSensorAndConfigKey<String>(
+            String.class, "topic.name", "Topic name");
+
+    /**
+     * Create the topic.
+     * 
+     * TODO make this an effector
+     */
+    public abstract void create();
+
+    /**
+     * Delete the topic.
+     * 
+     * TODO make this an effector
+     */
+    public abstract void delete();
+
+    String getTopicName();
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..9ec63f6
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBroker.java
@@ -0,0 +1,81 @@
+/*
+ * 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.entity.messaging.activemq;
+
+import org.apache.brooklyn.api.catalog.Catalog;
+import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.Attributes;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.SoftwareProcess;
+import brooklyn.entity.java.UsesJmx;
+import org.apache.brooklyn.entity.messaging.MessageBroker;
+import org.apache.brooklyn.entity.messaging.jms.JMSBroker;
+import brooklyn.event.basic.AttributeSensorAndConfigKey;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
+import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
+import brooklyn.event.basic.BasicConfigKey;
+import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+import brooklyn.util.time.Duration;
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single ActiveMQ broker instance.
+ */
+@Catalog(name="ActiveMQ Broker", description="ActiveMQ is an open source message broker which fully implements the Java Message Service 1.1 (JMS)", iconUrl="classpath:///activemq-logo.png")
+@ImplementedBy(ActiveMQBrokerImpl.class)
+public interface ActiveMQBroker extends SoftwareProcess, MessageBroker, UsesJmx, JMSBroker<ActiveMQQueue, ActiveMQTopic> {
+
+    @SetFromFlag("startTimeout")
+    ConfigKey<Duration> START_TIMEOUT = SoftwareProcess.START_TIMEOUT;
+    
+    @SetFromFlag("version")
+    public static final ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "5.10.2");
+
+    @SetFromFlag("downloadUrl")
+    public static final AttributeSensorAndConfigKey<String,String> DOWNLOAD_URL = new StringAttributeSensorAndConfigKey(
+            Attributes.DOWNLOAD_URL, "${driver.mirrorUrl}/${version}/apache-activemq-${version}-bin.tar.gz");
+
+    /** download mirror, if desired */
+    @SetFromFlag("mirrorUrl")
+    public static final BasicConfigKey<String> MIRROR_URL = new BasicConfigKey<String>(String.class, "activemq.install.mirror.url", "URL of mirror",
+        "http://www.mirrorservice.org/sites/ftp.apache.org/activemq");
+
+    @SetFromFlag("brokerName")
+    public static final AttributeSensorAndConfigKey<String,String> BROKER_NAME = 
+        ConfigKeys.newStringSensorAndConfigKey("activemq.brokerName", "ActiveMQ Broker Name", "localhost");
+
+    @SetFromFlag("openWirePort")
+    public static final PortAttributeSensorAndConfigKey OPEN_WIRE_PORT = new PortAttributeSensorAndConfigKey("openwire.port", "OpenWire port", "61616+");
+
+    @SetFromFlag("jettyPort")
+    public static final PortAttributeSensorAndConfigKey AMQ_JETTY_PORT = new PortAttributeSensorAndConfigKey("activemq.jetty.port", "jetty port", "8161+");
+
+    @SetFromFlag("jmxUser")
+    public static final BasicAttributeSensorAndConfigKey<String> JMX_USER = new BasicAttributeSensorAndConfigKey<String>(UsesJmx.JMX_USER, "admin");
+    
+    @SetFromFlag("jmxPassword")
+    public static final BasicAttributeSensorAndConfigKey<String> JMX_PASSWORD = new BasicAttributeSensorAndConfigKey<String>(UsesJmx.JMX_PASSWORD, "admin");
+    
+    @SetFromFlag("templateConfigurationUrl")
+    public static final BasicAttributeSensorAndConfigKey<String> TEMPLATE_CONFIGURATION_URL = new BasicAttributeSensorAndConfigKey<String>(
+            String.class, "activemq.templateConfigurationUrl", "Template file (in freemarker format) for the conf/activemq.xml file", 
+            "classpath://org/apache/brooklyn/entity/messaging/activemq/activemq.xml");
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..3907d76
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQBrokerImpl.java
@@ -0,0 +1,124 @@
+/*
+ * 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.entity.messaging.activemq;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.java.UsesJmx;
+import org.apache.brooklyn.entity.messaging.jms.JMSBrokerImpl;
+import brooklyn.event.feed.jmx.JmxAttributePollConfig;
+import brooklyn.event.feed.jmx.JmxFeed;
+
+import com.google.common.base.Functions;
+import com.google.common.base.Objects.ToStringHelper;
+import com.google.common.base.Predicates;
+/**
+ * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single ActiveMQ broker instance.
+ */
+public class ActiveMQBrokerImpl extends JMSBrokerImpl<ActiveMQQueue, ActiveMQTopic> implements ActiveMQBroker {
+    private static final Logger log = LoggerFactory.getLogger(ActiveMQBrokerImpl.class);
+
+    private volatile JmxFeed jmxFeed;
+
+    public ActiveMQBrokerImpl() {
+        super();
+    }
+
+    @Override
+    public void init() {
+        super.init();
+        Entities.getRequiredUrlConfig(this, TEMPLATE_CONFIGURATION_URL);
+    }
+    
+    public void setBrokerUrl() {
+        setAttribute(BROKER_URL, String.format("tcp://%s:%d", getAttribute(HOSTNAME), getAttribute(OPEN_WIRE_PORT)));
+    }
+    
+    public Integer getJmxPort() {
+        return !isJmxEnabled() ? Integer.valueOf(-1) : getAttribute(UsesJmx.JMX_PORT);
+    }
+    
+    public String getBrokerName() {
+        return getAttribute(BROKER_NAME);
+    }
+    
+    public Integer getOpenWirePort() {
+        return getAttribute(OPEN_WIRE_PORT);
+    }
+    
+    public boolean isJmxEnabled() {
+        return Boolean.TRUE.equals(getConfig(USE_JMX));
+    }
+
+    @Override
+    public ActiveMQQueue createQueue(Map properties) {
+        ActiveMQQueue result = addChild(EntitySpec.create(ActiveMQQueue.class).configure(properties));
+        Entities.manage(result);
+        result.create();
+        return result;
+    }
+
+    @Override
+    public ActiveMQTopic createTopic(Map properties) {
+        ActiveMQTopic result = addChild(EntitySpec.create(ActiveMQTopic.class).configure(properties));
+        Entities.manage(result);
+        result.create();
+        return result;
+    }
+
+    @Override     
+    protected void connectSensors() {
+        setAttribute(BROKER_URL, String.format("tcp://%s:%d", getAttribute(HOSTNAME), getAttribute(OPEN_WIRE_PORT)));
+        
+        String brokerMbeanName = "org.apache.activemq:type=Broker,brokerName=" + getBrokerName();
+        
+        jmxFeed = JmxFeed.builder()
+                .entity(this)
+                .period(500, TimeUnit.MILLISECONDS)
+                .pollAttribute(new JmxAttributePollConfig<Boolean>(SERVICE_UP)
+                        .objectName(brokerMbeanName)
+                        .attributeName("BrokerName")
+                        .onSuccess(Functions.forPredicate(Predicates.notNull()))
+                        .onFailureOrException(Functions.constant(false))
+                        .suppressDuplicates(true))
+                .build();
+    }
+
+    @Override
+    public void disconnectSensors() {
+        super.disconnectSensors();
+        if (jmxFeed != null) jmxFeed.stop();
+    }
+
+    @Override
+    protected ToStringHelper toStringHelper() {
+        return super.toStringHelper().add("openWirePort", getAttribute(OPEN_WIRE_PORT));
+    }
+
+    @Override
+    public Class getDriverInterface() {
+        return ActiveMQDriver.class;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDestination.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDestination.java b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDestination.java
new file mode 100644
index 0000000..c941ac1
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDestination.java
@@ -0,0 +1,24 @@
+/*
+ * 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.entity.messaging.activemq;
+
+import org.apache.brooklyn.entity.messaging.jms.JMSDestination;
+
+public interface ActiveMQDestination extends JMSDestination {
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/c14fef53/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
new file mode 100644
index 0000000..becd7d0
--- /dev/null
+++ b/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/activemq/ActiveMQDestinationImpl.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.entity.messaging.activemq;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.basic.EntityLocal;
+
+import com.google.common.base.Preconditions;
+
+import org.apache.brooklyn.entity.messaging.jms.JMSDestinationImpl;
+import brooklyn.event.feed.jmx.JmxFeed;
+import brooklyn.event.feed.jmx.JmxHelper;
+import brooklyn.util.exceptions.Exceptions;
+
+public abstract class ActiveMQDestinationImpl extends JMSDestinationImpl implements ActiveMQDestination {
+    protected ObjectName brokerMBeanName;
+    protected transient JmxHelper jmxHelper;
+    protected volatile JmxFeed jmxFeed;
+
+    public ActiveMQDestinationImpl() {
+    }
+    
+    @Override
+    public void onManagementStarting() {
+        super.onManagementStarting();
+
+        String brokerName = getBrokerName();
+        Preconditions.checkArgument(brokerName != null && !brokerName.isEmpty(), "ActiveMQ brokerName attribute must be specified");
+
+        try {
+            brokerMBeanName = new ObjectName("org.apache.activemq:type=Broker,brokerName=" + brokerName);
+            jmxHelper = new JmxHelper((EntityLocal) getParent());
+        } catch (MalformedObjectNameException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    @Override
+    protected void disconnectSensors() {
+        if (jmxFeed != null) jmxFeed.stop();
+    }
+    
+    protected String getBrokerName() {
+        Preconditions.checkNotNull(getParent(), "JMS Destination must have a broker parent");
+        return getParent().getAttribute(ActiveMQBroker.BROKER_NAME);
+    }
+}



[62/64] incubator-brooklyn git commit: This closes #827

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


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

Branch: refs/heads/master
Commit: bdd8ef99e4d2e42e6cd4ee41f9b732e0b506ac0e
Parents: ab3a3db ac1a7c0
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Aug 18 11:31:16 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 18 11:31:16 2015 +0100

----------------------------------------------------------------------
 docs/guide/start/_my-web-cluster.yaml           |   2 +-
 .../appserver-clustered-w-db-concise.yaml       |   2 +-
 .../example_yaml/appserver-clustered-w-db.yaml  |   2 +-
 .../appserver-w-db-other-flavor.yaml            |   2 +-
 .../guide/yaml/example_yaml/appserver-w-db.yaml |   2 +-
 .../yaml/example_yaml/appserver-w-policy.yaml   |   2 +-
 .../demo/WebClusterDatabaseExample.java         |   2 +-
 .../demo/WebClusterDatabaseExampleApp.java      |   2 +-
 ...lusterDatabaseExampleAppIntegrationTest.java |   2 +-
 .../postgresql/PostgreSqlNodeSaltImpl.java      |   2 +-
 .../postgresql/PostgreSqlSaltLiveTest.java      |   6 +-
 software/database/pom.xml                       |  18 +-
 .../brooklyn/entity/database/DatabaseNode.java  |  29 --
 .../entity/database/DatastoreMixins.java        | 104 ----
 .../entity/database/crate/CrateNode.java        |  92 ----
 .../entity/database/crate/CrateNodeDriver.java  |  24 -
 .../entity/database/crate/CrateNodeImpl.java    |  99 ----
 .../database/crate/CrateNodeSshDriver.java      | 118 -----
 .../entity/database/mariadb/MariaDbDriver.java  |  31 --
 .../entity/database/mariadb/MariaDbNode.java    | 100 ----
 .../database/mariadb/MariaDbNodeImpl.java       | 139 -----
 .../database/mariadb/MariaDbSshDriver.java      | 259 ----------
 .../entity/database/mysql/MySqlCluster.java     |  68 ---
 .../entity/database/mysql/MySqlClusterImpl.java | 445 ----------------
 .../entity/database/mysql/MySqlDriver.java      |  31 --
 .../entity/database/mysql/MySqlNode.java        |  97 ----
 .../entity/database/mysql/MySqlNodeImpl.java    | 167 ------
 .../entity/database/mysql/MySqlRowParser.java   |  39 --
 .../entity/database/mysql/MySqlSshDriver.java   | 279 ----------
 .../database/postgresql/PostgreSqlDriver.java   |  33 --
 .../database/postgresql/PostgreSqlNode.java     |  95 ----
 .../PostgreSqlNodeChefImplFromScratch.java      | 171 -------
 .../database/postgresql/PostgreSqlNodeImpl.java |  85 ---
 .../database/postgresql/PostgreSqlSpecs.java    |  43 --
 .../postgresql/PostgreSqlSshDriver.java         | 425 ---------------
 .../entity/database/rubyrep/RubyRepDriver.java  |  28 -
 .../entity/database/rubyrep/RubyRepNode.java    | 109 ----
 .../database/rubyrep/RubyRepNodeImpl.java       | 111 ----
 .../database/rubyrep/RubyRepSshDriver.java      | 126 -----
 .../brooklyn/entity/database/DatabaseNode.java  |  29 ++
 .../entity/database/DatastoreMixins.java        | 104 ++++
 .../entity/database/crate/CrateNode.java        |  92 ++++
 .../entity/database/crate/CrateNodeDriver.java  |  24 +
 .../entity/database/crate/CrateNodeImpl.java    |  99 ++++
 .../database/crate/CrateNodeSshDriver.java      | 118 +++++
 .../entity/database/mariadb/MariaDbDriver.java  |  31 ++
 .../entity/database/mariadb/MariaDbNode.java    | 100 ++++
 .../database/mariadb/MariaDbNodeImpl.java       | 139 +++++
 .../database/mariadb/MariaDbSshDriver.java      | 259 ++++++++++
 .../entity/database/mysql/MySqlCluster.java     |  68 +++
 .../entity/database/mysql/MySqlClusterImpl.java | 445 ++++++++++++++++
 .../entity/database/mysql/MySqlDriver.java      |  31 ++
 .../entity/database/mysql/MySqlNode.java        |  97 ++++
 .../entity/database/mysql/MySqlNodeImpl.java    | 167 ++++++
 .../entity/database/mysql/MySqlRowParser.java   |  39 ++
 .../entity/database/mysql/MySqlSshDriver.java   | 279 ++++++++++
 .../database/postgresql/PostgreSqlDriver.java   |  33 ++
 .../database/postgresql/PostgreSqlNode.java     |  95 ++++
 .../PostgreSqlNodeChefImplFromScratch.java      | 171 +++++++
 .../database/postgresql/PostgreSqlNodeImpl.java |  85 +++
 .../database/postgresql/PostgreSqlSpecs.java    |  43 ++
 .../postgresql/PostgreSqlSshDriver.java         | 425 +++++++++++++++
 .../entity/database/rubyrep/RubyRepDriver.java  |  28 +
 .../entity/database/rubyrep/RubyRepNode.java    | 109 ++++
 .../database/rubyrep/RubyRepNodeImpl.java       | 111 ++++
 .../database/rubyrep/RubyRepSshDriver.java      | 126 +++++
 .../brooklyn/entity/database/crate/crate.yaml   |  28 -
 .../brooklyn/entity/database/mariadb/my.cnf     |  19 -
 .../entity/database/mssql/ConfigurationFile.ini | 390 --------------
 .../entity/database/mssql/checkrunningmssql.bat |  23 -
 .../entity/database/mssql/configuremssql.ps1    |  22 -
 .../entity/database/mssql/installmssql.ps1      |  49 --
 .../entity/database/mssql/launchmssql.bat       |  25 -
 .../brooklyn/entity/database/mssql/mssql.yaml   |  40 --
 .../entity/database/mssql/stopmssql.bat         |  24 -
 .../brooklyn/entity/database/mysql/mysql.conf   |  19 -
 .../entity/database/mysql/mysql_master.conf     |  26 -
 .../entity/database/mysql/mysql_slave.conf      |  33 --
 .../entity/database/postgresql/postgresql.conf  | 513 -------------------
 .../entity/database/rubyrep/rubyrep.conf        |  28 -
 .../brooklyn/entity/database/crate/crate.yaml   |  28 +
 .../brooklyn/entity/database/mariadb/my.cnf     |  19 +
 .../entity/database/mssql/ConfigurationFile.ini | 390 ++++++++++++++
 .../entity/database/mssql/checkrunningmssql.bat |  23 +
 .../entity/database/mssql/configuremssql.ps1    |  22 +
 .../entity/database/mssql/installmssql.ps1      |  49 ++
 .../entity/database/mssql/launchmssql.bat       |  25 +
 .../brooklyn/entity/database/mssql/mssql.yaml   |  40 ++
 .../entity/database/mssql/stopmssql.bat         |  24 +
 .../brooklyn/entity/database/mysql/mysql.conf   |  19 +
 .../entity/database/mysql/mysql_master.conf     |  26 +
 .../entity/database/mysql/mysql_slave.conf      |  33 ++
 .../entity/database/postgresql/postgresql.conf  | 513 +++++++++++++++++++
 .../entity/database/rubyrep/rubyrep.conf        |  28 +
 .../entity/database/VogellaExampleAccess.java   | 161 ------
 .../crate/CrateNodeIntegrationTest.java         |  64 ---
 .../mariadb/MariaDbIntegrationTest.java         | 127 -----
 .../database/mariadb/MariaDbLiveEc2Test.java    |  57 ---
 .../mariadb/MariaDbLiveRackspaceTest.java       | 104 ----
 .../mysql/MySqlClusterIntegrationTest.java      |  44 --
 .../database/mysql/MySqlClusterLiveEc2Test.java |  43 --
 .../mysql/MySqlClusterLiveSoftlayerTest.java    |  39 --
 .../database/mysql/MySqlClusterTestHelper.java  | 115 -----
 .../database/mysql/MySqlIntegrationTest.java    | 106 ----
 .../entity/database/mysql/MySqlLiveEc2Test.java |  53 --
 .../entity/database/mysql/MySqlLiveGceTest.java |  49 --
 .../database/mysql/MySqlLiveRackspaceTest.java  | 107 ----
 .../mysql/MySqlRestartIntegrationTest.java      |  42 --
 .../database/mysql/MysqlDockerLiveTest.java     |  48 --
 .../postgresql/PostgreSqDockerLiveTest.java     |  46 --
 .../database/postgresql/PostgreSqlChefTest.java | 105 ----
 .../postgresql/PostgreSqlEc2LiveTest.java       |  54 --
 .../postgresql/PostgreSqlGceLiveTest.java       |  46 --
 .../postgresql/PostgreSqlIntegrationTest.java   |  97 ----
 .../postgresql/PostgreSqlRackspaceLiveTest.java | 108 ----
 .../PostgreSqlRebindIntegrationTest.java        |  58 ---
 .../PostgreSqlRestartIntegrationTest.java       |  50 --
 .../database/rubyrep/RubyRepEc2LiveTest.java    |  75 ---
 .../rubyrep/RubyRepIntegrationTest.java         | 191 -------
 .../rubyrep/RubyRepRackspaceLiveTest.java       | 130 -----
 .../entity/database/VogellaExampleAccess.java   | 161 ++++++
 .../crate/CrateNodeIntegrationTest.java         |  64 +++
 .../mariadb/MariaDbIntegrationTest.java         | 125 +++++
 .../database/mariadb/MariaDbLiveEc2Test.java    |  57 +++
 .../mariadb/MariaDbLiveRackspaceTest.java       | 104 ++++
 .../mysql/MySqlClusterIntegrationTest.java      |  44 ++
 .../database/mysql/MySqlClusterLiveEc2Test.java |  43 ++
 .../mysql/MySqlClusterLiveSoftlayerTest.java    |  39 ++
 .../database/mysql/MySqlClusterTestHelper.java  | 115 +++++
 .../database/mysql/MySqlIntegrationTest.java    | 106 ++++
 .../entity/database/mysql/MySqlLiveEc2Test.java |  53 ++
 .../entity/database/mysql/MySqlLiveGceTest.java |  49 ++
 .../database/mysql/MySqlLiveRackspaceTest.java  | 107 ++++
 .../mysql/MySqlRestartIntegrationTest.java      |  42 ++
 .../database/mysql/MysqlDockerLiveTest.java     |  48 ++
 .../postgresql/PostgreSqDockerLiveTest.java     |  46 ++
 .../database/postgresql/PostgreSqlChefTest.java | 105 ++++
 .../postgresql/PostgreSqlEc2LiveTest.java       |  54 ++
 .../postgresql/PostgreSqlGceLiveTest.java       |  46 ++
 .../postgresql/PostgreSqlIntegrationTest.java   |  96 ++++
 .../postgresql/PostgreSqlRackspaceLiveTest.java | 108 ++++
 .../PostgreSqlRebindIntegrationTest.java        |  58 +++
 .../PostgreSqlRestartIntegrationTest.java       |  50 ++
 .../database/rubyrep/RubyRepEc2LiveTest.java    |  75 +++
 .../rubyrep/RubyRepIntegrationTest.java         | 191 +++++++
 .../rubyrep/RubyRepRackspaceLiveTest.java       | 130 +++++
 .../monitoring/monit/MonitIntegrationTest.java  |   2 +-
 .../nosql/cassandra/CassandraDatacenter.java    |   2 +-
 .../entity/nosql/cassandra/CassandraNode.java   |   2 +-
 .../nosql/cassandra/CassandraNodeSshDriver.java |   2 +-
 .../nosql/elasticsearch/ElasticSearchNode.java  |   2 +-
 .../app/ClusterWebServerDatabaseSample.java     |   4 +-
 .../brooklyn/sample/app/SampleUnitTest.java     |   4 +-
 .../java-web-app-and-db-with-function-2.yaml    |   2 +-
 .../java-web-app-and-db-with-function.yaml      |   2 +-
 .../java-web-app-and-db-with-policy.yaml        |   2 +-
 ...-java-web-app-spec-and-db-with-function.yaml |   2 +-
 .../java-web-app-and-db-with-function.yaml      |   2 +-
 .../launcher/src/test/resources/mssql-test.yaml |  12 +-
 .../test/resources/postgres-gce-blueprint.yaml  |   2 +-
 .../qa/load/SimulatedMySqlNodeImpl.java         |   6 +-
 .../brooklyn/qa/load/SimulatedTheeTierApp.java  |   2 +-
 162 files changed, 6749 insertions(+), 6752 deletions(-)
----------------------------------------------------------------------



[63/64] incubator-brooklyn git commit: This closes #829

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

Conflicts: (all simple package renames in imports)
	core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogXmlSerializer.java
	software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
	software/messaging/src/test/java/org/apache/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java


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

Branch: refs/heads/master
Commit: b290fdd93e902d136be1273a21986dd10c528f16
Parents: bdd8ef9 54f5c36
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Aug 18 11:52:27 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 18 11:52:27 2015 +0100

----------------------------------------------------------------------
 .../org/apache/brooklyn/entity/database/mariadb/MariaDbDriver.java | 2 ++
 .../org/apache/brooklyn/entity/database/mysql/MySqlDriver.java     | 2 ++
 .../brooklyn/entity/database/postgresql/PostgreSqlDriver.java      | 2 ++
 .../java/org/apache/brooklyn/entity/messaging/kafka/Kafka.java     | 2 ++
 4 files changed, 8 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b290fdd9/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbDriver.java
----------------------------------------------------------------------
diff --cc software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbDriver.java
index 5c841a7,0000000..8ff7905
mode 100644,000000..100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbDriver.java
@@@ -1,31 -1,0 +1,33 @@@
 +/*
 + * 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.entity.database.mariadb;
 +
 +import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 +
++import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
++
 +import brooklyn.entity.basic.SoftwareProcessDriver;
 +
 +/**
 + * The {@link SoftwareProcessDriver} for MariaDB.
 + */
 +public interface MariaDbDriver extends SoftwareProcessDriver {
 +    public String getStatusCmd();
 +    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands);
 +}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b290fdd9/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlDriver.java
----------------------------------------------------------------------
diff --cc software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlDriver.java
index dd63ae1,0000000..0fc89ef
mode 100644,000000..100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlDriver.java
@@@ -1,31 -1,0 +1,33 @@@
 +/*
 + * 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.entity.database.mysql;
 +
 +import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 +
++import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
++
 +import brooklyn.entity.basic.SoftwareProcessDriver;
 +
 +/**
 + * The {@link SoftwareProcessDriver} for MySQL.
 + */
 +public interface MySqlDriver extends SoftwareProcessDriver {
 +    public String getStatusCmd();
 +    public ProcessTaskWrapper<Integer> executeScriptAsync(String commands);
 +}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b290fdd9/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
----------------------------------------------------------------------
diff --cc software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
index c1df992,0000000..f7e331d
mode 100644,000000..100644
--- a/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
+++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/postgresql/PostgreSqlDriver.java
@@@ -1,33 -1,0 +1,35 @@@
 +/*
 + * 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.entity.database.postgresql;
 +
 +import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
 +
++import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
++
 +import brooklyn.entity.basic.SoftwareProcessDriver;
 +
 +/**
 + * The {@link brooklyn.entity.basic.SoftwareProcessDriver} for PostgreSQL.
 + */
 +public interface PostgreSqlDriver extends SoftwareProcessDriver {
 +
 +    String getStatusCmd();
 +
 +    ProcessTaskWrapper<Integer> executeScriptAsync(String commands);
 +}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/b290fdd9/software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/Kafka.java
----------------------------------------------------------------------
diff --cc software/messaging/src/main/java/org/apache/brooklyn/entity/messaging/kafka/Kafka.java
index ed34c1e,0000000..dbd1b7b
mode 100644,000000..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
@@@ -1,45 -1,0 +1,47 @@@
 +/*
 + * 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.entity.messaging.kafka;
 +
 +import org.apache.brooklyn.core.util.flags.SetFromFlag;
 +
++import org.apache.brooklyn.core.util.flags.SetFromFlag;
++
 +import brooklyn.config.ConfigKey;
 +import brooklyn.entity.basic.Attributes;
 +import brooklyn.entity.basic.ConfigKeys;
 +import brooklyn.entity.basic.SoftwareProcess;
 +import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 +
 +/**
 + * Shared Kafka broker and zookeeper properties.
 + */
 +public interface Kafka {
 +
 +    ConfigKey<String> SUGGESTED_VERSION = ConfigKeys.newConfigKeyWithDefault(SoftwareProcess.SUGGESTED_VERSION, "2.9.2-0.8.2.1");
 +
 +    @SetFromFlag("downloadUrl")
 +    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
 +            Attributes.DOWNLOAD_URL, "http://apache.cbox.biz/kafka/0.8.2.1/kafka_${version}.tgz");
 +
 +    // TODO: Upgrade to version 0.8.0, which will require refactoring of the sensors to reflect the changes to the JMX beans
 +//    @SetFromFlag("downloadUrl")
 +//    BasicAttributeSensorAndConfigKey<String> DOWNLOAD_URL = new BasicAttributeSensorAndConfigKey<String>(
 +//            Attributes.DOWNLOAD_URL, "http://mirror.catn.com/pub/apache/kafka/${version}/kafka-${version}-src.tgz");
 +
 +}


[64/64] incubator-brooklyn git commit: Merge remote-tracking branch 'apache-git/master'

Posted by he...@apache.org.
Merge remote-tracking branch 'apache-git/master'


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

Branch: refs/heads/master
Commit: 76d24ca046ed2b2f38a103a9a2feada01bab776f
Parents: b290fdd ad4cfe6
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Tue Aug 18 11:59:05 2015 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Tue Aug 18 11:59:05 2015 +0100

----------------------------------------------------------------------
 .../brooklyn/entity/basic/AbstractEntity.java   |   8 +-
 .../brooklyn/event/basic/ListConfigKey.java     |   2 +-
 .../internal/storage/BrooklynStorage.java       | 114 --------
 .../brooklyn/internal/storage/DataGrid.java     |  52 ----
 .../internal/storage/DataGridFactory.java       |  38 ---
 .../brooklyn/internal/storage/Reference.java    |  50 ----
 .../internal/storage/impl/BackedReference.java  |  73 -----
 .../internal/storage/impl/BasicReference.java   |  67 -----
 .../storage/impl/BrooklynStorageImpl.java       | 139 ---------
 .../impl/ConcurrentMapAcceptingNullVals.java    | 272 ------------------
 .../impl/inmemory/InMemoryDataGridFactory.java  |  41 ---
 .../storage/impl/inmemory/InmemoryDatagrid.java |  93 ------
 .../internal/BrooklynFeatureEnablement.java     |   2 +-
 .../core/internal/storage/BrooklynStorage.java  | 114 ++++++++
 .../core/internal/storage/DataGrid.java         |  52 ++++
 .../core/internal/storage/DataGridFactory.java  |  38 +++
 .../core/internal/storage/Reference.java        |  50 ++++
 .../internal/storage/impl/BackedReference.java  |  73 +++++
 .../internal/storage/impl/BasicReference.java   |  67 +++++
 .../storage/impl/BrooklynStorageImpl.java       | 139 +++++++++
 .../impl/ConcurrentMapAcceptingNullVals.java    | 272 ++++++++++++++++++
 .../impl/inmemory/InMemoryDataGridFactory.java  |  40 +++
 .../storage/impl/inmemory/InmemoryDatagrid.java |  93 ++++++
 .../internal/AbstractManagementContext.java     |  10 +-
 .../internal/BrooklynGarbageCollector.java      |   2 +-
 .../management/internal/LocalEntityManager.java |   2 +-
 .../internal/LocalLocationManager.java          |   2 +-
 .../internal/LocalManagementContext.java        |   2 +-
 .../management/internal/LocalUsageManager.java  |   2 +-
 .../internal/ManagementContextInternal.java     |   2 +-
 .../NonDeploymentManagementContext.java         |   2 +-
 .../location/basic/AbstractLocation.java        |   8 +-
 .../storage/impl/BrooklynStorageImplTest.java   | 287 -------------------
 .../ConcurrentMapAcceptingNullValsTest.java     | 114 --------
 .../EntityCleanupLongevityTestFixture.java      |   6 +-
 .../storage/impl/BrooklynStorageImplTest.java   | 287 +++++++++++++++++++
 .../ConcurrentMapAcceptingNullValsTest.java     | 115 ++++++++
 .../impl/hazelcast/HazelcastDataGrid.java       |   3 +-
 .../hazelcast/HazelcastDataGridFactory.java     |   5 +-
 .../impl/hazelcast/HazelcastStorageTest.java    |   8 +-
 40 files changed, 1372 insertions(+), 1374 deletions(-)
----------------------------------------------------------------------



[39/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
[BROOKLYN-162] Refactor package in ./core/util


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

Branch: refs/heads/master
Commit: 699b3f6529d46376f675636b3a46eef7ba8865f6
Parents: 6caee58
Author: Hadrian Zbarcea <ha...@apache.org>
Authored: Mon Aug 17 01:00:29 2015 -0400
Committer: Hadrian Zbarcea <ha...@apache.org>
Committed: Mon Aug 17 01:00:29 2015 -0400

----------------------------------------------------------------------
 .../src/main/java/brooklyn/BrooklynVersion.java |    6 +-
 .../brooklyn/basic/AbstractBrooklynObject.java  |    4 +-
 .../brooklyn/basic/BasicConfigurableObject.java |    4 +-
 .../brooklyn/basic/BrooklynDynamicType.java     |    2 +-
 .../brooklyn/basic/BrooklynObjectInternal.java  |    2 +-
 .../basic/internal/ApiObjectsFactoryImpl.java   |    2 +-
 .../brooklyn/config/BrooklynProperties.java     |    6 +-
 .../brooklyn/config/BrooklynServerPaths.java    |    2 +-
 .../config/internal/AbstractConfigMapImpl.java  |    4 +-
 .../enricher/CustomAggregatingEnricher.java     |    2 +-
 .../main/java/brooklyn/enricher/Enrichers.java  |    2 +-
 .../enricher/basic/AbstractEnricher.java        |    2 +-
 .../basic/AbstractMultipleSensorAggregator.java |    2 +-
 .../basic/AbstractTypeTransformingEnricher.java |    2 +-
 .../brooklyn/enricher/basic/Aggregator.java     |    2 +-
 .../java/brooklyn/enricher/basic/Joiner.java    |    2 +-
 .../brooklyn/enricher/basic/Propagator.java     |    6 +-
 .../brooklyn/enricher/basic/Transformer.java    |    4 +-
 .../brooklyn/enricher/basic/UpdatingMap.java    |    2 +-
 .../basic/YamlTimeWeightedDeltaEnricher.java    |    2 +-
 .../brooklyn/entity/basic/AbstractEffector.java |    4 +-
 .../brooklyn/entity/basic/AbstractEntity.java   |    8 +-
 .../java/brooklyn/entity/basic/BasicGroup.java  |    2 +-
 .../entity/basic/BrooklynConfigKeys.java        |    4 +-
 .../entity/basic/BrooklynShutdownHooks.java     |    2 +-
 .../brooklyn/entity/basic/BrooklynTaskTags.java |    6 +-
 .../java/brooklyn/entity/basic/ConfigKeys.java  |    2 +-
 .../java/brooklyn/entity/basic/DataEntity.java  |    2 +-
 .../brooklyn/entity/basic/DynamicGroup.java     |    2 +-
 .../brooklyn/entity/basic/DynamicGroupImpl.java |    2 +-
 .../entity/basic/EffectorStartableImpl.java     |    3 +-
 .../java/brooklyn/entity/basic/Entities.java    |   18 +-
 .../brooklyn/entity/basic/EntityConfigMap.java  |   10 +-
 .../brooklyn/entity/basic/EntityFunctions.java  |    2 +-
 .../brooklyn/entity/basic/EntityInternal.java   |    2 +-
 .../basic/EntityTransientCopyInternal.java      |    2 +-
 .../java/brooklyn/entity/basic/Lifecycle.java   |    2 +-
 .../brooklyn/entity/basic/MethodEffector.java   |    2 +-
 .../java/brooklyn/entity/basic/Sanitizer.java   |    2 +-
 .../entity/basic/ServiceStateLogic.java         |    2 +-
 .../entity/effector/AddChildrenEffector.java    |    2 +-
 .../brooklyn/entity/effector/AddEffector.java   |    2 +-
 .../brooklyn/entity/effector/AddSensor.java     |    2 +-
 .../brooklyn/entity/effector/EffectorBody.java  |   10 +-
 .../brooklyn/entity/effector/EffectorTasks.java |   10 +-
 .../brooklyn/entity/effector/Effectors.java     |    4 +-
 .../java/brooklyn/entity/group/Cluster.java     |    2 +-
 .../brooklyn/entity/group/DynamicCluster.java   |    2 +-
 .../entity/group/DynamicClusterImpl.java        |    8 +-
 .../brooklyn/entity/group/DynamicFabric.java    |    2 +-
 .../entity/group/DynamicMultiGroup.java         |    2 +-
 .../entity/group/QuarantineGroupImpl.java       |    4 +-
 .../entity/proxying/EntityProxyImpl.java        |    6 +-
 .../entity/proxying/InternalEntityFactory.java  |    4 +-
 .../proxying/InternalLocationFactory.java       |    4 +-
 .../entity/proxying/InternalPolicyFactory.java  |    2 +-
 .../rebind/BasicCatalogItemRebindSupport.java   |    2 +-
 .../rebind/BasicEnricherRebindSupport.java      |    4 +-
 .../entity/rebind/BasicFeedRebindSupport.java   |    4 +-
 .../rebind/BasicLocationRebindSupport.java      |    4 +-
 .../entity/rebind/BasicPolicyRebindSupport.java |    4 +-
 .../rebind/PeriodicDeltaChangeListener.java     |    4 +-
 .../brooklyn/entity/rebind/RebindIteration.java |    2 +-
 .../entity/rebind/RebindManagerImpl.java        |    6 +-
 .../entity/rebind/dto/BasicLocationMemento.java |    2 +-
 .../entity/rebind/dto/MementosGenerators.java   |    4 +-
 .../BrooklynMementoPersisterToObjectStore.java  |    2 +-
 .../persister/BrooklynPersistenceUtils.java     |    2 +-
 .../rebind/persister/FileBasedObjectStore.java  |    2 +-
 .../rebind/persister/XmlMementoSerializer.java  |    2 +-
 .../rebind/transformer/CompoundTransformer.java |    4 +-
 .../transformer/CompoundTransformerLoader.java  |    4 +-
 .../java/brooklyn/entity/trait/Startable.java   |    4 +-
 .../brooklyn/entity/trait/StartableMethods.java |    6 +-
 .../java/brooklyn/event/basic/AttributeMap.java |    2 +-
 .../basic/AttributeSensorAndConfigKey.java      |    2 +-
 .../brooklyn/event/basic/BasicConfigKey.java    |    4 +-
 .../event/basic/DependentConfiguration.java     |   16 +-
 .../basic/PortAttributeSensorAndConfigKey.java  |    2 +-
 ...platedStringAttributeSensorAndConfigKey.java |    2 +-
 .../event/feed/AttributePollHandler.java        |    4 +-
 .../main/java/brooklyn/event/feed/Poller.java   |    6 +-
 .../java/brooklyn/event/feed/http/HttpFeed.java |    6 +-
 .../event/feed/http/HttpPollConfig.java         |    4 +-
 .../brooklyn/event/feed/http/HttpPollValue.java |    2 +-
 .../brooklyn/event/feed/http/HttpPolls.java     |    5 +-
 .../event/feed/http/HttpValueFunctions.java     |    3 +-
 .../brooklyn/event/feed/shell/ShellFeed.java    |    6 +-
 .../java/brooklyn/event/feed/ssh/SshFeed.java   |    6 +-
 .../windows/WindowsPerformanceCounterFeed.java  |    4 +-
 .../policy/basic/AbstractEntityAdjunct.java     |    8 +-
 .../brooklyn/policy/basic/ConfigMapImpl.java    |    4 +-
 .../util/BrooklynLanguageExtensions.java        |   48 -
 .../brooklyn/util/BrooklynMavenArtifacts.java   |   58 -
 .../brooklyn/util/BrooklynNetworkUtils.java     |   41 -
 .../main/java/brooklyn/util/ResourceUtils.java  |  639 ----------
 .../java/brooklyn/util/config/ConfigBag.java    |  588 ----------
 .../brooklyn/util/crypto/FluentKeySigner.java   |  192 ---
 .../java/brooklyn/util/crypto/SecureKeys.java   |  184 ---
 .../java/brooklyn/util/file/ArchiveBuilder.java |  423 -------
 .../java/brooklyn/util/file/ArchiveTasks.java   |   58 -
 .../java/brooklyn/util/file/ArchiveUtils.java   |  351 ------
 .../util/flags/ClassCoercionException.java      |   39 -
 .../java/brooklyn/util/flags/FlagUtils.java     |  587 ----------
 .../brooklyn/util/flags/MethodCoercions.java    |  183 ---
 .../java/brooklyn/util/flags/SetFromFlag.java   |   71 --
 .../java/brooklyn/util/flags/TypeCoercions.java |  879 --------------
 .../main/java/brooklyn/util/http/HttpTool.java  |  387 -------
 .../brooklyn/util/http/HttpToolResponse.java    |  185 ---
 .../util/internal/ConfigKeySelfExtracting.java  |   41 -
 .../java/brooklyn/util/internal/Repeater.java   |  369 ------
 .../ssh/BackoffLimitedRetryHandler.java         |   74 --
 .../util/internal/ssh/ShellAbstractTool.java    |  442 -------
 .../brooklyn/util/internal/ssh/ShellTool.java   |  113 --
 .../util/internal/ssh/SshAbstractTool.java      |  172 ---
 .../util/internal/ssh/SshException.java         |   32 -
 .../brooklyn/util/internal/ssh/SshTool.java     |  174 ---
 .../util/internal/ssh/cli/SshCliTool.java       |  316 -----
 .../util/internal/ssh/process/ProcessTool.java  |  214 ----
 .../internal/ssh/sshj/SshjClientConnection.java |  282 -----
 .../util/internal/ssh/sshj/SshjTool.java        | 1091 ------------------
 .../util/javalang/ReflectionScanner.java        |  135 ---
 .../brooklyn/util/javalang/UrlClassLoader.java  |   69 --
 .../java/brooklyn/util/mutex/MutexSupport.java  |  120 --
 .../brooklyn/util/mutex/SemaphoreForTasks.java  |  112 --
 .../util/mutex/SemaphoreWithOwners.java         |  231 ----
 .../java/brooklyn/util/mutex/WithMutexes.java   |   45 -
 .../src/main/java/brooklyn/util/osgi/Osgis.java |  719 ------------
 .../util/task/AbstractExecutionContext.java     |   75 --
 .../util/task/BasicExecutionContext.java        |  221 ----
 .../util/task/BasicExecutionManager.java        |  755 ------------
 .../main/java/brooklyn/util/task/BasicTask.java |  892 --------------
 .../java/brooklyn/util/task/CanSetName.java     |   25 -
 .../java/brooklyn/util/task/CompoundTask.java   |  131 ---
 .../brooklyn/util/task/DeferredSupplier.java    |   38 -
 .../util/task/DynamicSequentialTask.java        |  480 --------
 .../java/brooklyn/util/task/DynamicTasks.java   |  337 ------
 .../brooklyn/util/task/ExecutionListener.java   |   31 -
 .../java/brooklyn/util/task/ExecutionUtils.java |   49 -
 .../java/brooklyn/util/task/ForwardingTask.java |  325 ------
 .../util/task/ListenableForwardingFuture.java   |   50 -
 .../java/brooklyn/util/task/ParallelTask.java   |   85 --
 .../java/brooklyn/util/task/ScheduledTask.java  |  185 ---
 .../java/brooklyn/util/task/SequentialTask.java |   58 -
 .../util/task/SingleThreadedScheduler.java      |  216 ----
 .../java/brooklyn/util/task/TaskBuilder.java    |  184 ---
 .../java/brooklyn/util/task/TaskInternal.java   |  125 --
 .../java/brooklyn/util/task/TaskScheduler.java  |   41 -
 .../main/java/brooklyn/util/task/TaskTags.java  |   71 --
 .../src/main/java/brooklyn/util/task/Tasks.java |  488 --------
 .../java/brooklyn/util/task/ValueResolver.java  |  426 -------
 .../util/task/ssh/SshFetchTaskFactory.java      |   89 --
 .../util/task/ssh/SshFetchTaskWrapper.java      |  135 ---
 .../util/task/ssh/SshPutTaskFactory.java        |  123 --
 .../brooklyn/util/task/ssh/SshPutTaskStub.java  |   69 --
 .../util/task/ssh/SshPutTaskWrapper.java        |  190 ---
 .../java/brooklyn/util/task/ssh/SshTasks.java   |  236 ----
 .../internal/AbstractSshExecTaskFactory.java    |   58 -
 .../ssh/internal/PlainSshExecTaskFactory.java   |   71 --
 .../util/task/system/ProcessTaskFactory.java    |   65 --
 .../util/task/system/ProcessTaskStub.java       |  101 --
 .../util/task/system/ProcessTaskWrapper.java    |  187 ---
 .../brooklyn/util/task/system/SystemTasks.java  |   29 -
 .../internal/AbstractProcessTaskFactory.java    |  214 ----
 .../system/internal/ExecWithLoggingHelpers.java |  200 ----
 .../internal/SystemProcessTaskFactory.java      |  131 ---
 .../brooklyn/util/text/DataUriSchemeParser.java |  267 -----
 .../brooklyn/util/text/TemplateProcessor.java   |  397 -------
 ...ompilerIndependentOuterClassFieldMapper.java |  166 ---
 .../xstream/EnumCaseForgivingConverter.java     |   60 -
 .../EnumCaseForgivingSingleValueConverter.java  |   35 -
 .../util/xstream/ImmutableListConverter.java    |   54 -
 .../util/xstream/ImmutableMapConverter.java     |   56 -
 .../util/xstream/ImmutableSetConverter.java     |   54 -
 .../util/xstream/Inet4AddressConverter.java     |   65 --
 .../brooklyn/util/xstream/MapConverter.java     |  104 --
 .../util/xstream/MutableSetConverter.java       |   44 -
 .../util/xstream/StringKeyMapConverter.java     |  134 ---
 .../brooklyn/util/xstream/XmlSerializer.java    |   97 --
 .../java/brooklyn/util/xstream/XmlUtil.java     |   59 -
 .../catalog/internal/BasicBrooklynCatalog.java  |    2 +-
 .../catalog/internal/CatalogClasspathDo.java    |    6 +-
 .../core/catalog/internal/CatalogDto.java       |    2 +-
 .../core/catalog/internal/CatalogDtoUtils.java  |    2 +-
 .../catalog/internal/CatalogInitialization.java |    4 +-
 .../internal/CatalogItemDtoAbstract.java        |    4 +-
 .../catalog/internal/CatalogXmlSerializer.java  |    4 +-
 .../internal/BrooklynFeatureEnablement.java     |    2 +-
 .../core/internal/BrooklynInitialization.java   |    9 +-
 .../management/entitlement/Entitlements.java    |    2 +-
 .../ha/HighAvailabilityManagerImpl.java         |    4 +-
 .../core/management/ha/OsgiManager.java         |    4 +-
 .../internal/AbstractManagementContext.java     |    8 +-
 .../internal/AsyncCollectionChangeAdapter.java  |    4 +-
 .../internal/BrooklynGarbageCollector.java      |    6 +-
 .../core/management/internal/EffectorUtils.java |    4 +-
 .../internal/EntityManagementUtils.java         |    4 +-
 .../management/internal/LocalEntityManager.java |    2 +-
 .../internal/LocalLocationManager.java          |    4 +-
 .../internal/LocalManagementContext.java        |   10 +-
 .../internal/LocalSubscriptionManager.java      |    4 +-
 .../management/internal/LocalUsageManager.java  |    2 +-
 .../internal/ManagementContextInternal.java     |    2 +-
 .../core/util/BrooklynLanguageExtensions.java   |   48 +
 .../core/util/BrooklynMavenArtifacts.java       |   58 +
 .../core/util/BrooklynNetworkUtils.java         |   44 +
 .../brooklyn/core/util/ResourceUtils.java       |  639 ++++++++++
 .../brooklyn/core/util/config/ConfigBag.java    |  589 ++++++++++
 .../core/util/crypto/FluentKeySigner.java       |  192 +++
 .../brooklyn/core/util/crypto/SecureKeys.java   |  186 +++
 .../brooklyn/core/util/file/ArchiveBuilder.java |  424 +++++++
 .../brooklyn/core/util/file/ArchiveTasks.java   |   58 +
 .../brooklyn/core/util/file/ArchiveUtils.java   |  351 ++++++
 .../core/util/flags/ClassCoercionException.java |   39 +
 .../brooklyn/core/util/flags/FlagUtils.java     |  587 ++++++++++
 .../core/util/flags/MethodCoercions.java        |  183 +++
 .../brooklyn/core/util/flags/SetFromFlag.java   |   71 ++
 .../brooklyn/core/util/flags/TypeCoercions.java |  879 ++++++++++++++
 .../brooklyn/core/util/http/HttpTool.java       |  387 +++++++
 .../core/util/http/HttpToolResponse.java        |  185 +++
 .../util/internal/ConfigKeySelfExtracting.java  |   41 +
 .../brooklyn/core/util/internal/Repeater.java   |  370 ++++++
 .../ssh/BackoffLimitedRetryHandler.java         |   74 ++
 .../util/internal/ssh/ShellAbstractTool.java    |  442 +++++++
 .../core/util/internal/ssh/ShellTool.java       |  113 ++
 .../core/util/internal/ssh/SshAbstractTool.java |  172 +++
 .../core/util/internal/ssh/SshException.java    |   32 +
 .../core/util/internal/ssh/SshTool.java         |  174 +++
 .../core/util/internal/ssh/cli/SshCliTool.java  |  317 +++++
 .../util/internal/ssh/process/ProcessTool.java  |  215 ++++
 .../internal/ssh/sshj/SshjClientConnection.java |  282 +++++
 .../core/util/internal/ssh/sshj/SshjTool.java   | 1091 ++++++++++++++++++
 .../core/util/javalang/ReflectionScanner.java   |  135 +++
 .../core/util/javalang/UrlClassLoader.java      |   70 ++
 .../brooklyn/core/util/mutex/MutexSupport.java  |  119 ++
 .../core/util/mutex/SemaphoreForTasks.java      |  112 ++
 .../core/util/mutex/SemaphoreWithOwners.java    |  231 ++++
 .../brooklyn/core/util/mutex/WithMutexes.java   |   45 +
 .../apache/brooklyn/core/util/osgi/Osgis.java   |  720 ++++++++++++
 .../util/task/AbstractExecutionContext.java     |   75 ++
 .../core/util/task/BasicExecutionContext.java   |  221 ++++
 .../core/util/task/BasicExecutionManager.java   |  755 ++++++++++++
 .../brooklyn/core/util/task/BasicTask.java      |  892 ++++++++++++++
 .../brooklyn/core/util/task/CanSetName.java     |   25 +
 .../brooklyn/core/util/task/CompoundTask.java   |  131 +++
 .../core/util/task/DeferredSupplier.java        |   38 +
 .../core/util/task/DynamicSequentialTask.java   |  480 ++++++++
 .../brooklyn/core/util/task/DynamicTasks.java   |  337 ++++++
 .../core/util/task/ExecutionListener.java       |   31 +
 .../brooklyn/core/util/task/ExecutionUtils.java |   49 +
 .../brooklyn/core/util/task/ForwardingTask.java |  325 ++++++
 .../util/task/ListenableForwardingFuture.java   |   50 +
 .../brooklyn/core/util/task/ParallelTask.java   |   85 ++
 .../brooklyn/core/util/task/ScheduledTask.java  |  185 +++
 .../brooklyn/core/util/task/SequentialTask.java |   58 +
 .../core/util/task/SingleThreadedScheduler.java |  216 ++++
 .../brooklyn/core/util/task/TaskBuilder.java    |  184 +++
 .../brooklyn/core/util/task/TaskInternal.java   |  125 ++
 .../brooklyn/core/util/task/TaskScheduler.java  |   41 +
 .../brooklyn/core/util/task/TaskTags.java       |   71 ++
 .../apache/brooklyn/core/util/task/Tasks.java   |  488 ++++++++
 .../brooklyn/core/util/task/ValueResolver.java  |  426 +++++++
 .../core/util/task/ssh/SshFetchTaskFactory.java |   88 ++
 .../core/util/task/ssh/SshFetchTaskWrapper.java |  135 +++
 .../core/util/task/ssh/SshPutTaskFactory.java   |  123 ++
 .../core/util/task/ssh/SshPutTaskStub.java      |   69 ++
 .../core/util/task/ssh/SshPutTaskWrapper.java   |  189 +++
 .../brooklyn/core/util/task/ssh/SshTasks.java   |  236 ++++
 .../internal/AbstractSshExecTaskFactory.java    |   58 +
 .../ssh/internal/PlainSshExecTaskFactory.java   |   71 ++
 .../util/task/system/ProcessTaskFactory.java    |   66 ++
 .../core/util/task/system/ProcessTaskStub.java  |  102 ++
 .../util/task/system/ProcessTaskWrapper.java    |  187 +++
 .../core/util/task/system/SystemTasks.java      |   29 +
 .../internal/AbstractProcessTaskFactory.java    |  216 ++++
 .../system/internal/ExecWithLoggingHelpers.java |  202 ++++
 .../internal/SystemProcessTaskFactory.java      |  131 +++
 .../core/util/text/DataUriSchemeParser.java     |  267 +++++
 .../core/util/text/TemplateProcessor.java       |  398 +++++++
 ...ompilerIndependentOuterClassFieldMapper.java |  166 +++
 .../xstream/EnumCaseForgivingConverter.java     |   60 +
 .../EnumCaseForgivingSingleValueConverter.java  |   35 +
 .../util/xstream/ImmutableListConverter.java    |   54 +
 .../util/xstream/ImmutableMapConverter.java     |   56 +
 .../util/xstream/ImmutableSetConverter.java     |   54 +
 .../util/xstream/Inet4AddressConverter.java     |   65 ++
 .../core/util/xstream/MapConverter.java         |  104 ++
 .../core/util/xstream/MutableSetConverter.java  |   44 +
 .../util/xstream/StringKeyMapConverter.java     |  134 +++
 .../core/util/xstream/XmlSerializer.java        |   97 ++
 .../brooklyn/core/util/xstream/XmlUtil.java     |   59 +
 .../location/access/BrooklynAccessUtils.java    |    8 +-
 .../PortForwardManagerLocationResolver.java     |    3 +-
 .../location/basic/AbstractLocation.java        |    6 +-
 .../basic/AbstractLocationResolver.java         |    2 +-
 .../AggregatingMachineProvisioningLocation.java |    2 +-
 .../location/basic/BasicLocationRegistry.java   |    2 +-
 .../location/basic/BasicMachineDetails.java     |   10 +-
 .../location/basic/ByonLocationResolver.java    |    4 +-
 .../FixedListMachineProvisioningLocation.java   |    4 +-
 .../location/basic/HostLocationResolver.java    |    2 +-
 .../basic/LocalhostLocationResolver.java        |    3 +-
 .../LocalhostMachineProvisioningLocation.java   |   10 +-
 ...calhostPropertiesFromBrooklynProperties.java |    3 +-
 .../location/basic/LocationConfigUtils.java     |    8 +-
 .../location/basic/LocationInternal.java        |    2 +-
 ...ocationPropertiesFromBrooklynProperties.java |    4 +-
 .../brooklyn/location/basic/MultiLocation.java  |    2 +-
 .../location/basic/NamedLocationResolver.java   |    2 +-
 .../brooklyn/location/basic/PortRanges.java     |    3 +-
 .../basic/SingleMachineLocationResolver.java    |    2 +-
 .../SingleMachineProvisioningLocation.java      |    3 +-
 .../location/basic/SshMachineLocation.java      |   32 +-
 ...bstractCloudMachineProvisioningLocation.java |    4 +-
 .../location/cloud/CloudLocationConfig.java     |    3 +-
 .../cloud/names/AbstractCloudMachineNamer.java  |    4 +-
 .../cloud/names/BasicCloudMachineNamer.java     |    4 +-
 .../location/cloud/names/CloudMachineNamer.java |    3 +-
 .../cloud/names/CustomMachineNamer.java         |    6 +-
 .../location/dynamic/DynamicLocation.java       |    2 +-
 .../location/dynamic/LocationOwner.java         |    2 +-
 .../brooklyn/location/geo/HostGeoInfo.java      |    2 +-
 .../location/geo/LocalhostExternalIpLoader.java |    2 +-
 .../brooklyn/camp/lite/CampYamlLiteTest.java    |    4 +-
 .../camp/lite/TestAppAssemblyInstantiator.java  |    2 +-
 .../enricher/basic/BasicEnricherTest.java       |    2 +-
 .../java/brooklyn/entity/EffectorSayHiTest.java |    2 +-
 .../java/brooklyn/entity/SetFromFlagTest.java   |    2 +-
 .../brooklyn/entity/basic/ConfigMapTest.java    |    4 +-
 .../basic/DependentConfigurationTest.java       |    2 +-
 .../brooklyn/entity/basic/EntityConfigTest.java |    2 +-
 .../brooklyn/entity/basic/EntitySpecTest.java   |    2 +-
 ...apListAndOtherStructuredConfigKeyTest.groovy |    2 +-
 .../brooklyn/entity/basic/SanitizerTest.java    |    3 +-
 .../entity/effector/EffectorBasicTest.java      |    2 +-
 .../effector/EffectorConcatenateTest.java       |    4 +-
 .../entity/effector/EffectorTaskTest.java       |   10 +-
 .../java/brooklyn/entity/rebind/Dumpers.java    |    2 +-
 .../entity/rebind/RebindCatalogEntityTest.java  |    3 +-
 .../entity/rebind/RebindEnricherTest.java       |    2 +-
 .../rebind/RebindEntityDynamicTypeInfoTest.java |    2 +-
 .../entity/rebind/RebindEntityTest.java         |    2 +-
 .../entity/rebind/RebindFailuresTest.java       |    2 +-
 .../brooklyn/entity/rebind/RebindFeedTest.java  |    4 +-
 .../entity/rebind/RebindFeedWithHaTest.java     |    4 +-
 .../entity/rebind/RebindLocationTest.java       |    2 +-
 .../entity/rebind/RebindManagerTest.java        |    5 +-
 .../entity/rebind/RebindPolicyTest.java         |    2 +-
 .../entity/rebind/RebindTestFixture.java        |    2 +-
 .../transformer/impl/XsltTransformerTest.java   |    4 +-
 .../brooklyn/entity/trait/FailingEntity.java    |    2 +-
 .../entity/trait/FailingEntityImpl.java         |    2 +-
 .../entity/trait/StartableMethodsTest.java      |    3 +-
 .../java/brooklyn/event/feed/PollerTest.java    |    2 +-
 .../brooklyn/event/feed/http/HttpFeedTest.java  |    4 +-
 .../event/feed/http/HttpValueFunctionsTest.java |    3 +-
 .../brooklyn/policy/basic/BasicPolicyTest.java  |    2 +-
 .../EntityCleanupLongevityTestFixture.java      |    4 +-
 .../FilePersistencePerformanceTest.java         |    2 +-
 .../qa/performance/TaskPerformanceTest.java     |    4 +-
 .../test/java/brooklyn/test/HttpService.java    |    4 +-
 .../java/brooklyn/test/policy/TestEnricher.java |    2 +-
 .../java/brooklyn/test/policy/TestPolicy.java   |    2 +-
 .../util/BrooklynMavenArtifactsTest.java        |   96 --
 .../brooklyn/util/ResourceUtilsHttpTest.java    |  196 ----
 .../java/brooklyn/util/ResourceUtilsTest.java   |  189 ---
 .../brooklyn/util/config/ConfigBagTest.java     |  191 ---
 .../util/crypto/SecureKeysAndSignerTest.java    |  166 ---
 .../brooklyn/util/file/ArchiveBuilderTest.java  |  193 ----
 .../brooklyn/util/file/ArchiveUtilsTest.java    |  135 ---
 .../util/flags/MethodCoercionsTest.java         |  146 ---
 .../brooklyn/util/http/BetterMockWebServer.java |  138 ---
 .../util/http/HttpToolIntegrationTest.java      |   98 --
 .../brooklyn/util/internal/FlagUtilsTest.java   |  314 -----
 .../brooklyn/util/internal/RepeaterTest.groovy  |  255 ----
 .../util/internal/TypeCoercionsTest.java        |  360 ------
 .../util/internal/ssh/RecordingSshTool.java     |   95 --
 .../internal/ssh/ShellToolAbstractTest.java     |  439 -------
 .../ssh/SshToolAbstractIntegrationTest.java     |  301 -----
 .../ssh/SshToolAbstractPerformanceTest.java     |  137 ---
 .../ssh/cli/SshCliToolIntegrationTest.java      |  119 --
 .../ssh/cli/SshCliToolPerformanceTest.java      |   44 -
 .../ssh/process/ProcessToolIntegrationTest.java |   69 --
 .../ssh/process/ProcessToolStaticsTest.java     |   79 --
 .../sshj/SshjToolAsyncStubIntegrationTest.java  |  177 ---
 .../ssh/sshj/SshjToolIntegrationTest.java       |  313 -----
 .../ssh/sshj/SshjToolPerformanceTest.java       |   44 -
 .../brooklyn/util/mutex/WithMutexesTest.java    |  126 --
 .../test/java/brooklyn/util/osgi/OsgisTest.java |   41 -
 .../util/ssh/BashCommandsIntegrationTest.java   |  501 --------
 .../task/BasicTaskExecutionPerformanceTest.java |  206 ----
 .../util/task/BasicTaskExecutionTest.java       |  460 --------
 .../util/task/BasicTasksFutureTest.java         |  224 ----
 .../util/task/CompoundTaskExecutionTest.java    |  252 ----
 .../util/task/DynamicSequentialTaskTest.java    |  365 ------
 .../util/task/NonBasicTaskExecutionTest.java    |  126 --
 .../util/task/ScheduledExecutionTest.java       |  287 -----
 .../util/task/SingleThreadedSchedulerTest.java  |  192 ---
 .../util/task/TaskFinalizationTest.java         |   62 -
 .../test/java/brooklyn/util/task/TasksTest.java |  181 ---
 .../brooklyn/util/task/ValueResolverTest.java   |  132 ---
 .../brooklyn/util/task/ssh/SshTasksTest.java    |  207 ----
 .../util/task/system/SystemTasksTest.java       |  134 ---
 .../util/text/DataUriSchemeParserTest.java      |   52 -
 .../util/text/TemplateProcessorTest.java        |  179 ---
 .../util/xstream/CompilerCompatibilityTest.java |  154 ---
 .../util/xstream/ConverterTestFixture.java      |   40 -
 .../xstream/EnumCaseForgivingConverterTest.java |   52 -
 .../xstream/ImmutableListConverterTest.java     |   59 -
 .../util/xstream/InetAddressConverterTest.java  |   41 -
 .../util/xstream/StringKeyMapConverterTest.java |   77 --
 .../java/brooklyn/util/xstream/XmlUtilTest.java |   33 -
 .../core/catalog/internal/CatalogDtoTest.java   |    2 +-
 .../core/catalog/internal/CatalogLoadTest.java  |    3 +-
 .../core/catalog/internal/CatalogScanTest.java  |    2 +-
 .../AcmeEntitlementManagerTestFixture.java      |    2 +-
 .../entitlement/EntityEntitlementTest.java      |    2 +-
 .../internal/EntityExecutionManagerTest.java    |    8 +-
 .../management/osgi/OsgiStandaloneTest.java     |    6 +-
 .../osgi/OsgiVersionMoreEntityTest.java         |    2 +-
 .../core/util/BrooklynMavenArtifactsTest.java   |   98 ++
 .../core/util/ResourceUtilsHttpTest.java        |  197 ++++
 .../brooklyn/core/util/ResourceUtilsTest.java   |  190 +++
 .../core/util/config/ConfigBagTest.java         |  193 ++++
 .../util/crypto/SecureKeysAndSignerTest.java    |  169 +++
 .../core/util/file/ArchiveBuilderTest.java      |  194 ++++
 .../core/util/file/ArchiveUtilsTest.java        |  139 +++
 .../core/util/flags/MethodCoercionsTest.java    |  149 +++
 .../core/util/http/BetterMockWebServer.java     |  138 +++
 .../core/util/http/HttpToolIntegrationTest.java |  100 ++
 .../core/util/internal/FlagUtilsTest.java       |  314 +++++
 .../core/util/internal/RepeaterTest.groovy      |  257 +++++
 .../core/util/internal/TypeCoercionsTest.java   |  360 ++++++
 .../util/internal/ssh/RecordingSshTool.java     |   97 ++
 .../internal/ssh/ShellToolAbstractTest.java     |  441 +++++++
 .../ssh/SshToolAbstractIntegrationTest.java     |  304 +++++
 .../ssh/SshToolAbstractPerformanceTest.java     |  138 +++
 .../ssh/cli/SshCliToolIntegrationTest.java      |  119 ++
 .../ssh/cli/SshCliToolPerformanceTest.java      |   44 +
 .../ssh/process/ProcessToolIntegrationTest.java |   69 ++
 .../ssh/process/ProcessToolStaticsTest.java     |   80 ++
 .../sshj/SshjToolAsyncStubIntegrationTest.java  |  178 +++
 .../ssh/sshj/SshjToolIntegrationTest.java       |  314 +++++
 .../ssh/sshj/SshjToolPerformanceTest.java       |   44 +
 .../core/util/mutex/WithMutexesTest.java        |  129 +++
 .../brooklyn/core/util/osgi/OsgisTest.java      |   41 +
 .../util/ssh/BashCommandsIntegrationTest.java   |  504 ++++++++
 .../task/BasicTaskExecutionPerformanceTest.java |  209 ++++
 .../core/util/task/BasicTaskExecutionTest.java  |  462 ++++++++
 .../core/util/task/BasicTasksFutureTest.java    |  227 ++++
 .../util/task/CompoundTaskExecutionTest.java    |  258 +++++
 .../util/task/DynamicSequentialTaskTest.java    |  371 ++++++
 .../util/task/NonBasicTaskExecutionTest.java    |  130 +++
 .../core/util/task/ScheduledExecutionTest.java  |  291 +++++
 .../util/task/SingleThreadedSchedulerTest.java  |  195 ++++
 .../core/util/task/TaskFinalizationTest.java    |   63 +
 .../brooklyn/core/util/task/TasksTest.java      |  184 +++
 .../core/util/task/ValueResolverTest.java       |  134 +++
 .../core/util/task/ssh/SshTasksTest.java        |  213 ++++
 .../core/util/task/system/SystemTasksTest.java  |  137 +++
 .../core/util/text/DataUriSchemeParserTest.java |   53 +
 .../core/util/text/TemplateProcessorTest.java   |  180 +++
 .../util/xstream/CompilerCompatibilityTest.java |  158 +++
 .../core/util/xstream/ConverterTestFixture.java |   40 +
 .../xstream/EnumCaseForgivingConverterTest.java |   53 +
 .../xstream/ImmutableListConverterTest.java     |   60 +
 .../util/xstream/InetAddressConverterTest.java  |   42 +
 .../util/xstream/StringKeyMapConverterTest.java |   78 ++
 .../brooklyn/core/util/xstream/XmlUtilTest.java |   34 +
 .../location/basic/AbstractLocationTest.java    |    2 +-
 .../basic/LegacyAbstractLocationTest.java       |    2 +-
 .../location/basic/LocationConfigTest.java      |    2 +-
 .../location/basic/LocationConfigUtilsTest.java |    3 +-
 .../brooklyn/location/basic/PortRangesTest.java |    3 +-
 .../SshMachineLocationIntegrationTest.java      |    9 +-
 .../SshMachineLocationPerformanceTest.java      |    2 +-
 .../SshMachineLocationReuseIntegrationTest.java |    4 +-
 .../location/basic/SshMachineLocationTest.java  |   14 +-
 .../location/cloud/CloudMachineNamerTest.java   |    4 +-
 .../location/cloud/CustomMachineNamerTest.java  |    3 +-
 .../brooklyn/test/entity/BlockingEntity.java    |    2 +-
 .../apache/brooklyn/test/entity/TestEntity.java |    2 +-
 .../rebind/compiler_compatibility_eclipse.xml   |   20 +-
 .../rebind/compiler_compatibility_oracle.xml    |   18 +-
 .../brooklyn/demo/GlobalWebFabricExample.java   |    6 +-
 .../brooklyn/demo/CumulusRDFApplication.java    |    8 +-
 .../demo/WebClusterDatabaseExampleApp.java      |    6 +-
 .../brooklyn/policy/os/CreateUserPolicy.java    |    4 +-
 .../location/jclouds/BrooklynMachinePool.java   |    2 +-
 .../jclouds/ComputeServiceRegistry.java         |    3 +-
 .../jclouds/ComputeServiceRegistryImpl.java     |    2 +-
 .../jclouds/JcloudsByonLocationResolver.java    |    2 +-
 .../location/jclouds/JcloudsLocation.java       |   18 +-
 .../location/jclouds/JcloudsLocationConfig.java |    3 +-
 .../jclouds/JcloudsLocationCustomizer.java      |    3 +-
 .../location/jclouds/JcloudsMachineNamer.java   |    2 +-
 ...JcloudsPropertiesFromBrooklynProperties.java |    4 +-
 .../jclouds/JcloudsSshMachineLocation.java      |    2 +-
 .../brooklyn/location/jclouds/JcloudsUtil.java  |    2 +-
 .../jclouds/JcloudsWinRmMachineLocation.java    |    2 +-
 .../jclouds/SudoTtyFixingCustomizer.java        |    7 +-
 .../JcloudsLocationSecurityGroupCustomizer.java |    4 +-
 .../persister/jclouds/BlobStoreExpiryTest.java  |    6 +-
 .../policy/os/CreateUserPolicyLiveTest.java     |    2 +-
 .../policy/os/CreateUserPolicyTest.java         |    3 +-
 .../jclouds/AbstractJcloudsStubbedLiveTest.java |    3 +-
 .../jclouds/BailOutJcloudsLocation.java         |    2 +-
 ...ationTemplateOptionsCustomisersLiveTest.java |    4 +-
 .../location/jclouds/JcloudsLocationTest.java   |    2 +-
 .../jclouds/JcloudsMachineNamerTest.java        |    2 +-
 .../jclouds/RebindJcloudsLocationLiveTest.java  |    2 +-
 .../jclouds/RebindJcloudsLocationTest.java      |    3 +-
 .../java/brooklyn/enricher/DeltaEnricher.java   |    2 +-
 .../brooklyn/enricher/HttpLatencyDetector.java  |    2 +-
 .../brooklyn/enricher/RollingMeanEnricher.java  |    2 +-
 .../enricher/RollingTimeWindowMeanEnricher.java |    2 +-
 .../enricher/TimeFractionDeltaEnricher.java     |    2 +-
 .../enricher/TimeWeightedDeltaEnricher.java     |    2 +-
 .../entity/brooklyn/BrooklynMetrics.java        |    2 +-
 .../entity/brooklyn/BrooklynMetricsImpl.java    |    2 +-
 .../policy/autoscaling/AutoScalerPolicy.java    |    6 +-
 .../policy/followthesun/FollowTheSunPolicy.java |    2 +-
 .../policy/ha/AbstractFailureDetector.java      |    6 +-
 .../policy/ha/ConditionalSuspendPolicy.java     |    2 +-
 .../policy/ha/ConnectionFailureDetector.java    |    2 +-
 .../policy/ha/ServiceFailureDetector.java       |    8 +-
 .../brooklyn/policy/ha/ServiceReplacer.java     |    4 +-
 .../brooklyn/policy/ha/ServiceRestarter.java    |    4 +-
 .../policy/ha/SshMachineFailureDetector.java    |    4 +-
 .../loadbalancing/ItemsInContainersGroup.java   |    2 +-
 .../loadbalancing/LoadBalancingPolicy.java      |    2 +-
 .../brooklyn/policy/loadbalancing/Movable.java  |    2 +-
 .../enricher/HttpLatencyDetectorTest.java       |    4 +-
 .../brooklyn/enricher/RebindEnricherTest.java   |    2 +-
 .../brooklyn/policy/ha/ServiceReplacerTest.java |    2 +-
 .../policy/ha/ServiceRestarterTest.java         |    2 +-
 .../loadbalancing/MockContainerEntity.java      |    2 +-
 .../basic/AbstractSoftwareProcessDriver.java    |    8 +-
 .../basic/AbstractSoftwareProcessSshDriver.java |   12 +-
 .../SameServerDriverLifecycleEffectorTasks.java |    4 +-
 .../brooklyn/entity/basic/SameServerEntity.java |    2 +-
 .../entity/basic/SameServerEntityImpl.java      |    6 +-
 .../brooklyn/entity/basic/SoftwareProcess.java  |    2 +-
 ...wareProcessDriverLifecycleEffectorTasks.java |    4 +-
 .../entity/basic/SoftwareProcessImpl.java       |    8 +-
 .../basic/VanillaSoftwareProcessSshDriver.java  |    4 +-
 .../basic/lifecycle/NaiveScriptRunner.java      |    2 +-
 .../entity/basic/lifecycle/ScriptHelper.java    |   12 +-
 .../brooklynnode/BrooklynEntityMirrorImpl.java  |    8 +-
 .../entity/brooklynnode/BrooklynNode.java       |    2 +-
 .../entity/brooklynnode/BrooklynNodeImpl.java   |   12 +-
 .../brooklynnode/BrooklynNodeSshDriver.java     |   10 +-
 .../entity/brooklynnode/EntityHttpClient.java   |    4 +-
 .../brooklynnode/EntityHttpClientImpl.java      |    6 +-
 .../brooklynnode/RemoteEffectorBuilder.java     |    2 +-
 .../BrooklynClusterUpgradeEffectorBody.java     |    6 +-
 .../BrooklynNodeUpgradeEffectorBody.java        |    6 +-
 .../effector/SelectMasterEffectorBody.java      |    4 +-
 .../SetHighAvailabilityModeEffectorBody.java    |    4 +-
 ...SetHighAvailabilityPriorityEffectorBody.java |    4 +-
 .../brooklyn/entity/chef/ChefAttributeFeed.java |    4 +-
 .../java/brooklyn/entity/chef/ChefConfig.java   |    3 +-
 .../entity/chef/ChefLifecycleEffectorTasks.java |   10 +-
 .../brooklyn/entity/chef/ChefServerTasks.java   |    2 +-
 .../brooklyn/entity/chef/ChefSoloDriver.java    |    3 +-
 .../java/brooklyn/entity/chef/ChefTasks.java    |   10 +-
 .../entity/chef/KnifeConvergeTaskFactory.java   |    4 +-
 .../brooklyn/entity/chef/KnifeTaskFactory.java  |   10 +-
 .../java/JavaSoftwareProcessSshDriver.java      |   16 +-
 .../java/brooklyn/entity/java/JmxSupport.java   |    8 +-
 .../brooklyn/entity/java/JmxmpSslSupport.java   |    7 +-
 .../java/brooklyn/entity/java/UsesJava.java     |    3 +-
 .../brooklyn/entity/java/UsesJavaMXBeans.java   |    2 +-
 .../main/java/brooklyn/entity/java/UsesJmx.java |    3 +-
 .../brooklyn/entity/java/VanillaJavaApp.java    |    2 +-
 .../entity/java/VanillaJavaAppImpl.java         |    2 +-
 .../entity/java/VanillaJavaAppSshDriver.java    |   10 +-
 .../entity/machine/MachineEntityImpl.java       |    6 +-
 .../brooklyn/entity/pool/ServerPoolImpl.java    |    2 +-
 .../entity/pool/ServerPoolLocation.java         |    3 +-
 .../entity/service/EntityLaunchListener.java    |    2 +-
 .../entity/service/InitdServiceInstaller.java   |   12 +-
 .../entity/service/SystemServiceEnricher.java   |   14 +-
 .../entity/software/MachineInitTasks.java       |    8 +-
 .../software/MachineLifecycleEffectorTasks.java |    8 +-
 .../software/ProvidesProvisioningFlags.java     |    3 +-
 .../entity/software/SshEffectorTasks.java       |   24 +-
 .../brooklyn/entity/software/StaticSensor.java  |    6 +-
 .../entity/software/http/HttpRequestSensor.java |    2 +-
 .../software/java/JmxAttributeSensor.java       |    6 +-
 .../entity/software/ssh/SshCommandEffector.java |    2 +-
 .../entity/software/ssh/SshCommandSensor.java   |    4 +-
 .../winrm/WindowsPerformanceCounterSensors.java |    2 +-
 .../java/brooklyn/event/feed/jmx/JmxHelper.java |    2 +-
 .../basic/SoftwareProcessEntityLatchTest.java   |    2 +-
 .../basic/SoftwareProcessEntityRebindTest.java  |    3 +-
 .../entity/basic/SoftwareProcessEntityTest.java |    6 +-
 ...SoftwareProcessSshDriverIntegrationTest.java |    2 +-
 ...ftwareProcessAndChildrenIntegrationTest.java |    2 +-
 .../entity/basic/lifecycle/MyEntityImpl.java    |    6 +-
 .../basic/lifecycle/NaiveScriptRunnerTest.java  |    6 +-
 .../basic/lifecycle/StartStopSshDriverTest.java |    8 +-
 .../BrooklynNodeIntegrationTest.java            |    8 +-
 .../brooklynnode/CallbackEntityHttpClient.java  |    4 +-
 .../entity/chef/ChefLiveTestSupport.java        |    2 +-
 .../chef/ChefServerTasksIntegrationTest.java    |    2 +-
 .../ChefSoloDriverMySqlEntityLiveTest.java      |    2 +-
 .../java/brooklyn/entity/java/JavaOptsTest.java |    6 +-
 .../brooklyn/entity/java/JmxSupportTest.java    |    4 +-
 .../brooklyn/entity/java/SslKeyConfigTest.java  |    5 +-
 .../entity/java/VanillaJavaAppRebindTest.java   |    2 +-
 .../entity/java/VanillaJavaAppTest.java         |    8 +-
 .../MachineLifecycleEffectorTasksTest.java      |    4 +-
 .../entity/software/SoftwareEffectorTest.java   |    5 +-
 .../entity/software/SshEffectorTasksTest.java   |    6 +-
 .../entity/software/StaticSensorTest.java       |    2 +-
 .../software/http/HttpRequestSensorTest.java    |    2 +-
 .../mysql/AbstractToyMySqlEntityTest.java       |    2 +-
 .../mysql/DynamicToyMySqlEntityBuilder.java     |    8 +-
 .../software/ssh/SshCommandIntegrationTest.java |    2 +-
 .../entity/database/DatastoreMixins.java        |    4 +-
 .../entity/database/crate/CrateNode.java        |    3 +-
 .../entity/database/mariadb/MariaDbDriver.java  |    3 +-
 .../entity/database/mariadb/MariaDbNode.java    |    3 +-
 .../database/mariadb/MariaDbNodeImpl.java       |    4 +-
 .../database/mariadb/MariaDbSshDriver.java      |    4 +-
 .../entity/database/mysql/MySqlClusterImpl.java |    4 +-
 .../entity/database/mysql/MySqlDriver.java      |    3 +-
 .../entity/database/mysql/MySqlNode.java        |    3 +-
 .../entity/database/mysql/MySqlNodeImpl.java    |    4 +-
 .../entity/database/mysql/MySqlSshDriver.java   |    4 +-
 .../database/postgresql/PostgreSqlDriver.java   |    3 +-
 .../database/postgresql/PostgreSqlNode.java     |    3 +-
 .../PostgreSqlNodeChefImplFromScratch.java      |    8 +-
 .../database/postgresql/PostgreSqlNodeImpl.java |    2 +-
 .../postgresql/PostgreSqlSshDriver.java         |    8 +-
 .../entity/database/rubyrep/RubyRepNode.java    |    2 +-
 .../database/postgresql/PostgreSqlChefTest.java |    2 +-
 .../messaging/activemq/ActiveMQBroker.java      |    2 +-
 .../entity/messaging/amqp/AmqpExchange.java     |    2 +-
 .../brooklyn/entity/messaging/kafka/Kafka.java  |    3 +-
 .../entity/messaging/kafka/KafkaBroker.java     |    4 +-
 .../entity/messaging/kafka/KafkaCluster.java    |    2 +-
 .../entity/messaging/kafka/KafkaZooKeeper.java  |    2 +-
 .../entity/messaging/qpid/QpidBroker.java       |    2 +-
 .../messaging/qpid/QpidDestinationImpl.java     |    2 +-
 .../entity/messaging/rabbit/RabbitBroker.java   |    2 +-
 .../brooklyn/entity/messaging/storm/Storm.java  |    2 +-
 .../entity/messaging/storm/StormDeployment.java |    2 +-
 .../messaging/storm/StormDeploymentImpl.java    |    2 +-
 .../entity/zookeeper/ZooKeeperEnsemble.java     |    2 +-
 .../entity/zookeeper/ZooKeeperNode.java         |    2 +-
 .../storm/StormAbstractCloudLiveTest.java       |    4 +-
 .../entity/monitoring/monit/MonitNode.java      |    2 +-
 .../entity/network/bind/BindDnsServer.java      |    4 +-
 .../nosql/cassandra/CassandraDatacenter.java    |    2 +-
 .../cassandra/CassandraDatacenterImpl.java      |    4 +-
 .../entity/nosql/cassandra/CassandraNode.java   |    4 +-
 .../nosql/cassandra/CassandraNodeDriver.java    |    3 +-
 .../nosql/cassandra/CassandraNodeImpl.java      |    4 +-
 .../nosql/cassandra/CassandraNodeSshDriver.java |    8 +-
 .../nosql/couchbase/CouchbaseCluster.java       |    2 +-
 .../nosql/couchbase/CouchbaseClusterImpl.java   |   10 +-
 .../entity/nosql/couchbase/CouchbaseNode.java   |    2 +-
 .../nosql/couchbase/CouchbaseNodeImpl.java      |    8 +-
 .../nosql/couchbase/CouchbaseNodeSshDriver.java |   12 +-
 .../nosql/couchbase/CouchbaseSyncGateway.java   |    2 +-
 .../entity/nosql/couchdb/CouchDBCluster.java    |    2 +-
 .../entity/nosql/couchdb/CouchDBNode.java       |    2 +-
 .../entity/nosql/couchdb/CouchDBNodeImpl.java   |    2 +-
 .../elasticsearch/ElasticSearchCluster.java     |    2 +-
 .../nosql/elasticsearch/ElasticSearchNode.java  |    3 +-
 .../elasticsearch/ElasticSearchNodeImpl.java    |    4 +-
 .../nosql/mongodb/AbstractMongoDBServer.java    |    2 +-
 .../entity/nosql/mongodb/MongoDBClient.java     |    3 +-
 .../entity/nosql/mongodb/MongoDBReplicaSet.java |    2 +-
 .../entity/nosql/mongodb/MongoDBServer.java     |    2 +-
 .../sharding/CoLocatedMongoDBRouter.java        |    2 +-
 .../sharding/MongoDBShardedDeployment.java      |    2 +-
 .../brooklyn/entity/nosql/redis/RedisSlave.java |    2 +-
 .../brooklyn/entity/nosql/redis/RedisStore.java |    2 +-
 .../brooklyn/entity/nosql/riak/RiakCluster.java |    2 +-
 .../entity/nosql/riak/RiakClusterImpl.java      |    2 +-
 .../brooklyn/entity/nosql/riak/RiakNode.java    |    2 +-
 .../entity/nosql/riak/RiakNodeImpl.java         |    2 +-
 .../entity/nosql/riak/RiakNodeSshDriver.java    |    4 +-
 .../brooklyn/entity/nosql/solr/SolrServer.java  |    4 +-
 .../entity/nosql/solr/SolrServerSshDriver.java  |    2 +-
 .../cassandra/CassandraDatacenterTest.java      |    4 +-
 .../ElasticSearchClusterIntegrationTest.java    |    4 +-
 .../ElasticSearchNodeIntegrationTest.java       |    5 +-
 .../entity/osgi/karaf/KarafContainer.java       |    2 +-
 .../entity/dns/AbstractGeoDnsServiceImpl.java   |    2 +-
 .../dns/geoscaling/GeoscalingDnsService.java    |    2 +-
 .../geoscaling/GeoscalingDnsServiceImpl.java    |    4 +-
 .../geoscaling/GeoscalingScriptGenerator.java   |    3 +-
 .../dns/geoscaling/GeoscalingWebClient.java     |    2 +-
 .../entity/proxy/AbstractController.java        |    2 +-
 .../entity/proxy/AbstractControllerImpl.java    |    2 +-
 .../brooklyn/entity/proxy/LoadBalancer.java     |    2 +-
 .../brooklyn/entity/proxy/ProxySslConfig.java   |    5 +-
 .../entity/proxy/nginx/NginxController.java     |    2 +-
 .../entity/proxy/nginx/NginxControllerImpl.java |    8 +-
 .../entity/proxy/nginx/NginxSshDriver.java      |    8 +-
 .../nginx/NginxTemplateConfigGenerator.java     |    4 +-
 .../brooklyn/entity/proxy/nginx/UrlMapping.java |    2 +-
 .../webapp/ControlledDynamicWebAppCluster.java  |    2 +-
 .../entity/webapp/DynamicWebAppClusterImpl.java |    8 +-
 .../entity/webapp/JavaWebAppService.java        |    2 +-
 .../entity/webapp/JavaWebAppSshDriver.java      |    8 +-
 .../entity/webapp/WebAppServiceConstants.java   |    2 +-
 .../entity/webapp/jboss/JBoss6Server.java       |    2 +-
 .../entity/webapp/jboss/JBoss7Server.java       |    2 +-
 .../entity/webapp/jetty/Jetty6Server.java       |    2 +-
 .../webapp/nodejs/NodeJsWebAppService.java      |    3 +-
 .../webapp/nodejs/NodeJsWebAppSshDriver.java    |    4 +-
 .../entity/webapp/tomcat/Tomcat8Server.java     |    2 +-
 .../entity/webapp/tomcat/TomcatServer.java      |    4 +-
 .../GeoscalingScriptGeneratorTest.java          |    3 +-
 .../dns/geoscaling/GeoscalingWebClientTest.java |    2 +-
 .../entity/proxy/AbstractControllerTest.java    |    2 +-
 .../entity/proxy/ProxySslConfigTest.java        |    2 +-
 .../nginx/NginxRebindWithHaIntegrationTest.java |    4 +-
 .../AbstractWebAppFixtureIntegrationTest.java   |    4 +-
 .../entity/webapp/HttpsSslConfigTest.java       |    2 +-
 .../webapp/WebAppConcurrentDeployTest.java      |    4 +-
 .../test/entity/TestJavaWebAppEntity.java       |    2 +-
 .../test/entity/TestJavaWebAppEntityImpl.java   |    2 +-
 .../app/SampleLocalhostIntegrationTest.java     |    2 +-
 .../camp/brooklyn/YamlLauncherAbstract.java     |    2 +-
 .../BrooklynAssemblyTemplateInstantiator.java   |    4 +-
 .../BrooklynComponentTemplateResolver.java      |   10 +-
 .../BrooklynEntityDecorationResolver.java       |    2 +-
 .../creation/BrooklynYamlTypeInstantiator.java  |    2 +-
 .../spi/dsl/BrooklynDslDeferredSupplier.java    |    2 +-
 .../camp/brooklyn/spi/dsl/DslUtils.java         |    2 +-
 .../spi/dsl/methods/BrooklynDslCommon.java      |   10 +-
 .../brooklyn/spi/dsl/methods/DslComponent.java  |    4 +-
 .../camp/brooklyn/AbstractYamlRebindTest.java   |    4 +-
 .../camp/brooklyn/AbstractYamlTest.java         |    4 +-
 .../camp/brooklyn/DslAndRebindYamlTest.java     |    2 +-
 .../camp/brooklyn/EntitiesYamlTest.java         |    2 +-
 ...aWebAppWithDslYamlRebindIntegrationTest.java |    2 +-
 .../brooklyn/JavaWebAppsIntegrationTest.java    |    2 +-
 .../camp/brooklyn/JavaWebAppsMatchingTest.java  |    4 +-
 .../camp/brooklyn/MapReferenceYamlTest.java     |    2 +-
 .../brooklyn/camp/brooklyn/ObjectsYamlTest.java |    6 +-
 .../brooklyn/ReloadBrooklynPropertiesTest.java  |    2 +-
 .../TestSensorAndEffectorInitializer.java       |    2 +-
 .../catalog/AbstractCatalogXmlTest.java         |    2 +-
 .../CatalogOsgiVersionMoreEntityTest.java       |    2 +-
 .../brooklyn/catalog/CatalogYamlEntityTest.java |    2 +-
 .../org/apache/brooklyn/cli/ItemLister.java     |    4 +-
 .../main/java/org/apache/brooklyn/cli/Main.java |    2 +-
 .../apache/brooklyn/cli/lister/ClassFinder.java |    4 +-
 .../java/org/apache/brooklyn/cli/CliTest.java   |    2 +-
 .../brooklyn/launcher/BrooklynWebServer.java    |   14 +-
 .../launcher/config/CustomResourceLocator.java  |    2 +-
 .../entity/basic/VanillaSoftwareYamlTest.java   |    2 +-
 .../brooklynnode/BrooklynNodeRestTest.java      |    6 +-
 .../database/mssql/MssqlBlueprintLiveTest.java  |    5 +-
 .../BrooklynLauncherRebindCatalogTest.java      |    2 +-
 .../launcher/BrooklynWebServerTest.java         |    4 +-
 .../blueprints/AbstractBlueprintTest.java       |    2 +-
 .../qa/load/SimulatedMySqlNodeImpl.java         |    6 +-
 .../brooklyn/qa/longevity/MonitorUtils.java     |    4 +-
 .../SoftlayerObtainPrivateLiveTest.java         |    2 +-
 .../resources/AbstractBrooklynRestResource.java |    2 +-
 .../rest/resources/ApplicationResource.java     |    2 +-
 .../rest/resources/CatalogResource.java         |    2 +-
 .../rest/resources/EntityConfigResource.java    |    4 +-
 .../brooklyn/rest/resources/EntityResource.java |    2 +-
 .../rest/resources/PolicyConfigResource.java    |    3 +-
 .../brooklyn/rest/resources/SensorResource.java |    2 +-
 .../brooklyn/rest/resources/ServerResource.java |    6 +-
 .../rest/transform/EffectorTransformer.java     |    4 +-
 .../rest/transform/LocationTransformer.java     |    2 +-
 .../rest/transform/TaskTransformer.java         |    2 +-
 .../rest/util/BrooklynRestResourceUtils.java    |    2 +-
 .../rest/util/DefaultExceptionMapper.java       |    2 +-
 .../BrooklynPropertiesSecurityFilterTest.java   |    6 +-
 .../brooklyn/rest/HaMasterCheckFilterTest.java  |    4 +-
 .../rest/resources/CatalogResetTest.java        |    2 +-
 .../SensorResourceIntegrationTest.java          |    4 +-
 .../ServerResourceIntegrationTest.java          |    7 +-
 .../testing/mocks/RestMockSimpleEntity.java     |    3 +-
 .../testing/mocks/RestMockSimplePolicy.java     |    2 +-
 .../json/BrooklynJacksonSerializerTest.java     |    2 +-
 .../util/jmx/jmxmp/JmxmpAgentSslTest.java       |    5 +-
 .../brooklyn/util/jmx/jmxmp/JmxmpClient.java    |    3 +-
 .../brooklyn/osgi/tests/SimpleLocation.java     |    3 +-
 .../java/brooklyn/osgi/tests/SimplePolicy.java  |    3 +-
 .../osgi/tests/more/MoreEntityImpl.java         |    3 +-
 .../osgi/tests/more/MoreEntityImpl.java         |    2 +-
 .../osgi/tests/more/MoreEntityImpl.java         |    2 +-
 795 files changed, 28078 insertions(+), 27902 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/BrooklynVersion.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/BrooklynVersion.java b/core/src/main/java/brooklyn/BrooklynVersion.java
index dbc7869..bf45a99 100644
--- a/core/src/main/java/brooklyn/BrooklynVersion.java
+++ b/core/src/main/java/brooklyn/BrooklynVersion.java
@@ -45,11 +45,11 @@ import com.google.common.collect.Maps;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.classloading.OsgiBrooklynClassLoadingContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.osgi.Osgis;
+import org.apache.brooklyn.core.util.osgi.Osgis.ManifestHelper;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.osgi.Osgis;
-import brooklyn.util.osgi.Osgis.ManifestHelper;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
index c990ed9..76641bf 100644
--- a/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
+++ b/core/src/main/java/brooklyn/basic/AbstractBrooklynObject.java
@@ -25,14 +25,14 @@ import java.util.Set;
 import org.apache.brooklyn.api.basic.internal.ApiObjectsFactory;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.basic.AbstractEntity;
 import brooklyn.entity.proxying.InternalFactory;
 import brooklyn.entity.rebind.RebindManagerImpl;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.Identifiers;
 
 import com.google.common.collect.ImmutableSet;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/basic/BasicConfigurableObject.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/BasicConfigurableObject.java b/core/src/main/java/brooklyn/basic/BasicConfigurableObject.java
index d02f1bd..0604f3a 100644
--- a/core/src/main/java/brooklyn/basic/BasicConfigurableObject.java
+++ b/core/src/main/java/brooklyn/basic/BasicConfigurableObject.java
@@ -23,13 +23,13 @@ import org.apache.brooklyn.api.entity.trait.Identifiable;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.core.management.ManagementContextInjectable;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.camp.brooklyn.api.HasBrooklynManagementContext;
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.config.ConfigMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.Identifiers;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java b/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
index dbf8bbc..52d1413 100644
--- a/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
+++ b/core/src/main/java/brooklyn/basic/BrooklynDynamicType.java
@@ -34,13 +34,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.brooklyn.api.basic.BrooklynObject;
 import org.apache.brooklyn.api.basic.BrooklynType;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.event.basic.BasicConfigKey.BasicConfigKeyOverwriting;
-import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.javalang.Reflections;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/basic/BrooklynObjectInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/BrooklynObjectInternal.java b/core/src/main/java/brooklyn/basic/BrooklynObjectInternal.java
index 038013f..ef9212a 100644
--- a/core/src/main/java/brooklyn/basic/BrooklynObjectInternal.java
+++ b/core/src/main/java/brooklyn/basic/BrooklynObjectInternal.java
@@ -24,10 +24,10 @@ import org.apache.brooklyn.api.basic.BrooklynObject;
 import org.apache.brooklyn.api.entity.rebind.RebindSupport;
 import org.apache.brooklyn.api.entity.rebind.Rebindable;
 import org.apache.brooklyn.api.entity.trait.Configurable;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Maybe;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/basic/internal/ApiObjectsFactoryImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/basic/internal/ApiObjectsFactoryImpl.java b/core/src/main/java/brooklyn/basic/internal/ApiObjectsFactoryImpl.java
index 8e0f5a4..654c51a 100644
--- a/core/src/main/java/brooklyn/basic/internal/ApiObjectsFactoryImpl.java
+++ b/core/src/main/java/brooklyn/basic/internal/ApiObjectsFactoryImpl.java
@@ -21,9 +21,9 @@ package brooklyn.basic.internal;
 import org.apache.brooklyn.api.basic.internal.ApiObjectsFactoryInterface;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.task.Tasks;
 
 import brooklyn.entity.basic.BrooklynTaskTags;
-import brooklyn.util.task.Tasks;
 
 public class ApiObjectsFactoryImpl implements ApiObjectsFactoryInterface {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/config/BrooklynProperties.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/config/BrooklynProperties.java b/core/src/main/java/brooklyn/config/BrooklynProperties.java
index 2c76b21..921fe22 100644
--- a/core/src/main/java/brooklyn/config/BrooklynProperties.java
+++ b/core/src/main/java/brooklyn/config/BrooklynProperties.java
@@ -33,15 +33,15 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Properties;
 
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.StringFunctions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/config/BrooklynServerPaths.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/config/BrooklynServerPaths.java b/core/src/main/java/brooklyn/config/BrooklynServerPaths.java
index a865d5b..0e0a5c9 100644
--- a/core/src/main/java/brooklyn/config/BrooklynServerPaths.java
+++ b/core/src/main/java/brooklyn/config/BrooklynServerPaths.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.apache.commons.io.FileUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,7 +37,6 @@ import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
 import brooklyn.util.time.Time;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/config/internal/AbstractConfigMapImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/config/internal/AbstractConfigMapImpl.java b/core/src/main/java/brooklyn/config/internal/AbstractConfigMapImpl.java
index defb5bc..c648654 100644
--- a/core/src/main/java/brooklyn/config/internal/AbstractConfigMapImpl.java
+++ b/core/src/main/java/brooklyn/config/internal/AbstractConfigMapImpl.java
@@ -23,6 +23,8 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.concurrent.Future;
 
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.DeferredSupplier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,8 +33,6 @@ import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.config.ConfigMap;
 import brooklyn.entity.basic.ConfigMapViewWithStringKeys;
 import brooklyn.event.basic.StructuredConfigKey;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.task.DeferredSupplier;
 
 public abstract class AbstractConfigMapImpl implements ConfigMap {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/CustomAggregatingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/CustomAggregatingEnricher.java b/core/src/main/java/brooklyn/enricher/CustomAggregatingEnricher.java
index 1089ae4..4924684 100644
--- a/core/src/main/java/brooklyn/enricher/CustomAggregatingEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/CustomAggregatingEnricher.java
@@ -26,12 +26,12 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.enricher.basic.AbstractAggregatingEnricher;
 import brooklyn.util.GroovyJavaMethods;
-import brooklyn.util.flags.TypeCoercions;
 
 import com.google.common.base.Function;
 import com.google.common.base.Throwables;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/Enrichers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/Enrichers.java b/core/src/main/java/brooklyn/enricher/Enrichers.java
index 54af8d1..00aa03f 100644
--- a/core/src/main/java/brooklyn/enricher/Enrichers.java
+++ b/core/src/main/java/brooklyn/enricher/Enrichers.java
@@ -32,6 +32,7 @@ import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EnricherSpec;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.enricher.basic.Aggregator;
@@ -43,7 +44,6 @@ import brooklyn.enricher.basic.UpdatingMap;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.text.StringPredicates;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
index da5e822..5bca143 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractEnricher.java
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.mementos.EnricherMemento;
 import org.apache.brooklyn.api.policy.Enricher;
 import org.apache.brooklyn.api.policy.EnricherType;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -36,7 +37,6 @@ import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.rebind.BasicEnricherRebindSupport;
 import brooklyn.policy.basic.AbstractEntityAdjunct;
-import brooklyn.util.flags.TypeCoercions;
 
 import com.google.common.base.Objects;
 import com.google.common.collect.Maps;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java b/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java
index af47c59..84db77f 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractMultipleSensorAggregator.java
@@ -30,12 +30,12 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.BrooklynLogging;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.TypeCoercions;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/basic/AbstractTypeTransformingEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/AbstractTypeTransformingEnricher.java b/core/src/main/java/brooklyn/enricher/basic/AbstractTypeTransformingEnricher.java
index 7bf0ef6..cd9a33f 100644
--- a/core/src/main/java/brooklyn/enricher/basic/AbstractTypeTransformingEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/AbstractTypeTransformingEnricher.java
@@ -23,9 +23,9 @@ import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.event.basic.BasicSensorEvent;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * Convenience base for transforming a single sensor into a single new sensor of the same type

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Aggregator.java b/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
index c14487b..5512c28 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Aggregator.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,7 +41,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.StringPredicates;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/basic/Joiner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Joiner.java b/core/src/main/java/brooklyn/enricher/basic/Joiner.java
index 8c65681..f9e9d4e 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Joiner.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Joiner.java
@@ -26,6 +26,7 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,7 +34,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicSensorEvent;
 import brooklyn.util.collections.MutableList;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.StringEscapes;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/basic/Propagator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Propagator.java b/core/src/main/java/brooklyn/enricher/basic/Propagator.java
index 187ad8d..f6d2ee8 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Propagator.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Propagator.java
@@ -28,6 +28,9 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ValueResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,9 +38,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ValueResolver;
 
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/basic/Transformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/Transformer.java b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
index 7e331ba..705c626 100644
--- a/core/src/main/java/brooklyn/enricher/basic/Transformer.java
+++ b/core/src/main/java/brooklyn/enricher/basic/Transformer.java
@@ -21,14 +21,14 @@ package brooklyn.enricher.basic;
 import static com.google.common.base.Preconditions.checkArgument;
 
 import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ValueResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ValueResolver;
 
 import com.google.common.base.Function;
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/basic/UpdatingMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/UpdatingMap.java b/core/src/main/java/brooklyn/enricher/basic/UpdatingMap.java
index a973774..a396e6c 100644
--- a/core/src/main/java/brooklyn/enricher/basic/UpdatingMap.java
+++ b/core/src/main/java/brooklyn/enricher/basic/UpdatingMap.java
@@ -25,6 +25,7 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,7 +34,6 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.Entities;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Function;
 import com.google.common.collect.Maps;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricher.java b/core/src/main/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricher.java
index 65df607..f94c203 100644
--- a/core/src/main/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricher.java
+++ b/core/src/main/java/brooklyn/enricher/basic/YamlTimeWeightedDeltaEnricher.java
@@ -19,13 +19,13 @@
 package brooklyn.enricher.basic;
 
 import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.enricher.basic.AbstractTransformer;
 import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/AbstractEffector.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEffector.java b/core/src/main/java/brooklyn/entity/basic/AbstractEffector.java
index bf29732..2988aeb 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEffector.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEffector.java
@@ -27,14 +27,14 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ParameterType;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.core.management.internal.EffectorUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.DynamicSequentialTask;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.effector.EffectorBase;
 import brooklyn.entity.effector.EffectorTasks.EffectorTaskFactory;
 import brooklyn.entity.effector.EffectorWithBody;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.task.DynamicSequentialTask;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
index 1d21a7e..4bdae46 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -60,6 +60,10 @@ import org.apache.brooklyn.core.management.internal.EffectorUtils;
 import org.apache.brooklyn.core.management.internal.EntityManagementSupport;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.management.internal.SubscriptionTracker;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.task.DeferredSupplier;
 import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -91,12 +95,8 @@ import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.collections.SetFromLiveMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.Equals;
-import brooklyn.util.task.DeferredSupplier;
 import brooklyn.util.text.Strings;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/BasicGroup.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/BasicGroup.java b/core/src/main/java/brooklyn/entity/basic/BasicGroup.java
index 0bb67b6..05606af 100644
--- a/core/src/main/java/brooklyn/entity/basic/BasicGroup.java
+++ b/core/src/main/java/brooklyn/entity/basic/BasicGroup.java
@@ -19,10 +19,10 @@
 package brooklyn.entity.basic;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 @ImplementedBy(BasicGroupImpl.class)
 public interface BasicGroup extends AbstractGroup {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/BrooklynConfigKeys.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/BrooklynConfigKeys.java b/core/src/main/java/brooklyn/entity/basic/BrooklynConfigKeys.java
index 7910267..d9e4903 100644
--- a/core/src/main/java/brooklyn/entity/basic/BrooklynConfigKeys.java
+++ b/core/src/main/java/brooklyn/entity/basic/BrooklynConfigKeys.java
@@ -26,9 +26,9 @@ import brooklyn.event.basic.AttributeSensorAndConfigKey;
 import brooklyn.event.basic.TemplatedStringAttributeSensorAndConfigKey;
 
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.internal.ssh.SshTool;
 
-import brooklyn.util.internal.ssh.ShellTool;
-import brooklyn.util.internal.ssh.SshTool;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Preconditions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/BrooklynShutdownHooks.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/BrooklynShutdownHooks.java b/core/src/main/java/brooklyn/entity/basic/BrooklynShutdownHooks.java
index 6032fff..79fe68f 100644
--- a/core/src/main/java/brooklyn/entity/basic/BrooklynShutdownHooks.java
+++ b/core/src/main/java/brooklyn/entity/basic/BrooklynShutdownHooks.java
@@ -27,6 +27,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,7 +37,6 @@ import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.exceptions.RuntimeInterruptedException;
 import brooklyn.util.javalang.Threads;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.CountdownTimer;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java b/core/src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java
index 3cdfc39..2904ff5 100644
--- a/core/src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java
+++ b/core/src/main/java/brooklyn/entity/basic/BrooklynTaskTags.java
@@ -33,16 +33,16 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.management.ExecutionManager;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.entitlement.EntitlementContext;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.task.TaskTags;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.codehaus.jackson.annotate.JsonProperty;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.javalang.MemoryUsageTracker;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.TaskTags;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.StringEscapes.BashStringEscapes;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/ConfigKeys.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/ConfigKeys.java b/core/src/main/java/brooklyn/entity/basic/ConfigKeys.java
index 2b22a90..a50c800 100644
--- a/core/src/main/java/brooklyn/entity/basic/ConfigKeys.java
+++ b/core/src/main/java/brooklyn/entity/basic/ConfigKeys.java
@@ -22,6 +22,7 @@ import java.util.Map;
 
 import javax.annotation.Nonnull;
 
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,7 +33,6 @@ import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.TemplatedStringAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicConfigKey.BasicConfigKeyOverwriting;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/DataEntity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/DataEntity.java b/core/src/main/java/brooklyn/entity/basic/DataEntity.java
index 27f1c33..534e125 100644
--- a/core/src/main/java/brooklyn/entity/basic/DataEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/DataEntity.java
@@ -23,10 +23,10 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.trait.Startable;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.base.Supplier;
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/DynamicGroup.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/DynamicGroup.java b/core/src/main/java/brooklyn/entity/basic/DynamicGroup.java
index 078fc88..9ad8c83 100644
--- a/core/src/main/java/brooklyn/entity/basic/DynamicGroup.java
+++ b/core/src/main/java/brooklyn/entity/basic/DynamicGroup.java
@@ -23,6 +23,7 @@ import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.Sensor;
 import org.apache.brooklyn.api.event.SensorEvent;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import com.google.common.base.Predicate;
 import com.google.common.reflect.TypeToken;
@@ -31,7 +32,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.Effector;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 import groovy.lang.Closure;
 
 @ImplementedBy(DynamicGroupImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
index 7ffe8a0..3b1eb47 100644
--- a/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
+++ b/core/src/main/java/brooklyn/entity/basic/DynamicGroupImpl.java
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.core.management.internal.CollectionChangeListener;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,7 +38,6 @@ import brooklyn.config.BrooklynLogging;
 import brooklyn.config.BrooklynLogging.LoggingLevel;
 import brooklyn.util.GroovyJavaMethods;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.Tasks;
 
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/EffectorStartableImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EffectorStartableImpl.java b/core/src/main/java/brooklyn/entity/basic/EffectorStartableImpl.java
index 0abb90c..f60f408 100644
--- a/core/src/main/java/brooklyn/entity/basic/EffectorStartableImpl.java
+++ b/core/src/main/java/brooklyn/entity/basic/EffectorStartableImpl.java
@@ -29,8 +29,7 @@ import brooklyn.entity.annotation.EffectorParam;
 import brooklyn.entity.trait.Startable;
 
 import org.apache.brooklyn.api.location.Location;
-
-import brooklyn.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/Entities.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/Entities.java b/core/src/main/java/brooklyn/entity/basic/Entities.java
index c768726..635e99c 100644
--- a/core/src/main/java/brooklyn/entity/basic/Entities.java
+++ b/core/src/main/java/brooklyn/entity/basic/Entities.java
@@ -64,6 +64,15 @@ import org.apache.brooklyn.core.management.internal.EntityManagerInternal;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
 import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.management.internal.NonDeploymentManagementContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.ParallelTask;
+import org.apache.brooklyn.core.util.task.TaskTags;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.core.util.task.system.SystemTasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -80,20 +89,11 @@ import brooklyn.event.basic.DependentConfiguration;
 import org.apache.brooklyn.location.basic.LocationInternal;
 import org.apache.brooklyn.location.basic.Locations;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.FlagUtils;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.repeat.Repeater;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.ParallelTask;
-import brooklyn.util.task.TaskTags;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-import brooklyn.util.task.system.SystemTasks;
 import brooklyn.util.time.Duration;
 
 import com.google.common.annotations.Beta;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/EntityConfigMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EntityConfigMap.java b/core/src/main/java/brooklyn/entity/basic/EntityConfigMap.java
index 988d6d7..8a7a9f0 100644
--- a/core/src/main/java/brooklyn/entity/basic/EntityConfigMap.java
+++ b/core/src/main/java/brooklyn/entity/basic/EntityConfigMap.java
@@ -28,6 +28,11 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.management.ExecutionContext;
 import org.apache.brooklyn.api.management.Task;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.internal.ConfigKeySelfExtracting;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,12 +41,7 @@ import brooklyn.config.ConfigKey;
 import brooklyn.config.internal.AbstractConfigMapImpl;
 import brooklyn.event.basic.StructuredConfigKey;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.SetFromFlag;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.internal.ConfigKeySelfExtracting;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.Maps;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/EntityFunctions.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EntityFunctions.java b/core/src/main/java/brooklyn/entity/basic/EntityFunctions.java
index 4e02948..d9afc44 100644
--- a/core/src/main/java/brooklyn/entity/basic/EntityFunctions.java
+++ b/core/src/main/java/brooklyn/entity/basic/EntityFunctions.java
@@ -30,9 +30,9 @@ import org.apache.brooklyn.api.entity.trait.Identifiable;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 
 import brooklyn.config.ConfigKey;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Functionals;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/entity/basic/EntityInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EntityInternal.java b/core/src/main/java/brooklyn/entity/basic/EntityInternal.java
index 085079f..36e6907 100644
--- a/core/src/main/java/brooklyn/entity/basic/EntityInternal.java
+++ b/core/src/main/java/brooklyn/entity/basic/EntityInternal.java
@@ -33,10 +33,10 @@ import org.apache.brooklyn.api.management.ManagementContext;
 import org.apache.brooklyn.api.management.SubscriptionContext;
 import org.apache.brooklyn.api.mementos.EntityMemento;
 import org.apache.brooklyn.core.management.internal.EntityManagementSupport;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 
 import brooklyn.basic.BrooklynObjectInternal;
 import brooklyn.config.ConfigKey;
-import brooklyn.util.config.ConfigBag;
 
 import com.google.common.annotations.Beta;
 



[03/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
index 83e0af0..0dc6390 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/qpid/QpidDestinationImpl.java
@@ -24,6 +24,7 @@ import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
 
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -33,7 +34,6 @@ import brooklyn.entity.messaging.jms.JMSDestinationImpl;
 import brooklyn.event.feed.jmx.JmxFeed;
 import brooklyn.event.feed.jmx.JmxHelper;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
 
 public abstract class QpidDestinationImpl extends JMSDestinationImpl implements QpidDestination {
     public static final Logger log = LoggerFactory.getLogger(QpidDestination.class);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBroker.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBroker.java b/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBroker.java
index a641638..a70bfce 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBroker.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/rabbit/RabbitBroker.java
@@ -25,6 +25,7 @@ import com.google.common.annotations.Beta;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -35,7 +36,6 @@ import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Rabbit MQ broker instance, using AMQP 0-9-1.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/storm/Storm.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/Storm.java b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/Storm.java
index e38aa6a..ced7bef 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/Storm.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/Storm.java
@@ -22,6 +22,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.config.render.RendererHints;
@@ -32,7 +33,6 @@ import brooklyn.entity.zookeeper.ZooKeeperEnsemble;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * An {@link org.apache.brooklyn.api.entity.Entity} that represents a Storm node (UI, Nimbus or Supervisor).

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeployment.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeployment.java b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeployment.java
index 92ce3aa..fda29fd 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeployment.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeployment.java
@@ -21,11 +21,11 @@ package brooklyn.entity.messaging.storm;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.trait.Startable;
-import brooklyn.util.flags.SetFromFlag;
 
 @Catalog(name="Storm Deployment", description="A Storm cluster. Apache Storm is a distributed realtime computation system. "
         + "Storm makes it easy to reliably process unbounded streams of data, doing for realtime processing "

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeploymentImpl.java b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
index d5b79cc..cf90db8 100644
--- a/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
+++ b/software/messaging/src/main/java/brooklyn/entity/messaging/storm/StormDeploymentImpl.java
@@ -24,6 +24,7 @@ import static brooklyn.entity.messaging.storm.Storm.Role.SUPERVISOR;
 import static brooklyn.entity.messaging.storm.Storm.Role.UI;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -32,7 +33,6 @@ import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.BasicStartableImpl;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.zookeeper.ZooKeeperEnsemble;
-import brooklyn.util.ResourceUtils;
 
 public class StormDeploymentImpl extends BasicStartableImpl implements StormDeployment {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java
index b09e7f8..e5869c5 100644
--- a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java
+++ b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperEnsemble.java
@@ -23,13 +23,13 @@ import java.util.List;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNode.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNode.java b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNode.java
index 4d6ecdf..504a894 100644
--- a/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNode.java
+++ b/software/messaging/src/main/java/brooklyn/entity/zookeeper/ZooKeeperNode.java
@@ -21,6 +21,7 @@ package brooklyn.entity.zookeeper;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -28,7 +29,6 @@ import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * An {@link org.apache.brooklyn.api.entity.Entity} that represents a single Apache ZooKeeper instance.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
----------------------------------------------------------------------
diff --git a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java b/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
index 758ace7..d79b2da 100644
--- a/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
+++ b/software/messaging/src/test/java/brooklyn/entity/messaging/storm/StormAbstractCloudLiveTest.java
@@ -31,6 +31,8 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.core.management.internal.LocalManagementContext;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.file.ArchiveBuilder;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,9 +54,7 @@ import brooklyn.entity.basic.Entities;
 import brooklyn.entity.messaging.storm.topologies.ExclamationBolt;
 import brooklyn.entity.trait.Startable;
 import brooklyn.entity.zookeeper.ZooKeeperEnsemble;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.file.ArchiveBuilder;
 import brooklyn.util.os.Os;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 7e0ca22..064a54b 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,6 +27,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.entity.trait.HasShortName;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
@@ -35,7 +36,6 @@ import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 @Catalog(name="Monit Node", description="Monit is a free open source utility for managing and monitoring, processes, programs, files, directories and filesystems on a UNIX system")
 @ImplementedBy(MonitNodeImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 032a471..fc27b19 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
@@ -29,6 +29,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.Effector;
@@ -37,8 +38,9 @@ import brooklyn.entity.basic.DynamicGroup;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
+
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.flags.SetFromFlag;
+
 import brooklyn.util.net.Cidr;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 dc01fd5..07e7f96 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
@@ -26,6 +26,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.nosql.cassandra.TokenGenerators.PosNeg63TokenGenerator;
 
 import brooklyn.config.ConfigKey;
@@ -37,7 +38,6 @@ import brooklyn.entity.effector.Effectors;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Supplier;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 a2ed4c4..5b5cb9b 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,6 +35,8 @@ import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -51,11 +53,9 @@ import brooklyn.entity.group.DynamicClusterImpl;
 
 import org.apache.brooklyn.location.basic.Machines;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableList;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 21fbbb7..f779de8 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
@@ -26,6 +26,7 @@ import org.apache.brooklyn.api.entity.Effector;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BrooklynConfigKeys;
@@ -38,8 +39,9 @@ import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
+
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.flags.SetFromFlag;
+
 import brooklyn.util.time.Duration;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeDriver.java
index eab6672..befaa6d 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraNodeDriver.java
@@ -18,8 +18,9 @@
  */
 package org.apache.brooklyn.entity.nosql.cassandra;
 
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+
 import brooklyn.entity.java.JavaSoftwareProcessDriver;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 
 public interface CassandraNodeDriver extends JavaSoftwareProcessDriver {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 2d82d19..b27b957 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,6 +36,8 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -59,11 +61,9 @@ import org.apache.brooklyn.location.basic.Machines;
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
 
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
 import brooklyn.util.time.Duration;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 c3a57b0..7806979 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,6 +31,10 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.basic.EntityLocal;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.management.TaskWrapper;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,12 +62,8 @@ import brooklyn.util.net.Networking;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 65b7dd0..a46e1a8 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
@@ -26,12 +26,12 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 3196428..fcb944d 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
@@ -33,6 +33,9 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,9 +65,6 @@ import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Functionals;
 import brooklyn.util.guava.IfFunctions;
 import brooklyn.util.math.MathPredicates;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.ByteSizeStrings;
 import brooklyn.util.text.StringFunctions;
 import brooklyn.util.text.Strings;
@@ -565,8 +565,8 @@ public class CouchbaseClusterImpl extends DynamicClusterImpl implements Couchbas
                                         .onFailureOrException(new Function<Object, Boolean>() {
                                             @Override
                                             public Boolean apply(Object input) {
-                                                if (input instanceof brooklyn.util.http.HttpToolResponse) {
-                                                    if (((brooklyn.util.http.HttpToolResponse) input).getResponseCode() == 404) {
+                                                if (input instanceof org.apache.brooklyn.core.util.http.HttpToolResponse) {
+                                                    if (((org.apache.brooklyn.core.util.http.HttpToolResponse) input).getResponseCode() == 404) {
                                                         return true;
                                                     }
                                                 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 bd244b9..5f3269a 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
@@ -23,6 +23,7 @@ import java.net.URI;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.config.render.RendererHints;
@@ -36,7 +37,6 @@ import brooklyn.entity.effector.Effectors;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.ByteSizeStrings;
 
 @Catalog(name="CouchBase Node", description="Couchbase Server is an open source, distributed (shared-nothing architecture) "

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 07b34b4..d27f7db 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,6 +30,10 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.http.auth.UsernamePasswordCredentials;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -47,15 +51,11 @@ import org.apache.brooklyn.location.cloud.CloudLocationConfig;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Functionals;
 import brooklyn.util.guava.MaybeFunctions;
 import brooklyn.util.guava.TypeTokens;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.net.Urls;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 41bef9f..f894937 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,6 +33,12 @@ 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.management.Task;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.TaskTags;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.apache.http.auth.UsernamePasswordCredentials;
 
 import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
@@ -49,14 +55,8 @@ import org.apache.brooklyn.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.repeat.Repeater;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.TaskTags;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.NaturalOrderComparator;
 import brooklyn.util.text.StringEscapes.BashStringEscapes;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 2e8dba9..07665a3 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
@@ -21,6 +21,7 @@ package org.apache.brooklyn.entity.nosql.couchbase;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -28,7 +29,6 @@ import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 @ImplementedBy(CouchbaseSyncGatewayImpl.class)
 public interface CouchbaseSyncGateway extends SoftwareProcess {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 2964da7..94b33c1 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,11 +20,11 @@ package org.apache.brooklyn.entity.nosql.couchdb;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * A cluster of {@link CouchDBNode}s based on {@link DynamicCluster} which can be resized by a policy if required.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 f438de6..9d89349 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
@@ -20,13 +20,13 @@ package org.apache.brooklyn.entity.nosql.couchdb;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.webapp.WebAppService;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * An {@link org.apache.brooklyn.api.entity.Entity} that represents a CouchDB node in a {@link CouchDBCluster}.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 b200f6e..7f8f639 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
@@ -22,6 +22,7 @@ import java.util.concurrent.TimeUnit;
 
 import javax.annotation.Nullable;
 
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
 import org.apache.brooklyn.entity.webapp.JavaWebAppSoftwareProcessImpl;
 import org.apache.brooklyn.entity.webapp.WebAppServiceMethods;
 import org.slf4j.Logger;
@@ -31,7 +32,6 @@ import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
-import brooklyn.util.flags.TypeCoercions;
 import brooklyn.util.guava.Functionals;
 
 import com.google.common.base.Function;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 f73a911..c8b9bd3 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,10 +20,10 @@ package org.apache.brooklyn.entity.nosql.elasticsearch;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * A cluster of {@link ElasticSearchNode}s based on {@link DynamicCluster} which can be resized by a policy if required.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 a2d82c0..d82e34b 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
@@ -21,6 +21,7 @@ package org.apache.brooklyn.entity.nosql.elasticsearch;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
 
 import brooklyn.config.ConfigKey;
@@ -31,8 +32,8 @@ import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey.StringAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
+
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * An {@link org.apache.brooklyn.api.entity.Entity} that represents an ElasticSearch node

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 4478ac3..eb81a93 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
@@ -21,18 +21,20 @@ package org.apache.brooklyn.entity.nosql.elasticsearch;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.event.feed.http.JsonFunctions;
+
 import org.apache.brooklyn.location.access.BrooklynAccessUtils;
+
 import brooklyn.util.guava.Functionals;
 import brooklyn.util.guava.Maybe;
 import brooklyn.util.guava.MaybeFunctions;
 import brooklyn.util.guava.TypeTokens;
-import brooklyn.util.http.HttpToolResponse;
 
 import com.google.common.base.Function;
 import com.google.common.base.Functions;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 81ea23c..b2c8410 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
@@ -19,6 +19,7 @@
 package org.apache.brooklyn.entity.nosql.mongodb;
 
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -26,7 +27,6 @@ import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.AttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 public interface AbstractMongoDBServer extends SoftwareProcess, Entity {
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 3dbe34e..3bc3a88 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
@@ -28,10 +28,9 @@ import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.MethodEffector;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.nosql.mongodb.sharding.MongoDBShardedDeployment;
 
-import brooklyn.util.flags.SetFromFlag;
-
 import com.google.common.reflect.TypeToken;
 
 @ImplementedBy(MongoDBClientImpl.class)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 2ebd8bb..a19bd1e 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
@@ -23,13 +23,13 @@ import java.util.List;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.group.Cluster;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 f45070a..0ef0274 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
@@ -23,13 +23,13 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.event.AttributeSensor.SensorPersistenceMode;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 @Catalog(name="MongoDB Server",
     description="MongoDB (from \"humongous\") is a scalable, high-performance, open source NoSQL database",

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 b9a088b..a458ec7 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
@@ -24,12 +24,12 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SameServerEntity;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 ba8fc10..3bab3b8 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
@@ -24,6 +24,7 @@ import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.nosql.mongodb.MongoDBReplicaSet;
 import org.apache.brooklyn.entity.nosql.mongodb.MongoDBServer;
 
@@ -31,7 +32,6 @@ import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisSlave.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisSlave.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisSlave.java
index 3688057..84bfe0e 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisSlave.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/redis/RedisSlave.java
@@ -19,10 +19,10 @@
 package org.apache.brooklyn.entity.nosql.redis;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * A {@link RedisStore} configured as a slave.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 a1a6749..2673426 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
@@ -21,6 +21,7 @@ package org.apache.brooklyn.entity.nosql.redis;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
@@ -28,7 +29,6 @@ import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * An entity that represents a Redis key-value store service.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 e1ee7b5..b657267 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
@@ -25,13 +25,13 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.time.Duration;
 
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 4e72bae..7197787 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
@@ -30,6 +30,7 @@ import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.policy.EnricherSpec;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -45,7 +46,6 @@ import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import brooklyn.entity.group.DynamicClusterImpl;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.DependentConfiguration;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 502aa91..7519709 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
@@ -24,6 +24,7 @@ import java.util.List;
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.Effector;
@@ -36,7 +37,6 @@ import brooklyn.entity.java.UsesJava;
 import brooklyn.event.basic.AttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 587ffe3..6d0cd81 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
@@ -29,6 +29,7 @@ import javax.annotation.Nullable;
 
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.core.util.config.ConfigBag;
 import org.apache.brooklyn.entity.webapp.WebAppServiceMethods;
 
 import brooklyn.enricher.Enrichers;
@@ -43,7 +44,6 @@ import org.apache.brooklyn.location.access.BrooklynAccessUtils;
 import org.apache.brooklyn.location.cloud.CloudLocationConfig;
 
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.config.ConfigBag;
 import brooklyn.util.guava.Functionals;
 import brooklyn.util.time.Duration;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 f115ab3..cbeff70 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
@@ -47,14 +47,14 @@ import brooklyn.entity.basic.lifecycle.ScriptHelper;
 import brooklyn.entity.software.SshEffectorTasks;
 
 import org.apache.brooklyn.api.location.OsDetails;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.ssh.SshTasks;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Joiner;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 f813ced..a81a1da 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
@@ -22,6 +22,7 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.BrooklynConfigKeys;
@@ -32,8 +33,9 @@ import brooklyn.entity.java.UsesJavaMXBeans;
 import brooklyn.entity.java.UsesJmx;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
+
 import org.apache.brooklyn.location.basic.PortRanges;
-import brooklyn.util.flags.SetFromFlag;
+
 import brooklyn.util.time.Duration;
 
 import com.google.common.collect.Maps;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServerSshDriver.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServerSshDriver.java b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServerSshDriver.java
index 5f7335a..b66c06f 100644
--- a/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServerSshDriver.java
+++ b/software/nosql/src/main/java/org/apache/brooklyn/entity/nosql/solr/SolrServerSshDriver.java
@@ -33,10 +33,10 @@ import org.slf4j.LoggerFactory;
 import brooklyn.entity.basic.Entities;
 
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.file.ArchiveUtils;
 import org.apache.brooklyn.location.basic.SshMachineLocation;
 
 import brooklyn.util.collections.MutableMap;
-import brooklyn.util.file.ArchiveUtils;
 import brooklyn.util.net.Networking;
 import brooklyn.util.net.Urls;
 import brooklyn.util.os.Os;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterTest.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterTest.java b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterTest.java
index 1841cf7..4a78aaa 100644
--- a/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterTest.java
+++ b/software/nosql/src/test/java/org/apache/brooklyn/entity/nosql/cassandra/CassandraDatacenterTest.java
@@ -27,6 +27,8 @@ import java.util.Set;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,9 +44,7 @@ import brooklyn.entity.basic.EntityInternal;
 
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.javalang.JavaClassNames;
-import brooklyn.util.text.TemplateProcessor;
 import brooklyn.util.time.Duration;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 8e695c9..bad63b0 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
@@ -27,6 +27,8 @@ import java.net.URISyntaxException;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.http.client.methods.HttpGet;
 import org.bouncycastle.util.Strings;
@@ -41,8 +43,6 @@ import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.test.Asserts;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 8d5f0d1..5e9b5cb 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
@@ -25,6 +25,8 @@ import java.net.URISyntaxException;
 
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.test.EntityTestUtils;
 import org.apache.brooklyn.test.entity.TestApplication;
 import org.apache.http.client.methods.HttpGet;
@@ -41,9 +43,6 @@ import brooklyn.event.feed.http.HttpValueFunctions;
 
 import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
-
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 6f0bd72..b708e95 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
@@ -23,6 +23,7 @@ import java.util.Map;
 
 import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.Effector;
@@ -36,7 +37,6 @@ import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.MapConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * This sets up a Karaf OSGi container

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsServiceImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsServiceImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsServiceImpl.java
index 790aece..5b54f38 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsServiceImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/AbstractGeoDnsServiceImpl.java
@@ -36,6 +36,7 @@ import java.util.Set;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.webapp.WebAppService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,7 +53,6 @@ import org.apache.brooklyn.location.geo.HostGeoInfo;
 
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.net.Networking;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 f98314c..b9b8a1f 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
@@ -22,6 +22,7 @@ import java.net.URI;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.dns.AbstractGeoDnsService;
 import org.apache.brooklyn.entity.webapp.WebAppServiceConstants;
 
@@ -30,7 +31,6 @@ import brooklyn.entity.basic.Attributes;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 @ImplementedBy(GeoscalingDnsServiceImpl.class)
 public interface GeoscalingDnsService extends AbstractGeoDnsService {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingDnsServiceImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingDnsServiceImpl.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingDnsServiceImpl.java
index c71c00a..48a01f0 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingDnsServiceImpl.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingDnsServiceImpl.java
@@ -25,6 +25,7 @@ import java.net.URI;
 import java.util.Collection;
 import java.util.Set;
 
+import org.apache.brooklyn.core.util.http.HttpTool;
 import org.apache.brooklyn.entity.dns.AbstractGeoDnsServiceImpl;
 import org.apache.brooklyn.entity.dns.geoscaling.GeoscalingWebClient.Domain;
 import org.apache.brooklyn.entity.dns.geoscaling.GeoscalingWebClient.SmartSubdomain;
@@ -33,9 +34,10 @@ import org.slf4j.LoggerFactory;
 
 import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.basic.ServiceStateLogic;
+
 import org.apache.brooklyn.location.geo.HostGeoInfo;
+
 import brooklyn.util.collections.MutableSet;
-import brooklyn.util.http.HttpTool;
 import brooklyn.util.text.Identifiers;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingScriptGenerator.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingScriptGenerator.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingScriptGenerator.java
index e8def56..5c1e578 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingScriptGenerator.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingScriptGenerator.java
@@ -24,8 +24,9 @@ import java.util.Date;
 import java.util.Iterator;
 import java.util.TimeZone;
 
+import org.apache.brooklyn.core.util.ResourceUtils;
 import org.apache.brooklyn.location.geo.HostGeoInfo;
-import brooklyn.util.ResourceUtils;
+
 import brooklyn.util.javalang.JavaClassNames;
 import brooklyn.util.os.Os;
 import brooklyn.util.text.Strings;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingWebClient.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingWebClient.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingWebClient.java
index 7e5c3aa..afaac72 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingWebClient.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/dns/geoscaling/GeoscalingWebClient.java
@@ -28,6 +28,7 @@ import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.brooklyn.core.util.http.HttpTool;
 import org.apache.commons.io.FilenameUtils;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
@@ -48,7 +49,6 @@ import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.w3c.tidy.Tidy;
 
-import brooklyn.util.http.HttpTool;
 import brooklyn.util.text.Strings;
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 ca8caa3..de8955d 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
@@ -22,13 +22,13 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.group.Cluster;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * Represents a controller mechanism for a {@link Cluster}.

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 5eeeee9..a61da01 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
@@ -33,6 +33,7 @@ import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.policy.Policy;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -52,7 +53,6 @@ import org.apache.brooklyn.location.basic.Machines;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.guava.Maybe;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.text.Strings;
 
 import com.google.common.base.Objects;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 2af3da2..b3d32c0 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
@@ -24,6 +24,7 @@ import java.util.Map;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.webapp.WebAppService;
 
 import brooklyn.config.ConfigKey;
@@ -35,7 +36,6 @@ import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.BasicConfigKey;
 import brooklyn.event.basic.PortAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.reflect.TypeToken;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/ProxySslConfig.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/ProxySslConfig.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/ProxySslConfig.java
index 93e1b7f..ad6bf82 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/ProxySslConfig.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/ProxySslConfig.java
@@ -21,12 +21,11 @@ package org.apache.brooklyn.entity.proxy;
 import java.io.Serializable;
 import java.util.Map;
 
+import org.apache.brooklyn.core.util.flags.FlagUtils;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import brooklyn.util.flags.FlagUtils;
-import brooklyn.util.flags.SetFromFlag;
-
 import com.google.common.base.Objects;
 
 public class ProxySslConfig implements Serializable {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 de20631..1ae0ea8 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
@@ -24,6 +24,7 @@ import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.entity.trait.HasShortName;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.proxy.AbstractController;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
 
@@ -35,7 +36,6 @@ import brooklyn.entity.basic.MethodEffector;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.collect.ImmutableMap;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 3d65881..bd3840d 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
@@ -31,6 +31,10 @@ import org.apache.brooklyn.api.event.SensorEvent;
 import org.apache.brooklyn.api.event.SensorEventListener;
 import org.apache.brooklyn.api.management.SubscriptionHandle;
 import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.file.ArchiveUtils;
+import org.apache.brooklyn.core.util.http.HttpTool;
+import org.apache.brooklyn.core.util.http.HttpToolResponse;
 import org.apache.brooklyn.entity.proxy.AbstractControllerImpl;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
 import org.apache.brooklyn.entity.proxy.nginx.NginxController.NginxControllerInternal;
@@ -47,11 +51,7 @@ import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
-import brooklyn.util.ResourceUtils;
-import brooklyn.util.file.ArchiveUtils;
 import brooklyn.util.guava.Functionals;
-import brooklyn.util.http.HttpTool;
-import brooklyn.util.http.HttpToolResponse;
 import brooklyn.util.stream.Streams;
 import brooklyn.util.text.Strings;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxSshDriver.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxSshDriver.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxSshDriver.java
index da9bbf9..56d3dc6 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxSshDriver.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxSshDriver.java
@@ -27,6 +27,10 @@ import org.apache.brooklyn.api.entity.drivers.downloads.DownloadResolver;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.OsDetails;
 import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks;
+import org.apache.brooklyn.core.util.task.ssh.SshTasks.OnFailingTask;
 import org.apache.brooklyn.entity.proxy.AbstractController;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -46,10 +50,6 @@ import brooklyn.util.net.Networking;
 import brooklyn.util.os.Os;
 import brooklyn.util.ssh.BashCommands;
 import brooklyn.util.stream.Streams;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.ssh.SshTasks.OnFailingTask;
 import brooklyn.util.text.Strings;
 
 import com.google.common.collect.ImmutableList;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
index 34432dd7..3c079d6 100644
--- a/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
+++ b/software/webapp/src/main/java/org/apache/brooklyn/entity/proxy/nginx/NginxTemplateConfigGenerator.java
@@ -21,14 +21,14 @@ package org.apache.brooklyn.entity.proxy.nginx;
 import java.util.Collection;
 import java.util.Map;
 
+import org.apache.brooklyn.core.util.ResourceUtils;
+import org.apache.brooklyn.core.util.text.TemplateProcessor;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.text.Strings;
-import brooklyn.util.text.TemplateProcessor;
 
 import com.google.common.collect.LinkedHashMultimap;
 import com.google.common.collect.Multimap;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 ac937ee..59ec8bb 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
@@ -23,6 +23,7 @@ import java.util.Collection;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.proxy.AbstractController;
 import org.apache.brooklyn.entity.proxy.ProxySslConfig;
 
@@ -32,7 +33,6 @@ import brooklyn.entity.basic.AbstractGroup;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.MethodEffector;
 import brooklyn.event.basic.Sensors;
-import brooklyn.util.flags.SetFromFlag;
 
 import com.google.common.reflect.TypeToken;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 8315e17..58e206c 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
@@ -24,6 +24,7 @@ import org.apache.brooklyn.api.entity.Group;
 import org.apache.brooklyn.api.entity.proxying.EntitySpec;
 import org.apache.brooklyn.api.entity.proxying.ImplementedBy;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 import org.apache.brooklyn.entity.proxy.LoadBalancer;
 
 import brooklyn.config.ConfigKey;
@@ -39,7 +40,6 @@ import brooklyn.entity.trait.Resizable;
 import brooklyn.entity.trait.Startable;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicAttributeSensorAndConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 /**
  * This entity contains the sub-groups and entities that go in to a single location (e.g. datacenter)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 1c87941..5fe07ac 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,6 +29,10 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
 import org.apache.brooklyn.api.management.Task;
 import org.apache.brooklyn.api.management.TaskAdaptable;
+import org.apache.brooklyn.core.util.task.DynamicTasks;
+import org.apache.brooklyn.core.util.task.TaskBuilder;
+import org.apache.brooklyn.core.util.task.TaskTags;
+import org.apache.brooklyn.core.util.task.Tasks;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,10 +46,6 @@ import brooklyn.entity.group.DynamicClusterImpl;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.collections.MutableSet;
 import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.task.DynamicTasks;
-import brooklyn.util.task.TaskBuilder;
-import brooklyn.util.task.TaskTags;
-import brooklyn.util.task.Tasks;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/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 d863b19..b5e1c48 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
@@ -24,6 +24,7 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.core.util.flags.SetFromFlag;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.annotation.Effector;
@@ -32,7 +33,6 @@ import brooklyn.entity.basic.MethodEffector;
 import brooklyn.entity.java.UsesJava;
 import brooklyn.event.basic.BasicAttributeSensor;
 import brooklyn.event.basic.BasicConfigKey;
-import brooklyn.util.flags.SetFromFlag;
 
 public interface JavaWebAppService extends WebAppService, UsesJava {
 



[13/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java b/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java
deleted file mode 100644
index df0330a..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolAsyncStubIntegrationTest.java
+++ /dev/null
@@ -1,177 +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 brooklyn.util.internal.ssh.sshj;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.util.List;
-
-import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.internal.ssh.SshAbstractTool.SshAction;
-import brooklyn.util.internal.ssh.sshj.SshjTool.ShellAction;
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-/**
- * Tests for async-exec with {@link SshjTool}, where it stubs out the actual ssh commands
- * to return a controlled sequence of responses.
- */
-public class SshjToolAsyncStubIntegrationTest {
-
-    static class InjectedResult {
-        Predicate<SshjTool.ShellAction> expected;
-        Function<SshjTool.ShellAction, Integer> result;
-        
-        InjectedResult(Predicate<SshjTool.ShellAction> expected, Function<SshjTool.ShellAction, Integer> result) {
-            this.expected = expected;
-            this.result = result;
-        }
-    }
-    
-    private SshjTool tool;
-    private List<InjectedResult> sequence;
-    int counter = 0;
-    private boolean origFeatureEnablement;
-    
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
-        sequence = Lists.newArrayList();
-        counter = 0;
-        
-        tool = new SshjTool(ImmutableMap.<String,Object>of("host", "localhost")) {
-            @SuppressWarnings("unchecked")
-            protected <T, C extends SshAction<T>> T acquire(C action, int sshTries, Duration sshTriesTimeout) {
-                if (action instanceof SshjTool.ShellAction) {
-                    SshjTool.ShellAction shellAction = (SshjTool.ShellAction) action;
-                    InjectedResult injectedResult = sequence.get(counter);
-                    assertTrue(injectedResult.expected.apply(shellAction), "counter="+counter+"; cmds="+shellAction.commands);
-                    counter++;
-                    return (T) injectedResult.result.apply(shellAction);
-                }
-                return super.acquire(action, sshTries, sshTriesTimeout);
-            }
-        };
-    }
-
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        try {
-            if (tool != null) tool.disconnect();
-        } finally {
-            BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
-        }
-    }
-    
-    private Predicate<SshjTool.ShellAction> containsCmd(final String cmd) {
-        return new Predicate<SshjTool.ShellAction>() {
-            @Override public boolean apply(ShellAction input) {
-                return input != null && input.commands.toString().contains(cmd);
-            }
-        };
-    }
-    
-    private Function<SshjTool.ShellAction, Integer> returning(final int result, final String stdout, final String stderr) {
-        return new Function<SshjTool.ShellAction, Integer>() {
-            @Override public Integer apply(ShellAction input) {
-                try {
-                    if (stdout != null && input.out != null) input.out.write(stdout.getBytes());
-                    if (stderr != null && input.err != null) input.err.write(stderr.getBytes());
-                } catch (IOException e) {
-                    throw Exceptions.propagate(e);
-                }
-                return result;
-            }
-        };
-    }
-    
-    @Test(groups="Integration")
-    public void testPolls() throws Exception {
-        sequence = ImmutableList.of(
-                new InjectedResult(containsCmd("nohup"), returning(0, "", "")),
-                new InjectedResult(containsCmd("# Long poll"), returning(0, "mystringToStdout", "mystringToStderr")));
-
-        runTest(0, "mystringToStdout", "mystringToStderr");
-        assertEquals(counter, sequence.size());
-    }
-    
-    @Test(groups="Integration")
-    public void testPollsAndReturnsNonZeroExitCode() throws Exception {
-        sequence = ImmutableList.of(
-                new InjectedResult(containsCmd("nohup"), returning(0, "", "")),
-                new InjectedResult(containsCmd("# Long poll"), returning(123, "mystringToStdout", "mystringToStderr")),
-                new InjectedResult(containsCmd("# Retrieve status"), returning(0, "123", "")));
-
-        runTest(123, "mystringToStdout", "mystringToStderr");
-        assertEquals(counter, sequence.size());
-    }
-    
-    @Test(groups="Integration")
-    public void testPollsRepeatedly() throws Exception {
-        sequence = ImmutableList.of(
-                new InjectedResult(containsCmd("nohup"), returning(0, "", "")),
-                new InjectedResult(containsCmd("# Long poll"), returning(125, "mystringToStdout", "mystringToStderr")),
-                new InjectedResult(containsCmd("# Retrieve status"), returning(0, "", "")),
-                new InjectedResult(containsCmd("# Long poll"), returning(125, "mystringToStdout2", "mystringToStderr2")),
-                new InjectedResult(containsCmd("# Retrieve status"), returning(0, "", "")),
-                new InjectedResult(containsCmd("# Long poll"), returning(-1, "mystringToStdout3", "mystringToStderr3")),
-                new InjectedResult(containsCmd("# Long poll"), returning(125, "mystringToStdout4", "mystringToStderr4")),
-                new InjectedResult(containsCmd("# Retrieve status"), returning(0, "", "")),
-                new InjectedResult(containsCmd("# Long poll"), returning(0, "mystringToStdout5", "mystringToStderr5")));
-
-        runTest(0,
-                "mystringToStdout"+"mystringToStdout2"+"mystringToStdout3"+"mystringToStdout4"+"mystringToStdout5",
-                "mystringToStderr"+"mystringToStderr2"+"mystringToStderr3"+"mystringToStderr4"+"mystringToStderr5");
-        assertEquals(counter, sequence.size());
-    }
-    
-    protected void runTest(int expectedExit, String expectedStdout, String expectedStderr) throws Exception {
-        List<String> cmds = ImmutableList.of("abc");
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        ByteArrayOutputStream err = new ByteArrayOutputStream();
-        int exitCode = tool.execScript(
-                ImmutableMap.of(
-                        "out", out, 
-                        "err", err, 
-                        SshjTool.PROP_EXEC_ASYNC.getName(), true, 
-                        SshjTool.PROP_NO_EXTRA_OUTPUT.getName(), true,
-                        SshjTool.PROP_EXEC_ASYNC_POLLING_TIMEOUT.getName(), Duration.ONE_MILLISECOND), 
-                cmds, 
-                ImmutableMap.<String,String>of());
-        String outStr = new String(out.toByteArray());
-        String errStr = new String(err.toByteArray());
-
-        assertEquals(exitCode, expectedExit);
-        assertEquals(outStr.trim(), expectedStdout);
-        assertEquals(errStr.trim(), expectedStderr);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolIntegrationTest.java b/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolIntegrationTest.java
deleted file mode 100644
index f1e354c..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolIntegrationTest.java
+++ /dev/null
@@ -1,313 +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 brooklyn.util.internal.ssh.sshj;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-import net.schmizz.sshj.connection.channel.direct.Session;
-
-import org.apache.brooklyn.core.internal.BrooklynFeatureEnablement;
-import org.testng.annotations.Test;
-
-import brooklyn.test.Asserts;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.exceptions.RuntimeTimeoutException;
-import brooklyn.util.internal.ssh.SshException;
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.internal.ssh.SshToolAbstractIntegrationTest;
-import brooklyn.util.os.Os;
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-/**
- * Test the operation of the {@link SshJschTool} utility class.
- */
-public class SshjToolIntegrationTest extends SshToolAbstractIntegrationTest {
-
-    @Override
-    protected SshTool newUnregisteredTool(Map<String,?> flags) {
-        return new SshjTool(flags);
-    }
-
-    // TODO requires vt100 terminal emulation to work?
-    @Test(enabled = false, groups = {"Integration"})
-    public void testExecShellWithCommandTakingStdin() throws Exception {
-        // Uses `tee` to redirect stdin to the given file; cntr-d (i.e. char 4) stops tee with exit code 0
-        String content = "blah blah";
-        String out = execShellDirectWithTerminalEmulation("tee "+remoteFilePath, content, ""+(char)4, "echo file contents: `cat "+remoteFilePath+"`");
-
-        assertTrue(out.contains("file contents: blah blah"), "out="+out);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testGivesUpAfterMaxRetries() throws Exception {
-        final AtomicInteger callCount = new AtomicInteger();
-        
-        final SshTool localtool = new SshjTool(ImmutableMap.of("sshTries", 3, "host", "localhost", "privateKeyFile", "~/.ssh/id_rsa")) {
-            protected SshAction<Session> newSessionAction() {
-                callCount.incrementAndGet();
-                throw new RuntimeException("Simulating ssh execution failure");
-            }
-        };
-        
-        tools.add(localtool);
-        try {
-            localtool.execScript(ImmutableMap.<String,Object>of(), ImmutableList.of("true"));
-            fail();
-        } catch (SshException e) {
-            if (!e.toString().contains("out of retries")) throw e;
-            assertEquals(callCount.get(), 3);
-        }
-    }
-
-    @Test(groups = {"Integration"})
-    public void testReturnsOnSuccessWhenRetrying() throws Exception {
-        final AtomicInteger callCount = new AtomicInteger();
-        final int successOnAttempt = 2;
-        final SshTool localtool = new SshjTool(ImmutableMap.of("sshTries", 3, "host", "localhost", "privateKeyFile", "~/.ssh/id_rsa")) {
-            protected SshAction<Session> newSessionAction() {
-                callCount.incrementAndGet();
-                if (callCount.incrementAndGet() >= successOnAttempt) {
-                    return super.newSessionAction();
-                } else {
-                    throw new RuntimeException("Simulating ssh execution failure");
-                }
-            }
-        };
-        
-        tools.add(localtool);
-        localtool.execScript(ImmutableMap.<String,Object>of(), ImmutableList.of("true"));
-        assertEquals(callCount.get(), successOnAttempt);
-    }
-
-    @Test(groups = {"Integration"})
-    public void testGivesUpAfterMaxTime() throws Exception {
-        final AtomicInteger callCount = new AtomicInteger();
-        final SshTool localtool = new SshjTool(ImmutableMap.of("sshTriesTimeout", 1000, "host", "localhost", "privateKeyFile", "~/.ssh/id_rsa")) {
-            protected SshAction<Session> newSessionAction() {
-                callCount.incrementAndGet();
-                try {
-                    Thread.sleep(600);
-                } catch (InterruptedException e) {
-                    throw Exceptions.propagate(e);
-                }
-                throw new RuntimeException("Simulating ssh execution failure");
-            }
-        };
-        
-        tools.add(localtool);
-        try {
-            localtool.execScript(ImmutableMap.<String,Object>of(), ImmutableList.of("true"));
-            fail();
-        } catch (RuntimeTimeoutException e) {
-            if (!e.toString().contains("out of time")) throw e;
-            assertEquals(callCount.get(), 2);
-        }
-    }
-    
-    @Test(groups = {"Integration"})
-    public void testUsesCustomLocalTempDir() throws Exception {
-        class SshjToolForTest extends SshjTool {
-            public SshjToolForTest(Map<String, ?> map) {
-                super(map);
-            }
-            public File getLocalTempDir() {
-                return localTempDir;
-            }
-        };
-        
-        final SshjToolForTest localtool = new SshjToolForTest(ImmutableMap.<String, Object>of("host", "localhost"));
-        assertNotNull(localtool.getLocalTempDir());
-        assertEquals(localtool.getLocalTempDir(), new File(Os.tidyPath(SshjTool.PROP_LOCAL_TEMP_DIR.getDefaultValue())));
-        
-        String customTempDir = Os.tmp();
-        final SshjToolForTest localtool2 = new SshjToolForTest(ImmutableMap.of(
-                "host", "localhost", 
-                SshjTool.PROP_LOCAL_TEMP_DIR.getName(), customTempDir));
-        assertEquals(localtool2.getLocalTempDir(), new File(customTempDir));
-        
-        String customRelativeTempDir = "~/tmp";
-        final SshjToolForTest localtool3 = new SshjToolForTest(ImmutableMap.of(
-                "host", "localhost", 
-                SshjTool.PROP_LOCAL_TEMP_DIR.getName(), customRelativeTempDir));
-        assertEquals(localtool3.getLocalTempDir(), new File(Os.tidyPath(customRelativeTempDir)));
-    }
-
-    @Test(groups = {"Integration"})
-    public void testAsyncExecStdoutAndStderr() throws Exception {
-        boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
-        try {
-            // Include a sleep, to ensure that the contents retrieved in first poll and subsequent polls are appended
-            List<String> cmds = ImmutableList.of(
-                    "echo mystringToStdout",
-                    "echo mystringToStderr 1>&2",
-                    "sleep 5",
-                    "echo mystringPostSleepToStdout",
-                    "echo mystringPostSleepToStderr 1>&2");
-            
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            ByteArrayOutputStream err = new ByteArrayOutputStream();
-            int exitCode = tool.execScript(
-                    ImmutableMap.of(
-                            "out", out, 
-                            "err", err, 
-                            SshjTool.PROP_EXEC_ASYNC.getName(), true, 
-                            SshjTool.PROP_NO_EXTRA_OUTPUT.getName(), true,
-                            SshjTool.PROP_EXEC_ASYNC_POLLING_TIMEOUT.getName(), Duration.ONE_SECOND), 
-                    cmds, 
-                    ImmutableMap.<String,String>of());
-            String outStr = new String(out.toByteArray());
-            String errStr = new String(err.toByteArray());
-    
-            assertEquals(exitCode, 0);
-            assertEquals(outStr.trim(), "mystringToStdout\nmystringPostSleepToStdout");
-            assertEquals(errStr.trim(), "mystringToStderr\nmystringPostSleepToStderr");
-        } finally {
-            BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
-        }
-    }
-
-    @Test(groups = {"Integration"})
-    public void testAsyncExecReturnsExitCode() throws Exception {
-        boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
-        try {
-            int exitCode = tool.execScript(
-                    ImmutableMap.of(SshjTool.PROP_EXEC_ASYNC.getName(), true), 
-                    ImmutableList.of("exit 123"), 
-                    ImmutableMap.<String,String>of());
-            assertEquals(exitCode, 123);
-        } finally {
-            BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
-        }
-    }
-
-    @Test(groups = {"Integration"})
-    public void testAsyncExecTimesOut() throws Exception {
-        Stopwatch stopwatch = Stopwatch.createStarted();
-        boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
-        try {
-            tool.execScript(
-                ImmutableMap.of(SshjTool.PROP_EXEC_ASYNC.getName(), true, SshjTool.PROP_EXEC_TIMEOUT.getName(), Duration.millis(1)), 
-                ImmutableList.of("sleep 60"), 
-                ImmutableMap.<String,String>of());
-            fail();
-        } catch (Exception e) {
-            TimeoutException te = Exceptions.getFirstThrowableOfType(e, TimeoutException.class);
-            if (te == null) throw e;
-        } finally {
-            BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
-        }
-        
-        long seconds = stopwatch.elapsed(TimeUnit.SECONDS);
-        assertTrue(seconds < 30, "exec took "+seconds+" seconds");
-    }
-
-    @Test(groups = {"Integration"})
-    public void testAsyncExecAbortsIfProcessFails() throws Exception {
-        final AtomicReference<Throwable> error = new AtomicReference<Throwable>();
-        Thread thread = new Thread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Stopwatch stopwatch = Stopwatch.createStarted();
-                    int exitStatus = tool.execScript(
-                        ImmutableMap.of(SshjTool.PROP_EXEC_ASYNC.getName(), true, SshjTool.PROP_EXEC_TIMEOUT.getName(), Duration.millis(1)), 
-                        ImmutableList.of("sleep 63"), 
-                        ImmutableMap.<String,String>of());
-                    
-                    assertEquals(exitStatus, 143 /* 128 + Signal number (SIGTERM) */);
-                    
-                    long seconds = stopwatch.elapsed(TimeUnit.SECONDS);
-                    assertTrue(seconds < 30, "exec took "+seconds+" seconds");
-                } catch (Throwable t) {
-                    error.set(t);
-                }
-            }});
-        
-        boolean origFeatureEnablement = BrooklynFeatureEnablement.enable(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC);
-        try {
-            thread.start();
-            
-            Asserts.succeedsEventually(new Runnable() {
-                @Override
-                public void run() {
-                    int exitStatus = tool.execCommands(ImmutableMap.<String,Object>of(), ImmutableList.of("ps aux| grep \"sleep 63\" | grep -v grep"));
-                    assertEquals(exitStatus, 0);
-                }});
-            
-            tool.execCommands(ImmutableMap.<String,Object>of(), ImmutableList.of("ps aux| grep \"sleep 63\" | grep -v grep | awk '{print($2)}' | xargs kill"));
-            
-            thread.join(30*1000);
-            assertFalse(thread.isAlive());
-            if (error.get() != null) {
-                throw Exceptions.propagate(error.get());
-            }
-        } finally {
-            thread.interrupt();
-            BrooklynFeatureEnablement.setEnablement(BrooklynFeatureEnablement.FEATURE_SSH_ASYNC_EXEC, origFeatureEnablement);
-        }
-    }
-
-    
-    protected String execShellDirect(List<String> cmds) {
-        return execShellDirect(cmds, ImmutableMap.<String,Object>of());
-    }
-    
-    protected String execShellDirect(List<String> cmds, Map<String,?> env) {
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        int exitcode = ((SshjTool)tool).execShellDirect(ImmutableMap.of("out", out), cmds, env);
-        String outstr = new String(out.toByteArray());
-        assertEquals(exitcode, 0, outstr);
-        return outstr;
-    }
-
-    private String execShellDirectWithTerminalEmulation(String... cmds) {
-        return execShellDirectWithTerminalEmulation(Arrays.asList(cmds));
-    }
-    
-    private String execShellDirectWithTerminalEmulation(List<String> cmds) {
-        return execShellDirectWithTerminalEmulation(cmds, ImmutableMap.<String,Object>of());
-    }
-    
-    private String execShellDirectWithTerminalEmulation(List<String> cmds, Map<String,?> env) {
-        ByteArrayOutputStream out = new ByteArrayOutputStream();
-        int exitcode = ((SshjTool)tool).execShellDirect(ImmutableMap.of("allocatePTY", true, "out", out), cmds, env);
-        String outstr = new String(out.toByteArray());
-        assertEquals(exitcode, 0, outstr);
-        return outstr;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolPerformanceTest.java b/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolPerformanceTest.java
deleted file mode 100644
index 0c79bf1..0000000
--- a/core/src/test/java/brooklyn/util/internal/ssh/sshj/SshjToolPerformanceTest.java
+++ /dev/null
@@ -1,44 +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 brooklyn.util.internal.ssh.sshj;
-
-import java.util.Map;
-
-import org.testng.annotations.Test;
-
-import brooklyn.util.internal.ssh.SshTool;
-import brooklyn.util.internal.ssh.SshToolAbstractPerformanceTest;
-
-/**
- * Test the performance of different variants of invoking the sshj tool.
- * 
- * Intended for human-invocation and inspection, to see which parts are most expensive.
- */
-public class SshjToolPerformanceTest extends SshToolAbstractPerformanceTest {
-
-    @Override
-    protected SshTool newSshTool(Map<String,?> flags) {
-        return new SshjTool(flags);
-    }
-    
-    // Need to have at least one test method here (rather than just inherited) for eclipse to recognize it
-    @Test(enabled = false)
-    public void testDummy() throws Exception {
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/mutex/WithMutexesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/mutex/WithMutexesTest.java b/core/src/test/java/brooklyn/util/mutex/WithMutexesTest.java
deleted file mode 100644
index cde25d3..0000000
--- a/core/src/test/java/brooklyn/util/mutex/WithMutexesTest.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 brooklyn.util.mutex;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
-
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-public class WithMutexesTest {
-
-    @Test
-    public void testOneAcquisitionAndRelease() throws InterruptedException {
-        MutexSupport m = new MutexSupport();
-        Map<String, SemaphoreWithOwners> sems;
-        SemaphoreWithOwners s;
-        try {
-            m.acquireMutex("foo", "something foo");
-            sems = m.getAllSemaphores();
-            Assert.assertEquals(sems.size(), 1);
-            s = sems.get("foo");
-            Assert.assertEquals(s.getDescription(), "something foo");
-            Assert.assertEquals(s.getOwningThreads(), Arrays.asList(Thread.currentThread()));
-            Assert.assertEquals(s.getRequestingThreads(), Collections.emptyList());
-            Assert.assertTrue(s.isInUse());
-            Assert.assertTrue(s.isCallingThreadAnOwner());
-        } finally {
-            m.releaseMutex("foo");
-        }
-        Assert.assertFalse(s.isInUse());
-        Assert.assertFalse(s.isCallingThreadAnOwner());
-        Assert.assertEquals(s.getDescription(), "something foo");
-        Assert.assertEquals(s.getOwningThreads(), Collections.emptyList());
-        Assert.assertEquals(s.getRequestingThreads(), Collections.emptyList());
-        
-        sems = m.getAllSemaphores();
-        Assert.assertEquals(sems, Collections.emptyMap());
-    }
-
-    @Test(groups = "Integration")  //just because it takes a wee while
-    public void testBlockingAcquisition() throws InterruptedException {
-        final MutexSupport m = new MutexSupport();
-        m.acquireMutex("foo", "something foo");
-        
-        Assert.assertFalse(m.tryAcquireMutex("foo", "something else"));
-
-        Thread t = new Thread() {
-            public void run() {
-                try {
-                    m.acquireMutex("foo", "thread 2 foo");
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
-                m.releaseMutex("foo");
-            }
-        };
-        t.start();
-        
-        t.join(500);
-        Assert.assertTrue(t.isAlive());
-        Assert.assertEquals(m.getSemaphore("foo").getRequestingThreads(), Arrays.asList(t));
-
-        m.releaseMutex("foo");
-        
-        t.join(1000);
-        Assert.assertFalse(t.isAlive());
-
-        Assert.assertEquals(m.getAllSemaphores(), Collections.emptyMap());
-    }
-
-    
-    public static class SampleWithMutexesDelegatingMixin implements WithMutexes {
-        
-        /* other behaviour would typically go here... */
-        
-        WithMutexes mutexSupport = new MutexSupport();
-        
-        @Override
-        public void acquireMutex(String mutexId, String description) throws InterruptedException {
-            mutexSupport.acquireMutex(mutexId, description);
-        }
-
-        @Override
-        public boolean tryAcquireMutex(String mutexId, String description) {
-            return mutexSupport.tryAcquireMutex(mutexId, description);
-        }
-
-        @Override
-        public void releaseMutex(String mutexId) {
-            mutexSupport.releaseMutex(mutexId);
-        }
-
-        @Override
-        public boolean hasMutex(String mutexId) {
-            return mutexSupport.hasMutex(mutexId);
-        }
-    }
-    
-    @Test
-    public void testDelegatingMixinPattern() throws InterruptedException {
-        WithMutexes m = new SampleWithMutexesDelegatingMixin();
-        m.acquireMutex("foo", "sample");
-        Assert.assertTrue(m.hasMutex("foo"));
-        Assert.assertFalse(m.hasMutex("bar"));
-        m.releaseMutex("foo");
-        Assert.assertFalse(m.hasMutex("foo"));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/osgi/OsgisTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/osgi/OsgisTest.java b/core/src/test/java/brooklyn/util/osgi/OsgisTest.java
deleted file mode 100644
index 49f8017..0000000
--- a/core/src/test/java/brooklyn/util/osgi/OsgisTest.java
+++ /dev/null
@@ -1,41 +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 brooklyn.util.osgi;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-
-import org.osgi.framework.Version;
-import org.testng.annotations.Test;
-
-import brooklyn.util.osgi.Osgis.VersionedName;
-
-public class OsgisTest {
-
-    @Test
-    public void testParseOsgiIdentifier() throws Exception {
-        assertEquals(Osgis.parseOsgiIdentifier("a.b").get(), new VersionedName("a.b", null));
-        assertEquals(Osgis.parseOsgiIdentifier("a.b:0.1.2").get(), new VersionedName("a.b", Version.parseVersion("0.1.2")));
-        assertEquals(Osgis.parseOsgiIdentifier("a.b:0.0.0.SNAPSHOT").get(), new VersionedName("a.b", Version.parseVersion("0.0.0.SNAPSHOT")));
-        assertFalse(Osgis.parseOsgiIdentifier("a.b:0.notanumber.2").isPresent()); // invalid version
-        assertFalse(Osgis.parseOsgiIdentifier("a.b:0.1.2:3.4.5").isPresent());    // too many colons
-        assertFalse(Osgis.parseOsgiIdentifier("a.b:0.0.0_SNAPSHOT").isPresent()); // invalid version
-        assertFalse(Osgis.parseOsgiIdentifier("").isPresent());
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/ssh/BashCommandsIntegrationTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/ssh/BashCommandsIntegrationTest.java b/core/src/test/java/brooklyn/util/ssh/BashCommandsIntegrationTest.java
deleted file mode 100644
index accac56..0000000
--- a/core/src/test/java/brooklyn/util/ssh/BashCommandsIntegrationTest.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 brooklyn.util.ssh;
-
-import static brooklyn.util.ssh.BashCommands.sudo;
-import static java.lang.String.format;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotEquals;
-import static org.testng.Assert.assertTrue;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.apache.brooklyn.test.entity.LocalManagementContextForTests;
-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 brooklyn.entity.basic.Entities;
-import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.javalang.JavaClassNames;
-import brooklyn.util.net.Networking;
-import brooklyn.util.os.Os;
-import brooklyn.util.task.BasicExecutionContext;
-import brooklyn.util.task.ssh.SshTasks;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-import brooklyn.util.text.Identifiers;
-import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.io.Files;
-
-public class BashCommandsIntegrationTest {
-
-    private static final Logger log = LoggerFactory.getLogger(BashCommandsIntegrationTest.class);
-    
-    private ManagementContext mgmt;
-    private BasicExecutionContext exec;
-    
-    private File destFile;
-    private File sourceNonExistantFile;
-    private File sourceFile1;
-    private File sourceFile2;
-    private String sourceNonExistantFileUrl;
-    private String sourceFileUrl1;
-    private String sourceFileUrl2;
-    private SshMachineLocation loc;
-
-    private String localRepoFilename = "localrepofile.txt";
-    private File localRepoBasePath;
-    private File localRepoEntityBasePath;
-    private String localRepoEntityVersionPath;
-    private File localRepoEntityFile;
-    
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        mgmt = new LocalManagementContextForTests();
-        exec = new BasicExecutionContext(mgmt.getExecutionManager());
-        
-        destFile = Os.newTempFile(getClass(), "commoncommands-test-dest.txt");
-        
-        sourceNonExistantFile = new File("/this/does/not/exist/ERQBETJJIG1234");
-        sourceNonExistantFileUrl = sourceNonExistantFile.toURI().toString();
-        
-        sourceFile1 = Os.newTempFile(getClass(), "commoncommands-test.txt");
-        sourceFileUrl1 = sourceFile1.toURI().toString();
-        Files.write("mysource1".getBytes(), sourceFile1);
-        
-        sourceFile2 = Os.newTempFile(getClass(), "commoncommands-test2.txt");
-        sourceFileUrl2 = sourceFile2.toURI().toString();
-        Files.write("mysource2".getBytes(), sourceFile2);
-
-        localRepoEntityVersionPath = JavaClassNames.simpleClassName(this)+"-test-dest-"+Identifiers.makeRandomId(8);
-        localRepoBasePath = new File(format("%s/.brooklyn/repository", System.getProperty("user.home")));
-        localRepoEntityBasePath = new File(localRepoBasePath, localRepoEntityVersionPath);
-        localRepoEntityFile = new File(localRepoEntityBasePath, localRepoFilename);
-        localRepoEntityBasePath.mkdirs();
-        Files.write("mylocal1".getBytes(), localRepoEntityFile);
-
-        loc = mgmt.getLocationManager().createLocation(LocalhostMachineProvisioningLocation.spec()).obtain();
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (sourceFile1 != null) sourceFile1.delete();
-        if (sourceFile2 != null) sourceFile2.delete();
-        if (destFile != null) destFile.delete();
-        if (localRepoEntityFile != null) localRepoEntityFile.delete();
-        if (localRepoEntityBasePath != null) FileUtils.deleteDirectory(localRepoEntityBasePath);
-        if (loc != null) loc.close();
-        if (mgmt != null) Entities.destroyAll(mgmt);
-    }
-    
-    @Test(groups="Integration")
-    public void testSudo() throws Exception {
-        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
-        ByteArrayOutputStream errStream = new ByteArrayOutputStream();
-        String cmd = sudo("whoami");
-        int exitcode = loc.execCommands(ImmutableMap.of("out", outStream, "err", errStream), "test", ImmutableList.of(cmd));
-        String outstr = new String(outStream.toByteArray());
-        String errstr = new String(errStream.toByteArray());
-        
-        assertEquals(exitcode, 0, "out="+outstr+"; err="+errstr);
-        assertTrue(outstr.contains("root"), "out="+outstr+"; err="+errstr);
-    }
-    
-    public void testDownloadUrl() throws Exception {
-        List<String> cmds = BashCommands.commandsToDownloadUrlsAs(
-                ImmutableList.of(sourceFileUrl1), 
-                destFile.getAbsolutePath());
-        int exitcode = loc.execCommands("test", cmds);
-        
-        assertEquals(0, exitcode);
-        assertEquals(Files.readLines(destFile, Charsets.UTF_8), ImmutableList.of("mysource1"));
-    }
-    
-    @Test(groups="Integration")
-    public void testDownloadFirstSuccessfulFile() throws Exception {
-        List<String> cmds = BashCommands.commandsToDownloadUrlsAs(
-                ImmutableList.of(sourceNonExistantFileUrl, sourceFileUrl1, sourceFileUrl2), 
-                destFile.getAbsolutePath());
-        int exitcode = loc.execCommands("test", cmds);
-        
-        assertEquals(0, exitcode);
-        assertEquals(Files.readLines(destFile, Charsets.UTF_8), ImmutableList.of("mysource1"));
-    }
-    
-    @Test(groups="Integration")
-    public void testDownloadToStdout() throws Exception {
-        ProcessTaskWrapper<String> t = SshTasks.newSshExecTaskFactory(loc, 
-                "cd "+destFile.getParentFile().getAbsolutePath(),
-                BashCommands.downloadToStdout(Arrays.asList(sourceFileUrl1))+" | sed s/my/your/")
-            .requiringZeroAndReturningStdout().newTask();
-
-        String result = exec.submit(t).get();
-        assertTrue(result.trim().equals("yoursource1"), "Wrong contents of stdout download: "+result);
-    }
-
-    @Test(groups="Integration")
-    public void testAlternativesWhereFirstSucceeds() throws Exception {
-        ProcessTaskWrapper<Integer> t = SshTasks.newSshExecTaskFactory(loc)
-                .add(BashCommands.alternatives(Arrays.asList("echo first", "exit 88")))
-                .newTask();
-
-        Integer returnCode = exec.submit(t).get();
-        String stdout = t.getStdout();
-        String stderr = t.getStderr();
-        log.info("alternatives for good first command gave: "+returnCode+"; err="+stderr+"; out="+stdout);
-        assertTrue(stdout.contains("first"), "errcode="+returnCode+"; stdout="+stdout+"; stderr="+stderr);
-        assertEquals(returnCode, (Integer)0);
-    }
-
-    @Test(groups="Integration")
-    public void testAlternatives() throws Exception {
-        ProcessTaskWrapper<Integer> t = SshTasks.newSshExecTaskFactory(loc)
-                .add(BashCommands.alternatives(Arrays.asList("asdfj_no_such_command_1", "exit 88")))
-                .newTask();
-
-        Integer returnCode = exec.submit(t).get();
-        log.info("alternatives for bad commands gave: "+returnCode+"; err="+new String(t.getStderr())+"; out="+new String(t.getStdout()));
-        assertEquals(returnCode, (Integer)88);
-    }
-
-    @Test(groups="Integration")
-    public void testRequireTestHandlesFailure() throws Exception {
-        ProcessTaskWrapper<?> t = SshTasks.newSshExecTaskFactory(loc)
-            .add(BashCommands.requireTest("-f "+sourceNonExistantFile.getPath(),
-                    "The requested file does not exist")).newTask();
-
-        exec.submit(t).get();
-        assertNotEquals(t.getExitCode(), (Integer)0);
-        assertTrue(t.getStderr().contains("The requested file"), "Expected message in: "+t.getStderr());
-        assertTrue(t.getStdout().contains("The requested file"), "Expected message in: "+t.getStdout());
-    }
-
-    @Test(groups="Integration")
-    public void testRequireTestHandlesSuccess() throws Exception {
-        ProcessTaskWrapper<?> t = SshTasks.newSshExecTaskFactory(loc)
-            .add(BashCommands.requireTest("-f "+sourceFile1.getPath(),
-                    "The requested file does not exist")).newTask();
-
-        exec.submit(t).get();
-        assertEquals(t.getExitCode(), (Integer)0);
-        assertTrue(t.getStderr().equals(""), "Expected no stderr messages, but got: "+t.getStderr());
-    }
-
-    @Test(groups="Integration")
-    public void testRequireFileHandlesFailure() throws Exception {
-        ProcessTaskWrapper<?> t = SshTasks.newSshExecTaskFactory(loc)
-            .add(BashCommands.requireFile(sourceNonExistantFile.getPath())).newTask();
-
-        exec.submit(t).get();
-        assertNotEquals(t.getExitCode(), (Integer)0);
-        assertTrue(t.getStderr().contains("required file"), "Expected message in: "+t.getStderr());
-        assertTrue(t.getStderr().contains(sourceNonExistantFile.getPath()), "Expected message in: "+t.getStderr());
-        assertTrue(t.getStdout().contains("required file"), "Expected message in: "+t.getStdout());
-        assertTrue(t.getStdout().contains(sourceNonExistantFile.getPath()), "Expected message in: "+t.getStdout());
-    }
-
-    @Test(groups="Integration")
-    public void testRequireFileHandlesSuccess() throws Exception {
-        ProcessTaskWrapper<?> t = SshTasks.newSshExecTaskFactory(loc)
-            .add(BashCommands.requireFile(sourceFile1.getPath())).newTask();
-
-        exec.submit(t).get();
-        assertEquals(t.getExitCode(), (Integer)0);
-        assertTrue(t.getStderr().equals(""), "Expected no stderr messages, but got: "+t.getStderr());
-    }
-
-    @Test(groups="Integration")
-    public void testRequireFailureExitsImmediately() throws Exception {
-        ProcessTaskWrapper<?> t = SshTasks.newSshExecTaskFactory(loc)
-            .add(BashCommands.requireTest("-f "+sourceNonExistantFile.getPath(),
-                    "The requested file does not exist"))
-            .add("echo shouldnae come here").newTask();
-
-        exec.submit(t).get();
-        assertNotEquals(t.getExitCode(), (Integer)0);
-        assertTrue(t.getStderr().contains("The requested file"), "Expected message in: "+t.getStderr());
-        assertTrue(t.getStdout().contains("The requested file"), "Expected message in: "+t.getStdout());
-        Assert.assertFalse(t.getStdout().contains("shouldnae"), "Expected message in: "+t.getStdout());
-    }
-
-    @Test(groups="Integration")
-    public void testPipeMultiline() throws Exception {
-        String output = execRequiringZeroAndReturningStdout(loc,
-                BashCommands.pipeTextTo("hello world\n"+"and goodbye\n", "wc")).get();
-
-        assertEquals(Strings.replaceAllRegex(output, "\\s+", " ").trim(), "3 4 25");
-    }
-
-    @Test(groups="Integration")
-    public void testWaitForFileContentsWhenAbortingOnFail() throws Exception {
-        String fileContent = "mycontents";
-        String cmd = BashCommands.waitForFileContents(destFile.getAbsolutePath(), fileContent, Duration.ONE_SECOND, true);
-
-        int exitcode = loc.execCommands("test", ImmutableList.of(cmd));
-        assertEquals(exitcode, 1);
-        
-        Files.write(fileContent, destFile, Charsets.UTF_8);
-        int exitcode2 = loc.execCommands("test", ImmutableList.of(cmd));
-        assertEquals(exitcode2, 0);
-    }
-
-    @Test(groups="Integration")
-    public void testWaitForFileContentsWhenNotAbortingOnFail() throws Exception {
-        String fileContent = "mycontents";
-        String cmd = BashCommands.waitForFileContents(destFile.getAbsolutePath(), fileContent, Duration.ONE_SECOND, false);
-
-        String output = execRequiringZeroAndReturningStdout(loc, cmd).get();
-        assertTrue(output.contains("Couldn't find"), "output="+output);
-
-        Files.write(fileContent, destFile, Charsets.UTF_8);
-        String output2 = execRequiringZeroAndReturningStdout(loc, cmd).get();
-        assertFalse(output2.contains("Couldn't find"), "output="+output2);
-    }
-    
-    @Test(groups="Integration")
-    public void testWaitForFileContentsWhenContentsAppearAfterStart() throws Exception {
-        String fileContent = "mycontents";
-
-        String cmd = BashCommands.waitForFileContents(destFile.getAbsolutePath(), fileContent, Duration.THIRTY_SECONDS, false);
-        ProcessTaskWrapper<String> t = execRequiringZeroAndReturningStdout(loc, cmd);
-        exec.submit(t);
-        
-        // sleep for long enough to ensure the ssh command is definitely executing
-        Thread.sleep(5*1000);
-        assertFalse(t.isDone());
-        
-        Files.write(fileContent, destFile, Charsets.UTF_8);
-        String output = t.get();
-        assertFalse(output.contains("Couldn't find"), "output="+output);
-    }
-    
-    @Test(groups="Integration", dependsOnMethods="testSudo")
-    public void testWaitForPortFreeWhenAbortingOnTimeout() throws Exception {
-        ServerSocket serverSocket = openServerSocket();
-        try {
-            int port = serverSocket.getLocalPort();
-            String cmd = BashCommands.waitForPortFree(port, Duration.ONE_SECOND, true);
-    
-            int exitcode = loc.execCommands("test", ImmutableList.of(cmd));
-            assertEquals(exitcode, 1);
-            
-            serverSocket.close();
-            assertTrue(Networking.isPortAvailable(port));
-            int exitcode2 = loc.execCommands("test", ImmutableList.of(cmd));
-            assertEquals(exitcode2, 0);
-        } finally {
-            serverSocket.close();
-        }
-    }
-
-    @Test(groups="Integration", dependsOnMethods="testSudo")
-    public void testWaitForPortFreeWhenNotAbortingOnTimeout() throws Exception {
-        ServerSocket serverSocket = openServerSocket();
-        try {
-            int port = serverSocket.getLocalPort();
-            String cmd = BashCommands.waitForPortFree(port, Duration.ONE_SECOND, false);
-    
-            String output = execRequiringZeroAndReturningStdout(loc, cmd).get();
-            assertTrue(output.contains(port+" still in use"), "output="+output);
-    
-            serverSocket.close();
-            assertTrue(Networking.isPortAvailable(port));
-            String output2 = execRequiringZeroAndReturningStdout(loc, cmd).get();
-            assertFalse(output2.contains("still in use"), "output="+output2);
-        } finally {
-            serverSocket.close();
-        }
-    }
-    
-    @Test(groups="Integration", dependsOnMethods="testSudo")
-    public void testWaitForPortFreeWhenFreedAfterStart() throws Exception {
-        ServerSocket serverSocket = openServerSocket();
-        try {
-            int port = serverSocket.getLocalPort();
-    
-            String cmd = BashCommands.waitForPortFree(port, Duration.THIRTY_SECONDS, false);
-            ProcessTaskWrapper<String> t = execRequiringZeroAndReturningStdout(loc, cmd);
-            exec.submit(t);
-            
-            // sleep for long enough to ensure the ssh command is definitely executing
-            Thread.sleep(5*1000);
-            assertFalse(t.isDone());
-            
-            serverSocket.close();
-            assertTrue(Networking.isPortAvailable(port));
-            String output = t.get();
-            assertFalse(output.contains("still in use"), "output="+output);
-        } finally {
-            serverSocket.close();
-        }
-    }
-
-    
-    // Disabled by default because of risk of overriding /etc/hosts in really bad way if doesn't work properly!
-    // As a manual visual inspection test, consider first manually creating /etc/hostname and /etc/sysconfig/network
-    // so that it looks like debian+ubuntu / CentOS/RHEL.
-    @Test(groups={"Integration"}, enabled=false)
-    public void testSetHostnameUnqualified() throws Exception {
-        runSetHostname("br-"+Identifiers.makeRandomId(8).toLowerCase(), null, false);
-    }
-
-    @Test(groups={"Integration"}, enabled=false)
-    public void testSetHostnameQualified() throws Exception {
-        runSetHostname("br-"+Identifiers.makeRandomId(8).toLowerCase()+".brooklyn.incubator.apache.org", null, false);
-    }
-
-    @Test(groups={"Integration"}, enabled=false)
-    public void testSetHostnameNullDomain() throws Exception {
-        runSetHostname("br-"+Identifiers.makeRandomId(8).toLowerCase(), null, true);
-    }
-
-    @Test(groups={"Integration"}, enabled=false)
-    public void testSetHostnameNonNullDomain() throws Exception {
-        runSetHostname("br-"+Identifiers.makeRandomId(8).toLowerCase(), "brooklyn.incubator.apache.org", true);
-    }
-
-    protected void runSetHostname(String newHostname, String newDomain, boolean includeDomain) throws Exception {
-        String fqdn = (includeDomain && Strings.isNonBlank(newDomain)) ? newHostname + "." + newDomain : newHostname;
-        
-        LocalManagementContextForTests mgmt = new LocalManagementContextForTests();
-        SshMachineLocation loc = mgmt.getLocationManager().createLocation(LocalhostMachineProvisioningLocation.spec()).obtain();
-
-        execRequiringZeroAndReturningStdout(loc, sudo("cp /etc/hosts /etc/hosts-orig-testSetHostname")).get();
-        execRequiringZeroAndReturningStdout(loc, BashCommands.ifFileExistsElse0("/etc/hostname", sudo("cp /etc/hostname /etc/hostname-orig-testSetHostname"))).get();
-        execRequiringZeroAndReturningStdout(loc, BashCommands.ifFileExistsElse0("/etc/sysconfig/network", sudo("cp /etc/sysconfig/network /etc/sysconfig/network-orig-testSetHostname"))).get();
-        
-        String origHostname = getHostnameNoArgs(loc);
-        assertTrue(Strings.isNonBlank(origHostname));
-        
-        try {
-            List<String> cmd = (includeDomain) ? BashCommands.setHostname(newHostname, newDomain) : BashCommands.setHostname(newHostname);
-            execRequiringZeroAndReturningStdout(loc, cmd).get();
-
-            String actualHostnameUnqualified = getHostnameUnqualified(loc);
-            String actualHostnameFullyQualified = getHostnameFullyQualified(loc);
-
-            // TODO On OS X at least, we aren't actually setting the domain name; we're just letting 
-            //      the user pass in what the domain name is. We do add this properly to /etc/hosts
-            //      (e.g. first line is "127.0.0.1 br-g4x5wgx8.brooklyn.incubator.apache.org br-g4x5wgx8 localhost")
-            //      but subsequent calls to `hostname -f` returns the unqualified. Similarly, `domainname` 
-            //      returns blank. Therefore we can't assert that it equals our expected val (because we just made  
-            //      it up - "brooklyn.incubator.apache.org").
-            //      assertEquals(actualHostnameFullyQualified, fqdn);
-            assertEquals(actualHostnameUnqualified, Strings.getFragmentBetween(newHostname, null, "."));
-            execRequiringZeroAndReturningStdout(loc, "ping -c1 -n -q "+actualHostnameUnqualified).get();
-            execRequiringZeroAndReturningStdout(loc, "ping -c1 -n -q "+actualHostnameFullyQualified).get();
-            
-            String result = execRequiringZeroAndReturningStdout(loc, "grep -n "+fqdn+" /etc/hosts").get();
-            assertTrue(result.contains("localhost"), "line="+result);
-            log.info("result="+result);
-            
-        } finally {
-            execRequiringZeroAndReturningStdout(loc, sudo("cp /etc/hosts-orig-testSetHostname /etc/hosts")).get();
-            execRequiringZeroAndReturningStdout(loc, BashCommands.ifFileExistsElse0("/etc/hostname-orig-testSetHostname", sudo("cp /etc/hostname-orig-testSetHostname /etc/hostname"))).get();
-            execRequiringZeroAndReturningStdout(loc, BashCommands.ifFileExistsElse0("/etc/sysconfig/network-orig-testSetHostname", sudo("cp /etc/sysconfig/network-orig-testSetHostname /etc/sysconfig/network"))).get();
-            execRequiringZeroAndReturningStdout(loc, sudo("hostname "+origHostname)).get();
-        }
-    }
-
-    // Marked disabled because not safe to run on your normal machine! It modifies /etc/hosts, which is dangerous if things go wrong!
-    @Test(groups={"Integration"}, enabled=false)
-    public void testModifyEtcHosts() throws Exception {
-        LocalManagementContextForTests mgmt = new LocalManagementContextForTests();
-        SshMachineLocation loc = mgmt.getLocationManager().createLocation(LocalhostMachineProvisioningLocation.spec()).obtain();
-
-        execRequiringZeroAndReturningStdout(loc, sudo("cp /etc/hosts /etc/hosts-orig-testModifyEtcHosts")).get();
-        int numLinesOrig = Integer.parseInt(execRequiringZeroAndReturningStdout(loc, "wc -l /etc/hosts").get().trim().split("\\s")[0]);
-        
-        try {
-            String cmd = BashCommands.prependToEtcHosts("1.2.3.4", "myhostnamefor1234.at.start", "myhostnamefor1234b");
-            execRequiringZeroAndReturningStdout(loc, cmd).get();
-            
-            String cmd2 = BashCommands.appendToEtcHosts("5.6.7.8", "myhostnamefor5678.at.end", "myhostnamefor5678");
-            execRequiringZeroAndReturningStdout(loc, cmd2).get();
-            
-            String grepFirst = execRequiringZeroAndReturningStdout(loc, "grep -n myhostnamefor1234 /etc/hosts").get();
-            String grepLast = execRequiringZeroAndReturningStdout(loc, "grep -n myhostnamefor5678 /etc/hosts").get();
-            int numLinesAfter = Integer.parseInt(execRequiringZeroAndReturningStdout(loc, "wc -l /etc/hosts").get().trim().split("\\s")[0]);
-            log.info("result: numLinesBefore="+numLinesOrig+"; numLinesAfter="+numLinesAfter+"; first="+grepFirst+"; last="+grepLast);
-            
-            assertTrue(grepFirst.startsWith("1:") && grepFirst.contains("1.2.3.4 myhostnamefor1234.at.start myhostnamefor1234"), "first="+grepFirst);
-            assertTrue(grepLast.startsWith((numLinesOrig+2)+":") && grepLast.contains("5.6.7.8 myhostnamefor5678.at.end myhostnamefor5678"), "last="+grepLast);
-            assertEquals(numLinesOrig + 2, numLinesAfter, "lines orig="+numLinesOrig+", after="+numLinesAfter);
-        } finally {
-            execRequiringZeroAndReturningStdout(loc, sudo("cp /etc/hosts-orig-testModifyEtcHosts /etc/hosts")).get();
-        }
-    }
-    
-    private String getHostnameNoArgs(SshMachineLocation machine) {
-        String hostnameStdout = execRequiringZeroAndReturningStdout(machine, "echo FOREMARKER; hostname; echo AFTMARKER").get();
-        return Strings.getFragmentBetween(hostnameStdout, "FOREMARKER", "AFTMARKER").trim();
-    }
-
-    private String getHostnameUnqualified(SshMachineLocation machine) {
-        String hostnameStdout = execRequiringZeroAndReturningStdout(machine, "echo FOREMARKER; hostname -s 2> /dev/null || hostname; echo AFTMARKER").get();
-        return Strings.getFragmentBetween(hostnameStdout, "FOREMARKER", "AFTMARKER").trim();
-    }
-
-    private String getHostnameFullyQualified(SshMachineLocation machine) {
-        String hostnameStdout = execRequiringZeroAndReturningStdout(machine, "echo FOREMARKER; hostname --fqdn 2> /dev/null || hostname -f; echo AFTMARKER").get();
-        return Strings.getFragmentBetween(hostnameStdout, "FOREMARKER", "AFTMARKER").trim();
-    }
-
-    private ProcessTaskWrapper<String> execRequiringZeroAndReturningStdout(SshMachineLocation loc, Collection<String> cmds) {
-        return execRequiringZeroAndReturningStdout(loc, cmds.toArray(new String[cmds.size()]));
-    }
-    
-    private ProcessTaskWrapper<String> execRequiringZeroAndReturningStdout(SshMachineLocation loc, String... cmds) {
-        ProcessTaskWrapper<String> t = SshTasks.newSshExecTaskFactory(loc, cmds)
-                .requiringZeroAndReturningStdout().newTask();
-        exec.submit(t);
-        return t;
-    }
-
-    private ServerSocket openServerSocket() {
-        int lowerBound = 40000;
-        int upperBound = 40100;
-        for (int i = lowerBound; i < upperBound; i++) {
-            try {
-                return new ServerSocket(i);
-            } catch (IOException e) {
-                // try next number
-            }
-        }
-        throw new IllegalStateException("No ports available in range "+lowerBound+" to "+upperBound);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/BasicTaskExecutionPerformanceTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/BasicTaskExecutionPerformanceTest.java b/core/src/test/java/brooklyn/util/task/BasicTaskExecutionPerformanceTest.java
deleted file mode 100644
index 574c8c7..0000000
--- a/core/src/test/java/brooklyn/util/task/BasicTaskExecutionPerformanceTest.java
+++ /dev/null
@@ -1,206 +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 brooklyn.util.task;
-
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.management.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.util.collections.MutableMap;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Callables;
-
-/**
- * Test the operation of the {@link BasicTask} class.
- *
- * TODO clarify test purpose
- */
-public class BasicTaskExecutionPerformanceTest {
-    private static final Logger log = LoggerFactory.getLogger(BasicTaskExecutionPerformanceTest.class);
- 
-    private static final int TIMEOUT_MS = 10*1000;
-    
-    private BasicExecutionManager em;
-
-    public static final int MAX_OVERHEAD_MS = 1500; // was 750ms but saw 1.3s on buildhive
-    public static final int EARLY_RETURN_GRACE = 25; // saw 13ms early return on jenkins!
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() throws Exception {
-        em = new BasicExecutionManager("mycontext");
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (em != null) em.shutdownNow();
-    }
-    
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testScheduledTaskExecutedAfterDelay() throws Exception {
-        int delay = 100;
-        final CountDownLatch latch = new CountDownLatch(1);
-        
-        Callable<Task<?>> taskFactory = new Callable<Task<?>>() {
-            @Override public Task<?> call() {
-                return new BasicTask<Void>(new Runnable() {
-                    @Override public void run() {
-                        latch.countDown();
-                    }});
-            }};
-        ScheduledTask t = new ScheduledTask(taskFactory).delay(delay);
-
-        Stopwatch stopwatch = Stopwatch.createStarted();
-        em.submit(t);
-        
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        long actualDelay = stopwatch.elapsed(TimeUnit.MILLISECONDS);
-        
-        assertTrue(actualDelay > (delay-EARLY_RETURN_GRACE), "actualDelay="+actualDelay+"; delay="+delay);
-        assertTrue(actualDelay < (delay+MAX_OVERHEAD_MS), "actualDelay="+actualDelay+"; delay="+delay);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testScheduledTaskExecutedAtRegularPeriod() throws Exception {
-        final int period = 100;
-        final int numTimestamps = 4;
-        final CountDownLatch latch = new CountDownLatch(1);
-        final List<Long> timestamps = Collections.synchronizedList(Lists.<Long>newArrayList());
-        final Stopwatch stopwatch = Stopwatch.createStarted();
-        
-        Callable<Task<?>> taskFactory = new Callable<Task<?>>() {
-            @Override public Task<?> call() {
-                return new BasicTask<Void>(new Runnable() {
-                    @Override public void run() {
-                        timestamps.add(stopwatch.elapsed(TimeUnit.MILLISECONDS));
-                        if (timestamps.size() >= numTimestamps) latch.countDown();
-                    }});
-            }};
-        ScheduledTask t = new ScheduledTask(taskFactory).delay(1).period(period);
-        em.submit(t);
-        
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        
-        synchronized (timestamps) {
-            long prev = timestamps.get(0);
-            for (long timestamp : timestamps.subList(1, timestamps.size())) {
-                assertTrue(timestamp > prev+period-EARLY_RETURN_GRACE, "timestamps="+timestamps);
-                assertTrue(timestamp < prev+period+MAX_OVERHEAD_MS, "timestamps="+timestamps);
-                prev = timestamp;
-            }
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    @Test
-    public void testCanCancelScheduledTask() throws Exception {
-        final int period = 1;
-        final long checkPeriod = 250;
-        final List<Long> timestamps = Collections.synchronizedList(Lists.<Long>newArrayList());
-        
-        Callable<Task<?>> taskFactory = new Callable<Task<?>>() {
-            @Override public Task<?> call() {
-                return new BasicTask<Void>(new Runnable() {
-                    @Override public void run() {
-                        timestamps.add(System.currentTimeMillis());
-                    }});
-            }};
-        ScheduledTask t = new ScheduledTask(taskFactory).period(period);
-        em.submit(t);
-
-        t.cancel();
-        long cancelTime = System.currentTimeMillis();
-        int countImmediatelyAfterCancel = timestamps.size();
-        Thread.sleep(checkPeriod);
-        int countWellAfterCancel = timestamps.size();
-
-        // should have at most 1 more execution after cancel
-        log.info("testCanCancelScheduledTask saw "+countImmediatelyAfterCancel+" then cancel then "+countWellAfterCancel+" total");                
-        assertTrue(countWellAfterCancel - countImmediatelyAfterCancel <= 2, "timestamps="+timestamps+"; cancelTime="+cancelTime);
-    }
-
-    // Previously, when we used a CopyOnWriteArraySet, performance for submitting new tasks was
-    // terrible, and it degraded significantly as the number of previously executed tasks increased
-    // (e.g. 9s for first 1000; 26s for next 1000; 42s for next 1000).
-    @Test
-    public void testExecutionManagerPerformance() throws Exception {
-        // Was fixed at 1000 tasks, but was running out of virtual memory due to excessive thread creation
-        // on machines which were not able to execute the threads quickly.
-        final int NUM_TASKS = Math.min(500 * Runtime.getRuntime().availableProcessors(), 1000);
-        final int NUM_TIMES = 10;
-        final int MAX_ACCEPTABLE_TIME = 7500; // saw 5601ms on buildhive
-        
-        long tWarmup = execTasksAndWaitForDone(NUM_TASKS, ImmutableList.of("A"));
-        
-        List<Long> times = Lists.newArrayList();
-        for (int i = 1; i <= NUM_TIMES; i++) {
-            times.add(execTasksAndWaitForDone(NUM_TASKS, ImmutableList.of("A")));
-        }
-        
-        Long toobig = Iterables.find(
-                times, 
-                new Predicate<Long>() {
-                    public boolean apply(Long input) {
-                        return input > MAX_ACCEPTABLE_TIME;
-                    }},
-                null);
-        assertNull(toobig, "warmup="+tWarmup+"; times="+times);
-    }
-    
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private long execTasksAndWaitForDone(int numTasks, List<?> tags) throws Exception {
-        List<Task<?>> tasks = Lists.newArrayList();
-        long startTimestamp = System.currentTimeMillis();
-        for (int i = 1; i < numTasks; i++) {
-            Task<?> t = new BasicTask(Callables.returning(null)); // no-op
-            em.submit(MutableMap.of("tags", tags), t);
-            tasks.add(t);
-        }
-        long submittedTimestamp = System.currentTimeMillis();
-
-        for (Task t : tasks) {
-            t.get();
-        }
-        long endTimestamp = System.currentTimeMillis();
-        long submitTime = submittedTimestamp - startTimestamp;
-        long totalTime = endTimestamp - startTimestamp;
-        
-        log.info("Executed {} tasks; {}ms total; {}ms to submit", new Object[] {numTasks, totalTime, submitTime});
-
-        return totalTime;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/test/java/brooklyn/util/task/BasicTaskExecutionTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/util/task/BasicTaskExecutionTest.java b/core/src/test/java/brooklyn/util/task/BasicTaskExecutionTest.java
deleted file mode 100644
index 40660d4..0000000
--- a/core/src/test/java/brooklyn/util/task/BasicTaskExecutionTest.java
+++ /dev/null
@@ -1,460 +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 brooklyn.util.task;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CancellationException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.brooklyn.api.management.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import brooklyn.test.Asserts;
-import brooklyn.util.collections.MutableMap;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Callables;
-
-/**
- * Test the operation of the {@link BasicTask} class.
- *
- * TODO clarify test purpose
- */
-public class BasicTaskExecutionTest {
-    private static final Logger log = LoggerFactory.getLogger(BasicTaskExecutionTest.class);
- 
-    private static final int TIMEOUT_MS = 10*1000;
-    
-    private BasicExecutionManager em;
-    private Map<Object, Object> data;
-
-    @BeforeMethod(alwaysRun=true)
-    public void setUp() {
-        em = new BasicExecutionManager("mycontext");
-        data = Collections.synchronizedMap(new HashMap<Object, Object>());
-        data.clear();
-    }
-    
-    @AfterMethod(alwaysRun=true)
-    public void tearDown() throws Exception {
-        if (em != null) em.shutdownNow();
-        if (data != null) data.clear();
-    }
-    
-    @Test
-    public void runSimpleBasicTask() throws Exception {
-        BasicTask<Object> t = new BasicTask<Object>(newPutCallable(1, "b"));
-        data.put(1, "a");
-        Task<Object> t2 = em.submit(MutableMap.of("tag", "A"), t);
-        assertEquals("a", t.get());
-        assertEquals("a", t2.get());
-        assertEquals("b", data.get(1));
-    }
-    
-    @Test
-    public void runSimpleRunnable() throws Exception {
-        data.put(1, "a");
-        Task<?> t = em.submit(MutableMap.of("tag", "A"), newPutRunnable(1, "b"));
-        assertEquals(null, t.get());
-        assertEquals("b", data.get(1));
-    }
-
-    @Test
-    public void runSimpleCallable() throws Exception {
-        data.put(1, "a");
-        Task<?> t = em.submit(MutableMap.of("tag", "A"), newPutCallable(1, "b"));
-        assertEquals("a", t.get());
-        assertEquals("b", data.get(1));
-    }
-
-    @Test
-    public void runBasicTaskWithWaits() throws Exception {
-        final CountDownLatch signalStarted = new CountDownLatch(1);
-        final CountDownLatch allowCompletion = new CountDownLatch(1);
-        final BasicTask<Object> t = new BasicTask<Object>(new Callable<Object>() {
-            public Object call() throws Exception {
-                Object result = data.put(1, "b");
-                signalStarted.countDown();
-                assertTrue(allowCompletion.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-                return result;
-            }});
-        data.put(1, "a");
-
-        Task<?> t2 = em.submit(MutableMap.of("tag", "A"), t);
-        assertEquals(t, t2);
-        assertFalse(t.isDone());
-        
-        assertTrue(signalStarted.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        assertEquals("b", data.get(1));
-        assertFalse(t.isDone());
-        
-        log.debug("runBasicTaskWithWaits, BasicTask status: {}", t.getStatusDetail(false));
-        
-        Asserts.succeedsEventually(new Runnable() {
-            public void run() {
-                String status = t.getStatusDetail(false);
-                assertTrue(status != null && status.toLowerCase().contains("waiting"), "status="+status);
-            }});
-        
-        allowCompletion.countDown();
-        assertEquals("a", t.get());
-    }
-
-    @Test
-    public void runMultipleBasicTasks() throws Exception {
-        data.put(1, 1);
-        BasicExecutionManager em = new BasicExecutionManager("mycontext");
-        for (int i = 0; i < 2; i++) {
-            em.submit(MutableMap.of("tag", "A"), new BasicTask<Integer>(newIncrementCallable(1)));
-            em.submit(MutableMap.of("tag", "B"), new BasicTask<Integer>(newIncrementCallable((1))));
-        }
-        int total = 0;
-        for (Object tag : em.getTaskTags()) {
-                log.debug("tag {}", tag);
-                for (Task<?> task : em.getTasksWithTag(tag)) {
-                    log.debug("BasicTask {}, has {}", task, task.get());
-                    total += (Integer)task.get();
-                }
-            }
-        assertEquals(10, total);
-        //now that all have completed:
-        assertEquals(5, data.get(1));
-    }
-
-    @Test
-    public void runMultipleBasicTasksMultipleTags() throws Exception {
-        data.put(1, 1);
-        Collection<Task<Integer>> tasks = Lists.newArrayList();
-        tasks.add(em.submit(MutableMap.of("tag", "A"), new BasicTask<Integer>(newIncrementCallable(1))));
-        tasks.add(em.submit(MutableMap.of("tags", ImmutableList.of("A","B")), new BasicTask<Integer>(newIncrementCallable(1))));
-        tasks.add(em.submit(MutableMap.of("tags", ImmutableList.of("B","C")), new BasicTask<Integer>(newIncrementCallable(1))));
-        tasks.add(em.submit(MutableMap.of("tags", ImmutableList.of("D")), new BasicTask<Integer>(newIncrementCallable(1))));
-        int total = 0;
-
-        for (Task<Integer> t : tasks) {
-            log.debug("BasicTask {}, has {}", t, t.get());
-            total += t.get();
-            }
-        assertEquals(10, total);
- 
-        //now that all have completed:
-        assertEquals(data.get(1), 5);
-        assertEquals(em.getTasksWithTag("A").size(), 2);
-        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A")).size(), 2);
-        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A")).size(), 2);
-
-        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A", "B")).size(), 3);
-        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A", "B")).size(), 1);
-        assertEquals(em.getTasksWithAllTags(ImmutableList.of("B", "C")).size(), 1);
-        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A", "D")).size(), 3);
-    }
-
-    @Test
-    public void testGetTaskById() throws Exception {
-        Task<?> t = new BasicTask<Void>(newNoop());
-        em.submit(MutableMap.of("tag", "A"), t);
-        assertEquals(em.getTask(t.getId()), t);
-    }
-
-    @Test
-    public void testRetrievingTasksWithTagsReturnsExpectedTask() throws Exception {
-        Task<?> t = new BasicTask<Void>(newNoop());
-        em.submit(MutableMap.of("tag", "A"), t);
-        t.get();
-
-        assertEquals(em.getTasksWithTag("A"), ImmutableList.of(t));
-        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A")), ImmutableList.of(t));
-        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A", "B")), ImmutableList.of(t));
-        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A")), ImmutableList.of(t));
-    }
-
-    @Test
-    public void testRetrievingTasksWithTagsExcludesNonMatchingTasks() throws Exception {
-        Task<?> t = new BasicTask<Void>(newNoop());
-        em.submit(MutableMap.of("tag", "A"), t);
-        t.get();
-
-        assertEquals(em.getTasksWithTag("B"), ImmutableSet.of());
-        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("B")), ImmutableSet.of());
-        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A", "B")), ImmutableSet.of());
-    }
-    
-    @Test
-    public void testRetrievingTasksWithMultipleTags() throws Exception {
-        Task<?> t = new BasicTask<Void>(newNoop());
-        em.submit(MutableMap.of("tags", ImmutableList.of("A", "B")), t);
-        t.get();
-
-        assertEquals(em.getTasksWithTag("A"), ImmutableList.of(t));
-        assertEquals(em.getTasksWithTag("B"), ImmutableList.of(t));
-        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A")), ImmutableList.of(t));
-        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("B")), ImmutableList.of(t));
-        assertEquals(em.getTasksWithAnyTag(ImmutableList.of("A", "B")), ImmutableList.of(t));
-        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A", "B")), ImmutableList.of(t));
-        assertEquals(em.getTasksWithAllTags(ImmutableList.of("A")), ImmutableList.of(t));
-        assertEquals(em.getTasksWithAllTags(ImmutableList.of("B")), ImmutableList.of(t));
-    }
-
-    // ENGR-1796: if nothing matched first tag, then returned whatever matched second tag!
-    @Test
-    public void testRetrievingTasksWithAllTagsWhenFirstNotMatched() throws Exception {
-        Task<?> t = new BasicTask<Void>(newNoop());
-        em.submit(MutableMap.of("tags", ImmutableList.of("A")), t);
-        t.get();
-
-        assertEquals(em.getTasksWithAllTags(ImmutableList.of("not_there","A")), ImmutableSet.of());
-    }
-    
-    @Test
-    public void testRetrievedTasksIncludesTasksInProgress() throws Exception {
-        final CountDownLatch runningLatch = new CountDownLatch(1);
-        final CountDownLatch finishLatch = new CountDownLatch(1);
-        Task<Void> t = new BasicTask<Void>(new Callable<Void>() {
-            public Void call() throws Exception {
-                runningLatch.countDown();
-                finishLatch.await();
-                return null;
-            }});
-        em.submit(MutableMap.of("tags", ImmutableList.of("A")), t);
-        
-        try {
-            runningLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-    
-            assertEquals(em.getTasksWithTag("A"), ImmutableList.of(t));
-        } finally {
-            finishLatch.countDown();
-        }
-    }
-    
-    @Test
-    public void cancelBeforeRun() throws Exception {
-        final CountDownLatch blockForever = new CountDownLatch(1);
-        
-        BasicTask<Integer> t = new BasicTask<Integer>(new Callable<Integer>() {
-            public Integer call() throws Exception {
-                blockForever.await(); return 42;
-            }});
-        t.cancel(true);
-        assertTrue(t.isCancelled());
-        assertTrue(t.isDone());
-        assertTrue(t.isError());
-        em.submit(MutableMap.of("tag", "A"), t);
-        try {
-            t.get();
-            fail("get should have failed due to cancel");
-        } catch (CancellationException e) {
-            // expected
-        }
-        assertTrue(t.isCancelled());
-        assertTrue(t.isDone());
-        assertTrue(t.isError());
-        
-        log.debug("cancelBeforeRun status: {}", t.getStatusDetail(false));
-        assertTrue(t.getStatusDetail(false).toLowerCase().contains("cancel"));
-    }
-
-    @Test
-    public void cancelDuringRun() throws Exception {
-        final CountDownLatch signalStarted = new CountDownLatch(1);
-        final CountDownLatch blockForever = new CountDownLatch(1);
-        
-        BasicTask<Integer> t = new BasicTask<Integer>(new Callable<Integer>() {
-            public Integer call() throws Exception {
-                synchronized (data) {
-                    signalStarted.countDown();
-                    blockForever.await();
-                }
-                return 42;
-            }});
-        em.submit(MutableMap.of("tag", "A"), t);
-        assertFalse(t.isCancelled());
-        assertFalse(t.isDone());
-        assertFalse(t.isError());
-        
-        assertTrue(signalStarted.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        t.cancel(true);
-        
-        assertTrue(t.isCancelled());
-        assertTrue(t.isError());
-        try {
-            t.get();
-            fail("get should have failed due to cancel");
-        } catch (CancellationException e) {
-            // expected
-        }
-        assertTrue(t.isCancelled());
-        assertTrue(t.isDone());
-        assertTrue(t.isError());
-    }
-    
-    @Test
-    public void cancelAfterRun() throws Exception {
-        BasicTask<Integer> t = new BasicTask<Integer>(Callables.returning(42));
-        em.submit(MutableMap.of("tag", "A"), t);
-
-        assertEquals(t.get(), (Integer)42);
-        t.cancel(true);
-        assertFalse(t.isCancelled());
-        assertFalse(t.isError());
-        assertTrue(t.isDone());
-    }
-    
-    @Test
-    public void errorDuringRun() throws Exception {
-        BasicTask<Void> t = new BasicTask<Void>(new Callable<Void>() {
-            public Void call() throws Exception {
-                throw new IllegalStateException("Simulating failure in errorDuringRun");
-            }});
-        
-        em.submit(MutableMap.of("tag", "A"), t);
-        
-        try {
-            t.get();
-            fail("get should have failed due to error"); 
-        } catch (Exception eo) { 
-            Throwable e = Throwables.getRootCause(eo);
-            assertEquals("Simulating failure in errorDuringRun", e.getMessage());
-        }
-        
-        assertFalse(t.isCancelled());
-        assertTrue(t.isError());
-        assertTrue(t.isDone());
-        
-        log.debug("errorDuringRun status: {}", t.getStatusDetail(false));
-        assertTrue(t.getStatusDetail(false).contains("Simulating failure in errorDuringRun"), "details="+t.getStatusDetail(false));
-    }
-
-    @Test
-    public void fieldsSetForSimpleBasicTask() throws Exception {
-        final CountDownLatch signalStarted = new CountDownLatch(1);
-        final CountDownLatch allowCompletion = new CountDownLatch(1);
-        
-        BasicTask<Integer> t = new BasicTask<Integer>(new Callable<Integer>() {
-            public Integer call() throws Exception {
-                signalStarted.countDown();
-                allowCompletion.await();
-                return 42;
-            }});
-        assertEquals(null, t.getSubmittedByTask());
-        assertEquals(-1, t.submitTimeUtc);
-        assertNull(t.getInternalFuture());
-
-        em.submit(MutableMap.of("tag", "A"), t);
-        assertTrue(signalStarted.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        
-        assertTrue(t.submitTimeUtc > 0);
-        assertTrue(t.startTimeUtc >= t.submitTimeUtc);
-        assertNotNull(t.getInternalFuture());
-        assertEquals(-1, t.endTimeUtc);
-        assertEquals(false, t.isCancelled());
-        
-        allowCompletion.countDown();
-        assertEquals(t.get(), (Integer)42);
-        assertTrue(t.endTimeUtc >= t.startTimeUtc);
-
-        log.debug("BasicTask duration (millis): {}", (t.endTimeUtc - t.submitTimeUtc));
-    }
-
-    @Test
-    public void fieldsSetForBasicTaskSubmittedBasicTask() throws Exception {
-        //submitted BasicTask B is started by A, and waits for A to complete
-        BasicTask<Integer> t = new BasicTask<Integer>(MutableMap.of("displayName", "sample", "description", "some descr"), new Callable<Integer>() {
-            public Integer call() throws Exception {
-                em.submit(MutableMap.of("tag", "B"), new Callable<Integer>() {
-                    public Integer call() throws Exception {
-                        assertEquals(45, em.getTasksWithTag("A").iterator().next().get());
-                        return 46;
-                    }});
-                return 45;
-            }});
-        em.submit(MutableMap.of("tag", "A"), t);
-
-        t.blockUntilEnded();
- 
-//        assertEquals(em.getAllTasks().size(), 2
-        
-        BasicTask<?> tb = (BasicTask<?>) em.getTasksWithTag("B").iterator().next();
-        assertEquals( 46, tb.get() );
-        assertEquals( t, em.getTasksWithTag("A").iterator().next() );
-        assertNull( t.getSubmittedByTask() );
-        
-        BasicTask<?> submitter = (BasicTask<?>) tb.getSubmittedByTask();
-        assertNotNull(submitter);
-        assertEquals("sample", submitter.displayName);
-        assertEquals("some descr", submitter.description);
-        assertEquals(t, submitter);
-        
-        assertTrue(submitter.submitTimeUtc <= tb.submitTimeUtc);
-        assertTrue(submitter.endTimeUtc <= tb.endTimeUtc);
-        
-        log.debug("BasicTask {} was submitted by {}", tb, submitter);
-    }
-    
-    private Callable<Object> newPutCallable(final Object key, final Object val) {
-        return new Callable<Object>() {
-            public Object call() {
-                return data.put(key, val);
-            }
-        };
-    }
-    
-    private Callable<Integer> newIncrementCallable(final Object key) {
-        return new Callable<Integer>() {
-            public Integer call() {
-                synchronized (data) {
-                    return (Integer) data.put(key, (Integer)data.get(key) + 1);
-                }
-            }
-        };
-    }
-    
-    private Runnable newPutRunnable(final Object key, final Object val) {
-        return new Runnable() {
-            public void run() {
-                data.put(key, val);
-            }
-        };
-    }
-    
-    private Runnable newNoop() {
-        return new Runnable() {
-            public void run() {
-            }
-        };
-    }
-}


[28/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/system/internal/ExecWithLoggingHelpers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/internal/ExecWithLoggingHelpers.java b/core/src/main/java/brooklyn/util/task/system/internal/ExecWithLoggingHelpers.java
deleted file mode 100644
index c2b8907..0000000
--- a/core/src/main/java/brooklyn/util/task/system/internal/ExecWithLoggingHelpers.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 brooklyn.util.task.system.internal;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PipedInputStream;
-import java.io.PipedOutputStream;
-import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-
-import brooklyn.config.ConfigKey;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.internal.ssh.ShellAbstractTool;
-import brooklyn.util.internal.ssh.ShellTool;
-import brooklyn.util.stream.StreamGobbler;
-import brooklyn.util.stream.Streams;
-import brooklyn.util.task.Tasks;
-import brooklyn.util.text.Strings;
-
-import com.google.common.base.Function;
-import com.google.common.base.Throwables;
-
-public abstract class ExecWithLoggingHelpers {
-
-    public static final ConfigKey<OutputStream> STDOUT = SshMachineLocation.STDOUT;
-    public static final ConfigKey<OutputStream> STDERR = SshMachineLocation.STDERR;
-    public static final ConfigKey<Boolean> NO_STDOUT_LOGGING = SshMachineLocation.NO_STDOUT_LOGGING;
-    public static final ConfigKey<Boolean> NO_STDERR_LOGGING = SshMachineLocation.NO_STDERR_LOGGING;
-    public static final ConfigKey<String> LOG_PREFIX = SshMachineLocation.LOG_PREFIX;
-
-    protected final String shortName;
-    protected Logger commandLogger = null;
-    
-    public interface ExecRunner {
-        public int exec(ShellTool ssh, Map<String,?> flags, List<String> cmds, Map<String,?> env);
-    }
-
-    protected abstract <T> T execWithTool(MutableMap<String, Object> toolCreationAndConnectionProperties, Function<ShellTool, T> runMethodOnTool);
-    protected abstract void preExecChecks();
-    protected abstract String getTargetName();
-    protected abstract String constructDefaultLoggingPrefix(ConfigBag execFlags);
-
-    /** takes a very short name for use in blocking details, e.g. SSH or Process */
-    public ExecWithLoggingHelpers(String shortName) {
-        this.shortName = shortName;
-    }
-
-    public ExecWithLoggingHelpers logger(Logger commandLogger) {
-        this.commandLogger = commandLogger;
-        return this;
-    }
-    
-    public int execScript(Map<String,?> props, String summaryForLogging, List<String> commands, Map<String,?> env) {
-        // TODO scriptHeader are the extra commands we expect the SshTool/ShellTool to add.
-        // Would be better if could get this from the ssh-tool, rather than assuming it will behave as
-        // we expect.
-        String scriptHeader = ShellAbstractTool.getOptionalVal(props, ShellTool.PROP_SCRIPT_HEADER);
-        
-        return execWithLogging(props, summaryForLogging, commands, env, scriptHeader, new ExecRunner() {
-                @Override public int exec(ShellTool ssh, Map<String, ?> flags, List<String> cmds, Map<String, ?> env) {
-                    return ssh.execScript(flags, cmds, env);
-                }});
-    }
-
-    protected static <T> T getOptionalVal(Map<String,?> map, ConfigKey<T> keyC) {
-        if (keyC==null) return null;
-        String key = keyC.getName();
-        if (map!=null && map.containsKey(key)) {
-            return TypeCoercions.coerce(map.get(key), keyC.getTypeToken());
-        } else {
-            return keyC.getDefaultValue();
-        }
-    }
-
-    public int execCommands(Map<String,?> props, String summaryForLogging, List<String> commands, Map<String,?> env) {
-        return execWithLogging(props, summaryForLogging, commands, env, new ExecRunner() {
-                @Override public int exec(ShellTool tool, Map<String,?> flags, List<String> cmds, Map<String,?> env) {
-                    return tool.execCommands(flags, cmds, env);
-                }});
-    }
-
-    public int execWithLogging(Map<String,?> props, final String summaryForLogging, final List<String> commands,
-            final Map<String,?> env, final ExecRunner execCommand) {
-        return execWithLogging(props, summaryForLogging, commands, env, null, execCommand);
-    }
-    
-    @SuppressWarnings("resource")
-    public int execWithLogging(Map<String,?> props, final String summaryForLogging, final List<String> commands,
-            final Map<String,?> env, String expectedCommandHeaders, final ExecRunner execCommand) {
-        if (commandLogger!=null && commandLogger.isDebugEnabled()) {
-            String allcmds = (Strings.isBlank(expectedCommandHeaders) ? "" : expectedCommandHeaders + " ; ") + Strings.join(commands, " ; ");
-            commandLogger.debug("{}, initiating "+shortName.toLowerCase()+" on machine {}{}: {}",
-                    new Object[] {summaryForLogging, getTargetName(),
-                    env!=null && !env.isEmpty() ? " (env "+env+")": "", allcmds});
-        }
-
-        if (commands.isEmpty()) {
-            if (commandLogger!=null && commandLogger.isDebugEnabled())
-                commandLogger.debug("{}, on machine {}, ending: no commands to run", summaryForLogging, getTargetName());
-            return 0;
-        }
-
-        final ConfigBag execFlags = new ConfigBag().putAll(props);
-        // some props get overridden in execFlags, so remove them from the tool flags
-        final ConfigBag toolFlags = new ConfigBag().putAll(props).removeAll(
-                LOG_PREFIX, STDOUT, STDERR, ShellTool.PROP_NO_EXTRA_OUTPUT);
-
-        execFlags.configure(ShellTool.PROP_SUMMARY, summaryForLogging);
-        
-        PipedOutputStream outO = null;
-        PipedOutputStream outE = null;
-        StreamGobbler gO=null, gE=null;
-        try {
-            preExecChecks();
-            
-            String logPrefix = execFlags.get(LOG_PREFIX);
-            if (logPrefix==null) logPrefix = constructDefaultLoggingPrefix(execFlags);
-
-            if (!execFlags.get(NO_STDOUT_LOGGING)) {
-                PipedInputStream insO = new PipedInputStream();
-                outO = new PipedOutputStream(insO);
-
-                String stdoutLogPrefix = "["+(logPrefix != null ? logPrefix+":stdout" : "stdout")+"] ";
-                gO = new StreamGobbler(insO, execFlags.get(STDOUT), commandLogger).setLogPrefix(stdoutLogPrefix);
-                gO.start();
-
-                execFlags.put(STDOUT, outO);
-            }
-
-            if (!execFlags.get(NO_STDERR_LOGGING)) {
-                PipedInputStream insE = new PipedInputStream();
-                outE = new PipedOutputStream(insE);
-
-                String stderrLogPrefix = "["+(logPrefix != null ? logPrefix+":stderr" : "stderr")+"] ";
-                gE = new StreamGobbler(insE, execFlags.get(STDERR), commandLogger).setLogPrefix(stderrLogPrefix);
-                gE.start();
-
-                execFlags.put(STDERR, outE);
-            }
-
-            Tasks.setBlockingDetails(shortName+" executing, "+summaryForLogging);
-            try {
-                return execWithTool(MutableMap.copyOf(toolFlags.getAllConfig()), new Function<ShellTool, Integer>() {
-                    public Integer apply(ShellTool tool) {
-                        int result = execCommand.exec(tool, MutableMap.copyOf(execFlags.getAllConfig()), commands, env);
-                        if (commandLogger!=null && commandLogger.isDebugEnabled()) 
-                            commandLogger.debug("{}, on machine {}, completed: return status {}",
-                                    new Object[] {summaryForLogging, getTargetName(), result});
-                        return result;
-                    }});
-
-            } finally {
-                Tasks.setBlockingDetails(null);
-            }
-
-        } catch (IOException e) {
-            if (commandLogger!=null && commandLogger.isDebugEnabled()) 
-                commandLogger.debug("{}, on machine {}, failed: {}", new Object[] {summaryForLogging, getTargetName(), e});
-            throw Throwables.propagate(e);
-        } finally {
-            // Must close the pipedOutStreams, otherwise input will never read -1 so StreamGobbler thread would never die
-            if (outO!=null) try { outO.flush(); } catch (IOException e) {}
-            if (outE!=null) try { outE.flush(); } catch (IOException e) {}
-            Streams.closeQuietly(outO);
-            Streams.closeQuietly(outE);
-
-            try {
-                if (gE!=null) { gE.join(); }
-                if (gO!=null) { gO.join(); }
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-                Throwables.propagate(e);
-            }
-        }
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/task/system/internal/SystemProcessTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/task/system/internal/SystemProcessTaskFactory.java b/core/src/main/java/brooklyn/util/task/system/internal/SystemProcessTaskFactory.java
deleted file mode 100644
index e6eb831..0000000
--- a/core/src/main/java/brooklyn/util/task/system/internal/SystemProcessTaskFactory.java
+++ /dev/null
@@ -1,131 +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 brooklyn.util.task.system.internal;
-
-import java.io.File;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.config.ConfigBag;
-import brooklyn.util.internal.ssh.ShellTool;
-import brooklyn.util.internal.ssh.process.ProcessTool;
-import brooklyn.util.task.system.ProcessTaskWrapper;
-
-import com.google.common.base.Function;
-
-public class SystemProcessTaskFactory<T extends SystemProcessTaskFactory<T,RET>,RET> extends AbstractProcessTaskFactory<T, RET> {
-
-    private static final Logger log = LoggerFactory.getLogger(SystemProcessTaskFactory.class);
-    
-    // FIXME Plum this through?!
-    private File directory;
-    private Boolean loginShell;
-
-    public SystemProcessTaskFactory(String ...commands) {
-        super(commands);
-    }
-    
-    public T directory(File directory) {
-        markDirty();
-        this.directory = directory;
-        return self();
-    }
-    
-    public T loginShell(boolean loginShell) {
-        markDirty();
-        this.loginShell = loginShell;
-        return self();
-    }
-    
-    @Override
-    public T machine(SshMachineLocation machine) {
-        log.warn("Not permitted to set machines on "+this+" (ignoring - "+machine+")");
-        if (log.isDebugEnabled())
-            log.debug("Source of attempt to set machines on "+this+" ("+machine+")",
-                    new Throwable("Source of attempt to set machines on "+this+" ("+machine+")"));
-        return self();
-    }
-
-    @Override
-    public ProcessTaskWrapper<RET> newTask() {
-        return new SystemProcessTaskWrapper();
-    }
-
-    protected class SystemProcessTaskWrapper extends ProcessTaskWrapper<RET> {
-        protected final String taskTypeShortName;
-        
-        public SystemProcessTaskWrapper() {
-            this("Process");
-        }
-        public SystemProcessTaskWrapper(String taskTypeShortName) {
-            super(SystemProcessTaskFactory.this);
-            this.taskTypeShortName = taskTypeShortName;
-        }
-        @Override
-        protected ConfigBag getConfigForRunning() {
-            ConfigBag result = super.getConfigForRunning();
-            if (directory != null) config.put(ProcessTool.PROP_DIRECTORY, directory.getAbsolutePath());
-            if (loginShell != null) config.put(ProcessTool.PROP_LOGIN_SHELL, loginShell);
-            return result;
-        }
-        @Override
-        protected void run(ConfigBag config) {
-            if (Boolean.FALSE.equals(this.runAsScript)) {
-                this.exitCode = newExecWithLoggingHelpers().execCommands(config.getAllConfig(), getSummary(), getCommands(), getShellEnvironment());
-            } else { // runScript = null or TRUE
-                this.exitCode = newExecWithLoggingHelpers().execScript(config.getAllConfig(), getSummary(), getCommands(), getShellEnvironment());
-            }
-        }
-        @Override
-        protected String taskTypeShortName() { return taskTypeShortName; }
-    }
-    
-    protected ExecWithLoggingHelpers newExecWithLoggingHelpers() {
-        return new ExecWithLoggingHelpers("Process") {
-            @Override
-            protected <U> U execWithTool(MutableMap<String, Object> props, Function<ShellTool, U> task) {
-                // properties typically passed to both
-                if (log.isDebugEnabled() && props!=null && !props.isEmpty())
-                    log.debug("Ignoring flags "+props+" when running "+this);
-                return task.apply(new ProcessTool());
-            }
-            @Override
-            protected void preExecChecks() {}
-            @Override
-            protected String constructDefaultLoggingPrefix(ConfigBag execFlags) {
-                return "system.exec";
-            }
-            @Override
-            protected String getTargetName() {
-                return "local host";
-            }
-        }.logger(log);
-    }
-
-    /** concrete instance (for generics) */
-    public static class ConcreteSystemProcessTaskFactory<RET> extends SystemProcessTaskFactory<ConcreteSystemProcessTaskFactory<RET>, RET> {
-        public ConcreteSystemProcessTaskFactory(String ...commands) {
-            super(commands);
-        }
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/text/DataUriSchemeParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/text/DataUriSchemeParser.java b/core/src/main/java/brooklyn/util/text/DataUriSchemeParser.java
deleted file mode 100644
index 393ab20..0000000
--- a/core/src/main/java/brooklyn/util/text/DataUriSchemeParser.java
+++ /dev/null
@@ -1,267 +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 brooklyn.util.text;
-
-import java.io.ByteArrayInputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
-import java.net.URLDecoder;
-import java.nio.charset.Charset;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import brooklyn.util.exceptions.Exceptions;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.io.BaseEncoding;
-//import com.sun.jersey.core.util.Base64;
-
-/** implementation (currently hokey) of RFC-2397 data: URI scheme.
- * see: http://stackoverflow.com/questions/12353552/any-rfc-2397-data-uri-parser-for-java */
-public class DataUriSchemeParser {
-
-    public static final String PROTOCOL_PREFIX = "data:";
-    public static final String DEFAULT_MIME_TYPE = "text/plain";
-    public static final String DEFAULT_CHARSET = "US-ASCII";
-    
-    private final String url;
-    private int parseIndex = 0;
-    private boolean isParsed = false;
-    private boolean allowMissingComma = false;
-    private boolean allowSlashesAfterColon = false;
-    private boolean allowOtherLaxities = false;
-    
-    private String mimeType;
-    private byte[] data;
-    private Map<String,String> parameters = new LinkedHashMap<String,String>();
-
-    public DataUriSchemeParser(String url) {
-        this.url = Preconditions.checkNotNull(url, "url");
-    }
-
-    // ---- static conveniences -----
-    
-    public static String toString(String url) {
-        return new DataUriSchemeParser(url).lax().parse().getDataAsString();
-    }
-
-    public static byte[] toBytes(String url) {
-        return new DataUriSchemeParser(url).lax().parse().getData();
-    }
-
-    // ---- accessors (once it is parsed) -----------
-    
-    public String getCharset() {
-        String charset = parameters.get("charset");
-        if (charset!=null) return charset;
-        return DEFAULT_CHARSET;
-    }
-
-    public String getMimeType() {
-        assertParsed();
-        if (mimeType!=null) return mimeType;
-        return DEFAULT_MIME_TYPE;
-    }
-    
-    public Map<String, String> getParameters() {
-        return ImmutableMap.<String, String>copyOf(parameters);
-    }
-
-    public byte[] getData() {
-        assertParsed();
-        return data;
-    }
-    
-    public ByteArrayInputStream getDataAsInputStream() {
-        return new ByteArrayInputStream(getData());
-    }
-
-    public String getDataAsString() {
-        return new String(getData(), Charset.forName(getCharset()));
-    }
-
-    // ---- config ------------------
-    
-    public synchronized DataUriSchemeParser lax() {
-        return allowMissingComma(true).allowSlashesAfterColon(true).allowOtherLaxities(true);
-    }
-        
-    public synchronized DataUriSchemeParser allowMissingComma(boolean allowMissingComma) {
-        assertNotParsed();
-        this.allowMissingComma = allowMissingComma;
-        return this;
-    }
-    
-    public synchronized DataUriSchemeParser allowSlashesAfterColon(boolean allowSlashesAfterColon) {
-        assertNotParsed();
-        this.allowSlashesAfterColon = allowSlashesAfterColon;
-        return this;
-    }
-    
-    private synchronized DataUriSchemeParser allowOtherLaxities(boolean allowOtherLaxities) {
-        assertNotParsed();
-        this.allowOtherLaxities = allowOtherLaxities;
-        return this;
-    }
-    
-    private void assertNotParsed() {
-        if (isParsed) throw new IllegalStateException("Operation not permitted after parsing");
-    }
-
-    private void assertParsed() {
-        if (!isParsed) throw new IllegalStateException("Operation not permitted before parsing");
-    }
-
-    public synchronized DataUriSchemeParser parse() {
-        try {
-            return parseChecked();
-        } catch (Exception e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-    
-    public synchronized DataUriSchemeParser parseChecked() throws UnsupportedEncodingException, MalformedURLException {
-        if (isParsed) return this;
-        
-        skipOptional(PROTOCOL_PREFIX);
-        if (allowSlashesAfterColon)
-            while (skipOptional("/")) ;
-        
-        if (allowMissingComma && remainder().indexOf(',')==-1) {
-            mimeType = DEFAULT_MIME_TYPE;
-            parameters.put("charset", DEFAULT_CHARSET);
-        } else {        
-            parseMediaType();
-            parseParameterOrParameterValues();
-            skipRequired(",");
-        }
-        
-        parseData();
-        
-        isParsed = true;
-        return this;
-    }
-
-    private void parseMediaType() throws MalformedURLException {
-        if (remainder().startsWith(";") || remainder().startsWith(","))
-            return;
-        int slash = remainder().indexOf("/");
-        if (slash==-1) throw new MalformedURLException("Missing required '/' in MIME type of data: URL");
-        String type = read(slash);
-        skipRequired("/");
-        int next = nextSemiOrComma();
-        String subtype = read(next);
-        mimeType = type+"/"+subtype;
-    }
-
-    private String read(int next) {
-        String result = remainder().substring(0, next);
-        parseIndex += next;
-        return result;
-    }
-
-    private int nextSemiOrComma() throws MalformedURLException {
-        int semi = remainder().indexOf(';');
-        int comma = remainder().indexOf(',');
-        if (semi<0 && comma<0) throw new MalformedURLException("Missing required ',' in data: URL");
-        if (semi<0) return comma;
-        if (comma<0) return semi;
-        return Math.min(semi, comma);
-    }
-
-    private void parseParameterOrParameterValues() throws MalformedURLException {
-        while (true) {
-            if (!remainder().startsWith(";")) return;
-            parseIndex++;
-            int eq = remainder().indexOf('=');
-            String word, value;
-            int nextSemiOrComma = nextSemiOrComma();
-            if (eq==-1 || eq>nextSemiOrComma) {
-                word = read(nextSemiOrComma);
-                value = null;
-            } else {
-                word = read(eq);
-                if (remainder().startsWith("\"")) {
-                    // is quoted
-                    parseIndex++;
-                    int nextUnescapedQuote = nextUnescapedQuote();
-                    value = "\"" + read(nextUnescapedQuote);
-                } else {
-                    value = read(nextSemiOrComma());
-                }
-            }
-            parameters.put(word, value);
-        }
-    }
-
-    private int nextUnescapedQuote() throws MalformedURLException {
-        int i=0;
-        String r = remainder();
-        boolean escaped = false;
-        while (i<r.length()) {
-            if (escaped) {
-                escaped = false;
-            } else {
-                if (r.charAt(i)=='"') return i;
-                if (r.charAt(i)=='\\') escaped = true;
-            }
-            i++;
-        }
-        throw new MalformedURLException("Unclosed double-quote in data: URL");
-    }
-
-    private void parseData() throws UnsupportedEncodingException, MalformedURLException {
-        if (parameters.containsKey("base64")) {
-            checkNoParamValue("base64");
-            data = BaseEncoding.base64().decode(remainder());
-        } else if (parameters.containsKey("base64url")) {
-            checkNoParamValue("base64url");
-            data = BaseEncoding.base64Url().decode(remainder());
-        } else {
-            data = URLDecoder.decode(remainder(), getCharset()).getBytes(Charset.forName(getCharset()));
-        }
-    }
-
-    private void checkNoParamValue(String param) throws MalformedURLException {
-        if (allowOtherLaxities) return; 
-        String value = parameters.get(param);
-        if (value!=null)
-            throw new MalformedURLException(param+" parameter must not take a value ("+value+") in data: URL");
-    }
-
-    private String remainder() {
-        return url.substring(parseIndex);
-    }
-
-    private boolean skipOptional(String word) {
-        if (remainder().startsWith(word)) {
-            parseIndex += word.length();
-            return true;
-        }
-        return false;
-    }
-
-    private void skipRequired(String word) throws MalformedURLException {
-        if (!remainder().startsWith(word))
-            throw new MalformedURLException("Missing required '"+word+"' at position "+parseIndex+" of data: URL");
-        parseIndex += word.length();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/text/TemplateProcessor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/text/TemplateProcessor.java b/core/src/main/java/brooklyn/util/text/TemplateProcessor.java
deleted file mode 100644
index eb0c2ad..0000000
--- a/core/src/main/java/brooklyn/util/text/TemplateProcessor.java
+++ /dev/null
@@ -1,397 +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 brooklyn.util.text;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.drivers.EntityDriver;
-import org.apache.brooklyn.api.event.AttributeSensor;
-import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.api.management.ManagementContext;
-import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.ConfigKeys;
-import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.EntityInternal;
-import brooklyn.event.basic.DependentConfiguration;
-import brooklyn.event.basic.Sensors;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-
-import com.google.common.base.Charsets;
-import com.google.common.collect.Iterables;
-import com.google.common.io.Files;
-
-import freemarker.cache.StringTemplateLoader;
-import freemarker.template.Configuration;
-import freemarker.template.ObjectWrapper;
-import freemarker.template.Template;
-import freemarker.template.TemplateHashModel;
-import freemarker.template.TemplateModel;
-import freemarker.template.TemplateModelException;
-
-/** A variety of methods to assist in Freemarker template processing,
- * including passing in maps with keys flattened (dot-separated namespace),
- * and accessing {@link ManagementContext} brooklyn.properties 
- * and {@link Entity}, {@link EntityDriver}, and {@link Location} methods and config.
- * <p>
- * See {@link #processTemplateContents(String, ManagementContextInternal, Map)} for
- * a description of how management access is done.
- */
-public class TemplateProcessor {
-
-    private static final Logger log = LoggerFactory.getLogger(TemplateProcessor.class);
-
-    protected static TemplateModel wrapAsTemplateModel(Object o) throws TemplateModelException {
-        if (o instanceof Map) return new DotSplittingTemplateModel((Map<?,?>)o);
-        return ObjectWrapper.DEFAULT_WRAPPER.wrap(o);
-    }
-    
-    /** @deprecated since 0.7.0 use {@link #processTemplateFile(String, Map)} */ @Deprecated
-    public static String processTemplate(String templateFileName, Map<String, ? extends Object> substitutions) {
-        return processTemplateFile(templateFileName, substitutions);
-    }
-    
-    /** As per {@link #processTemplateContents(String, Map)}, but taking a file. */
-    public static String processTemplateFile(String templateFileName, Map<String, ? extends Object> substitutions) {
-        String templateContents;
-        try {
-            templateContents = Files.toString(new File(templateFileName), Charsets.UTF_8);
-        } catch (IOException e) {
-            log.warn("Error loading file " + templateFileName, e);
-            throw Exceptions.propagate(e);
-        }
-        return processTemplateContents(templateContents, substitutions);
-    }
-
-    /** @deprecated since 0.7.0 use {@link #processTemplateFile(String, EntityDriver, Map)} */ @Deprecated
-    public static String processTemplate(String templateFileName, EntityDriver driver, Map<String, ? extends Object> extraSubstitutions) {
-        return processTemplateFile(templateFileName, driver, extraSubstitutions);
-    }
-    
-    /** Processes template contents according to {@link EntityAndMapTemplateModel}. */
-    public static String processTemplateFile(String templateFileName, EntityDriver driver, Map<String, ? extends Object> extraSubstitutions) {
-        String templateContents;
-        try {
-            templateContents = Files.toString(new File(templateFileName), Charsets.UTF_8);
-        } catch (IOException e) {
-            log.warn("Error loading file " + templateFileName, e);
-            throw Exceptions.propagate(e);
-        }
-        return processTemplateContents(templateContents, driver, extraSubstitutions);
-    }
-
-    /** Processes template contents according to {@link EntityAndMapTemplateModel}. */
-    public static String processTemplateContents(String templateContents, EntityDriver driver, Map<String,? extends Object> extraSubstitutions) {
-        return processTemplateContents(templateContents, new EntityAndMapTemplateModel(driver, extraSubstitutions));
-    }
-
-    /** Processes template contents according to {@link EntityAndMapTemplateModel}. */
-    public static String processTemplateContents(String templateContents, ManagementContext managementContext, Map<String,? extends Object> extraSubstitutions) {
-        return processTemplateContents(templateContents, new EntityAndMapTemplateModel(managementContext, extraSubstitutions));
-    }
-
-    /**
-     * A Freemarker {@link TemplateHashModel} which will correctly handle entries of the form "a.b" in this map,
-     * matching against template requests for "${a.b}".
-     * <p>
-     * Freemarker requests "a" in a map when given such a request, and expects that to point to a map
-     * with a key "b". This model provides such maps even for "a.b" in a map.
-     * <p>
-     * However if "a" <b>and</b> "a.b" are in the map, this will <b>not</b> currently do the deep mapping.
-     * (It does not have enough contextual information from Freemarker to handle this case.) */
-    public static final class DotSplittingTemplateModel implements TemplateHashModel {
-        protected final Map<?,?> map;
-
-        protected DotSplittingTemplateModel(Map<?,?> map) {
-            this.map = map;
-        }
-
-        @Override
-        public boolean isEmpty() { return map!=null && map.isEmpty(); }
-
-        public boolean contains(String key) {
-            if (map==null) return false;
-            if (map.containsKey(key)) return true;
-            for (Map.Entry<?,?> entry: map.entrySet()) {
-                String k = Strings.toString(entry.getKey());
-                if (k.startsWith(key+".")) {
-                    // contains this prefix
-                    return true;
-                }
-            }
-            return false;
-        }
-        
-        @Override
-        public TemplateModel get(String key) throws TemplateModelException {
-            if (map==null) return null;
-            try {
-                if (map.containsKey(key)) 
-                    return wrapAsTemplateModel( map.get(key) );
-                
-                Map<String,Object> result = MutableMap.of();
-                for (Map.Entry<?,?> entry: map.entrySet()) {
-                    String k = Strings.toString(entry.getKey());
-                    if (k.startsWith(key+".")) {
-                        String k2 = Strings.removeFromStart(k, key+".");
-                        result.put(k2, entry.getValue());
-                    }
-                }
-                if (!result.isEmpty()) 
-                        return wrapAsTemplateModel( result );
-                
-            } catch (Exception e) {
-                Exceptions.propagateIfFatal(e);
-                throw new IllegalStateException("Error accessing config '"+key+"'"+": "+e, e);
-            }
-            
-            return null;
-        }
-        
-        @Override
-        public String toString() {
-            return getClass().getName()+"["+map+"]";
-        }
-    }
-    
-    /** FreeMarker {@link TemplateHashModel} which resolves keys inside the given entity or management context.
-     * Callers are required to include dots for dot-separated keys.
-     * Freemarker will only due this when in inside bracket notation in an outer map, as in <code>${outer['a.b.']}</code>; 
-     * as a result this is intended only for use by {@link EntityAndMapTemplateModel} where 
-     * a caller has used bracked notation, as in <code>${mgmt['key.subkey']}</code>. */
-    protected static final class EntityConfigTemplateModel implements TemplateHashModel {
-        protected final EntityInternal entity;
-        protected final ManagementContext mgmt;
-
-        protected EntityConfigTemplateModel(EntityInternal entity) {
-            this.entity = entity;
-            this.mgmt = entity.getManagementContext();
-        }
-
-        protected EntityConfigTemplateModel(ManagementContext mgmt) {
-            this.entity = null;
-            this.mgmt = mgmt;
-        }
-
-        @Override
-        public boolean isEmpty() { return false; }
-
-        @Override
-        public TemplateModel get(String key) throws TemplateModelException {
-            try {
-                Object result = null;
-                
-                if (entity!=null)
-                    result = entity.getConfig(ConfigKeys.builder(Object.class).name(key).build());
-                if (result==null && mgmt!=null)
-                    result = mgmt.getConfig().getConfig(ConfigKeys.builder(Object.class).name(key).build());
-                
-                if (result!=null)
-                    return wrapAsTemplateModel( result );
-                
-            } catch (Exception e) {
-                Exceptions.propagateIfFatal(e);
-                throw new IllegalStateException("Error accessing config '"+key+"'"
-                    + (entity!=null ? " on "+entity : "")+": "+e, e);
-            }
-            
-            return null;
-        }
-        
-        @Override
-        public String toString() {
-            return getClass().getName()+"["+entity+"]";
-        }
-    }
-
-    protected final static class EntityAttributeTemplateModel implements TemplateHashModel {
-        protected final EntityInternal entity;
-
-        protected EntityAttributeTemplateModel(EntityInternal entity) {
-            this.entity = entity;
-        }
-
-        @Override
-        public boolean isEmpty() throws TemplateModelException {
-            return false;
-        }
-
-        @Override
-        public TemplateModel get(String key) throws TemplateModelException {
-            Object result;
-            try {
-                result = Entities.submit(entity, DependentConfiguration.attributeWhenReady(entity,
-                        Sensors.builder(Object.class, key).persistence(AttributeSensor.SensorPersistenceMode.NONE).build())).get();
-            } catch (Exception e) {
-                throw Exceptions.propagate(e);
-            }
-            if (result == null) {
-                return null;
-            } else {
-                return wrapAsTemplateModel(result);
-            }
-        }
-
-        @Override
-        public String toString() {
-            return getClass().getName()+"["+entity+"]";
-        }
-    }
-
-    /**
-     * Provides access to config on an entity or management context, using
-     * <code>${config['entity.config.key']}</code> or <code>${mgmt['brooklyn.properties.key']}</code> notation,
-     * and also allowing access to <code>getX()</code> methods on entity (interface) or driver
-     * using <code>${entity.x}</code> or <code><${driver.x}</code>.
-     * Optional extra properties can be supplied, treated as per {@link DotSplittingTemplateModel}.
-     */
-    protected static final class EntityAndMapTemplateModel implements TemplateHashModel {
-        protected final EntityInternal entity;
-        protected final EntityDriver driver;
-        protected final ManagementContext mgmt;
-        protected final DotSplittingTemplateModel extraSubstitutionsModel;
-
-        protected EntityAndMapTemplateModel(ManagementContext mgmt, Map<String,? extends Object> extraSubstitutions) {
-            this.entity = null;
-            this.driver = null;
-            this.mgmt = mgmt;
-            this.extraSubstitutionsModel = new DotSplittingTemplateModel(extraSubstitutions);
-        }
-
-        protected EntityAndMapTemplateModel(EntityDriver driver, Map<String,? extends Object> extraSubstitutions) {
-            this.driver = driver;
-            this.entity = (EntityInternal) driver.getEntity();
-            this.mgmt = entity.getManagementContext();
-            this.extraSubstitutionsModel = new DotSplittingTemplateModel(extraSubstitutions);
-        }
-
-        protected EntityAndMapTemplateModel(EntityInternal entity, Map<String,? extends Object> extraSubstitutions) {
-            this.entity = entity;
-            this.driver = null;
-            this.mgmt = entity.getManagementContext();
-            this.extraSubstitutionsModel = new DotSplittingTemplateModel(extraSubstitutions);
-        }
-
-        @Override
-        public boolean isEmpty() { return false; }
-
-        @Override
-        public TemplateModel get(String key) throws TemplateModelException {
-            if (extraSubstitutionsModel.contains(key))
-                return wrapAsTemplateModel( extraSubstitutionsModel.get(key) );
-
-            if ("entity".equals(key) && entity!=null)
-                return wrapAsTemplateModel( entity );
-            if ("config".equals(key)) {
-                if (entity!=null)
-                    return new EntityConfigTemplateModel(entity);
-                else
-                    return new EntityConfigTemplateModel(mgmt);
-            }
-            if ("mgmt".equals(key)) {
-                return new EntityConfigTemplateModel(mgmt);
-            }
-
-            if ("driver".equals(key) && driver!=null)
-                return wrapAsTemplateModel( driver );
-            if ("location".equals(key)) {
-                if (driver!=null && driver.getLocation()!=null)
-                    return wrapAsTemplateModel( driver.getLocation() );
-                if (entity!=null)
-                    return wrapAsTemplateModel( Iterables.getOnlyElement( entity.getLocations() ) );
-            }
-            if ("attribute".equals(key)) {
-                return new EntityAttributeTemplateModel(entity);
-            }
-            
-            if (mgmt!=null) {
-                // TODO deprecated in 0.7.0, remove after next version
-                // ie not supported to access global props without qualification
-                Object result = mgmt.getConfig().getConfig(ConfigKeys.builder(Object.class).name(key).build());
-                if (result!=null) { 
-                    log.warn("Deprecated access of global brooklyn.properties value for "+key+"; should be qualified with 'mgmt.'");
-                    return wrapAsTemplateModel( result );
-                }
-            }
-            
-            if ("javaSysProps".equals(key))
-                return wrapAsTemplateModel( System.getProperties() );
-
-            return null;
-        }
-        
-        @Override
-        public String toString() {
-            return getClass().getName()+"["+(entity!=null ? entity : mgmt)+"]";
-        }
-    }
-
-    /** Processes template contents with the given items in scope as per {@link EntityAndMapTemplateModel}. */
-    public static String processTemplateContents(String templateContents, final EntityInternal entity, Map<String,? extends Object> extraSubstitutions) {
-        return processTemplateContents(templateContents, new EntityAndMapTemplateModel(entity, extraSubstitutions));
-    }
-    
-    /** Processes template contents using the given map, passed to freemarker,
-     * with dot handling as per {@link DotSplittingTemplateModel}. */
-    public static String processTemplateContents(String templateContents, final Map<String, ? extends Object> substitutions) {
-        TemplateHashModel root;
-        try {
-            root = substitutions != null
-                ? (TemplateHashModel)wrapAsTemplateModel(substitutions)
-                : null;
-        } catch (TemplateModelException e) {
-            throw new IllegalStateException("Unable to set up TemplateHashModel to parse template, given "+substitutions+": "+e, e);
-        }
-        
-        return processTemplateContents(templateContents, root);
-    }
-    
-    /** Processes template contents against the given {@link TemplateHashModel}. */
-    public static String processTemplateContents(String templateContents, final TemplateHashModel substitutions) {
-        try {
-            Configuration cfg = new Configuration();
-            StringTemplateLoader templateLoader = new StringTemplateLoader();
-            templateLoader.putTemplate("config", templateContents);
-            cfg.setTemplateLoader(templateLoader);
-            Template template = cfg.getTemplate("config");
-
-            // TODO could expose CAMP '$brooklyn:' style dsl, based on template.createProcessingEnvironment
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            Writer out = new OutputStreamWriter(baos);
-            template.process(substitutions, out);
-            out.flush();
-
-            return new String(baos.toByteArray());
-        } catch (Exception e) {
-            log.warn("Error processing template (propagating): "+e, e);
-            log.debug("Template which could not be parsed (causing "+e+") is:"
-                + (Strings.isMultiLine(templateContents) ? "\n"+templateContents : templateContents));
-            throw Exceptions.propagate(e);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/CompilerIndependentOuterClassFieldMapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/CompilerIndependentOuterClassFieldMapper.java b/core/src/main/java/brooklyn/util/xstream/CompilerIndependentOuterClassFieldMapper.java
deleted file mode 100644
index f9a1f00..0000000
--- a/core/src/main/java/brooklyn/util/xstream/CompilerIndependentOuterClassFieldMapper.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 brooklyn.util.xstream;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.thoughtworks.xstream.core.Caching;
-import com.thoughtworks.xstream.mapper.Mapper;
-import com.thoughtworks.xstream.mapper.MapperWrapper;
-
-/**
- * <p>Compiler independent outer class field mapper.</p>
- * <p>Different compilers generate different indexes for the names of outer class reference
- *    field (this$N) leading to deserialization errors.</p>
- * <ul>
- *   <li> eclipse-[groovy-]compiler counts all outer static classes
- *   <li> OpenJDK/Oracle/IBM compiler starts at 0, regardless of the nesting level
- * </ul>
- * <p>The mapper will be able to update field names for instances with a single this$N
- *    field only (including those from parent classes).</p>
- * <p>For difference between generated field names compare
- *    {@code src/test/java/brooklyn/util/xstream/compiler_compatibility_eclipse.xml} and
- *    {@code src/test/java/brooklyn/util/xstream/compiler_compatibility_oracle.xml},
- *    generated from {@code brooklyn.util.xstream.CompilerCompatibilityTest}</p>
- * <p>JLS 1.1 relevant section, copied verbatim for a lack of reliable URL:</p>
- * <blockquote>
- *  <p>Java 1.1 compilers are strongly encouraged, though not required, to use the
- *     following naming conventions when implementing inner classes. Compilers may
- *     not use synthetic names of the forms defined here for any other purposes.</p>
- *  <p>A synthetic field pointing to the outermost enclosing instance is named this$0.
- *     The next-outermost enclosing instance is this$1, and so forth. (At most one such
- *     field is necessary in any given inner class.) A synthetic field containing a copy
- *     of a constant v is named val$v. These fields are final.</p>
- * </blockquote>
- * <p>Currently available at
- *    http://web.archive.org/web/20000830111107/http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc10.html</p>
- */
-public class CompilerIndependentOuterClassFieldMapper extends MapperWrapper implements Caching {
-    public static final Logger LOG = LoggerFactory.getLogger(CompilerIndependentOuterClassFieldMapper.class);
-
-    private static final String OUTER_CLASS_FIELD_PREFIX = "this$";
-
-    private final Map<String, Collection<String>> classOuterFields = new ConcurrentHashMap<String, Collection<String>>();
-
-    public CompilerIndependentOuterClassFieldMapper(Mapper wrapped) {
-        super(wrapped);
-        classOuterFields.put(Object.class.getName(), Collections.<String>emptyList());
-    }
-
-    @Override
-    public String realMember(@SuppressWarnings("rawtypes") Class type, String serialized) {
-        // Let com.thoughtworks.xstream.mapper.OuterClassMapper also run on the input.
-        String serializedFieldName = super.realMember(type, serialized);
-
-        if (serializedFieldName.startsWith(OUTER_CLASS_FIELD_PREFIX)) {
-            Collection<String> compiledFieldNames = findOuterClassFieldNames(type);
-            if (compiledFieldNames.size() == 0) {
-                throw new IllegalStateException("Unable to find any outer class fields in " + type + ", searching specifically for " + serializedFieldName);
-            }
-
-            Set<String> uniqueFieldNames = new HashSet<String>(compiledFieldNames);
-            String deserializeFieldName;
-            if (!compiledFieldNames.contains(serializedFieldName)) {
-                String msg =
-                        "Unable to find outer class field " + serializedFieldName + " in class " + type + ". " +
-                        "This could be caused by " +
-                        "1) changing the class (or one of its parents) to a static or " +
-                        "2) moving the class to a different lexical level (enclosing classes) or " +
-                        "3) using a different compiler (i.e eclipse vs oracle) at the time the object was serialized. ";
-                if (uniqueFieldNames.size() == 1) {
-                    // Try to fix the field naming only for the case with a single field or 
-                    // multiple fields with the same name, in which case XStream puts defined-in
-                    // for the field declared in super.
-                    //
-                    // We don't have access to the XML elements from here to check for same name
-                    // so we check the target class instead. This should work most of the time, but
-                    // if code is recompiled in such a way that the new instance has fields with
-                    // different names, where only the field of the extending class is renamed and
-                    // the super field is not, then the instance will be deserialized incorrectly -
-                    // the super field will be assigned both times. If the field type is incompatible
-                    // then a casting exception will be thrown, if it's the same then only the warning
-                    // below will indicate of a possible problem down the line - most probably NPE on
-                    // the this$N field.
-                    deserializeFieldName = compiledFieldNames.iterator().next();
-                    LOG.warn(msg + "Will use the field " + deserializeFieldName + " instead.");
-                } else {
-                    // Multiple fields with differing names case - don't try to fix it.
-                    // Better fail with an explicit error, and have someone fix it manually,
-                    // than try to fix it here non-reliably and have it fail down the line
-                    // with some unrelated error.
-                    // XStream will fail later with a field not found exception.
-                    LOG.error(msg + "Will fail with a field not found exception. " +
-                            "Edit the persistence state manually and update the field names. "+
-                            "Existing field names are " + uniqueFieldNames);
-                    deserializeFieldName = serializedFieldName;
-                }
-            } else {
-                if (uniqueFieldNames.size() > 1) {
-                    // Log at debug level as the actual problem would occur in very specific cases. Only
-                    // useful when the compiler is changed, otherwise leads to false positives.
-                    LOG.debug("Deserializing the non-static class " + type + " with multiple outer class fields " + uniqueFieldNames + ". " +
-                            "When changing compilers it's possible that the instance won't be able to be deserialized due to changed outer class field names. " +
-                            "In those cases deserialization could fail with field not found exception or class cast exception following this log line.");
-                }
-                deserializeFieldName = serializedFieldName;
-            }
-
-            return deserializeFieldName;
-        } else {
-            return serializedFieldName;
-        }
-    }
-    
-    private Collection<String> findOuterClassFieldNames(Class<?> type) {
-        Collection<String> fields = classOuterFields.get(type.getName());
-        if (fields == null) {
-            fields = new ArrayList<String>();
-            addOuterClassFields(type, fields);
-            classOuterFields.put(type.getName(), fields);
-        }
-        return fields;
-    }
-    
-    private void addOuterClassFields(Class<?> type, Collection<String> fields) {
-        for (Field field : type.getDeclaredFields()) {
-            if (field.isSynthetic()) {
-                fields.add(field.getName());
-            }
-        }
-        if (type.getSuperclass() != null) {
-            addOuterClassFields(type.getSuperclass(), fields);
-        }
-    }
-
-    @Override
-    public void flushCache() {
-        classOuterFields.keySet().retainAll(Collections.singletonList(Object.class.getName()));
-    }
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/EnumCaseForgivingConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/EnumCaseForgivingConverter.java b/core/src/main/java/brooklyn/util/xstream/EnumCaseForgivingConverter.java
deleted file mode 100644
index 96bafe6..0000000
--- a/core/src/main/java/brooklyn/util/xstream/EnumCaseForgivingConverter.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 brooklyn.util.xstream;
-
-import brooklyn.util.exceptions.Exceptions;
-
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.converters.enums.EnumConverter;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-
-/** ... except this doesn't seem to get applied when we think it should
- * (normal xstream.resgisterConverter doesn't apply to enums) */
-public class EnumCaseForgivingConverter extends EnumConverter {
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
-        Class type = context.getRequiredType();
-        if (type.getSuperclass() != Enum.class) {
-            type = type.getSuperclass(); // polymorphic enums
-        }
-        String token = reader.getValue();
-        // this is the new bit (overriding superclass to accept case-insensitive)
-        return resolve(type, token);
-    }
-
-    public static <T extends Enum<T>> T resolve(Class<T> type, String token) {
-        try {
-            return Enum.valueOf(type, token.toUpperCase());
-        } catch (Exception e) {
-            
-            // new stuff here:  try reading case insensitive
-            
-            Exceptions.propagateIfFatal(e);
-            try {
-                for (T v: type.getEnumConstants())
-                    if (v.name().equalsIgnoreCase(token)) return v;
-                throw e;
-            } catch (Exception e2) {
-                throw Exceptions.propagate(e2);
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/EnumCaseForgivingSingleValueConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/EnumCaseForgivingSingleValueConverter.java b/core/src/main/java/brooklyn/util/xstream/EnumCaseForgivingSingleValueConverter.java
deleted file mode 100644
index a7aba8c..0000000
--- a/core/src/main/java/brooklyn/util/xstream/EnumCaseForgivingSingleValueConverter.java
+++ /dev/null
@@ -1,35 +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 brooklyn.util.xstream;
-
-import com.thoughtworks.xstream.converters.enums.EnumSingleValueConverter;
-
-public class EnumCaseForgivingSingleValueConverter extends EnumSingleValueConverter {
-
-    private final Class enumType;
-
-    public EnumCaseForgivingSingleValueConverter(Class type) {
-        super(type);
-        enumType = type;
-    }
-
-    public Object fromString(String str) {
-        return EnumCaseForgivingConverter.resolve(enumType, str);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/ImmutableListConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/ImmutableListConverter.java b/core/src/main/java/brooklyn/util/xstream/ImmutableListConverter.java
deleted file mode 100644
index df33142..0000000
--- a/core/src/main/java/brooklyn/util/xstream/ImmutableListConverter.java
+++ /dev/null
@@ -1,54 +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 brooklyn.util.xstream;
-
-import java.util.Collection;
-
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.converters.collections.CollectionConverter;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-import com.thoughtworks.xstream.mapper.Mapper;
-
-public class ImmutableListConverter extends CollectionConverter {
-
-    public ImmutableListConverter(Mapper mapper) {
-        super(mapper);
-    }
-
-    @Override
-    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
-        return ImmutableList.class.isAssignableFrom(type);
-    }
-
-    // marshalling is the same
-    // so is unmarshalling the entries
-
-    // only differences are creating the overarching collection, which we do after the fact
-    // (optimizing format on disk as opposed to in-memory), and we discard null values 
-    // to avoid failing entirely.
-    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
-        Collection<?> collection = Lists.newArrayList();
-        populateCollection(reader, context, collection);
-        return ImmutableList.copyOf(Iterables.filter(collection, Predicates.notNull()));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/ImmutableMapConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/ImmutableMapConverter.java b/core/src/main/java/brooklyn/util/xstream/ImmutableMapConverter.java
deleted file mode 100644
index aa8ca4c..0000000
--- a/core/src/main/java/brooklyn/util/xstream/ImmutableMapConverter.java
+++ /dev/null
@@ -1,56 +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 brooklyn.util.xstream;
-
-import java.util.Map;
-import java.util.Map.Entry;
-
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-import com.thoughtworks.xstream.mapper.Mapper;
-
-public class ImmutableMapConverter extends MapConverter {
-
-    public ImmutableMapConverter(Mapper mapper) {
-        super(mapper);
-    }
-
-    @Override
-    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
-        return ImmutableMap.class.isAssignableFrom(type);
-    }
-
-    // marshalling is the same
-    // so is unmarshalling the entries
-
-    // only differences are creating the overarching collection, which we do after the fact
-    // (optimizing format on disk as opposed to in-memory), and we discard null key/values 
-    // to avoid failing entirely.
-    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
-        Map<?, ?> map = Maps.newLinkedHashMap();
-        populateMap(reader, context, map);
-        return ImmutableMap.copyOf(Maps.filterEntries(map, new Predicate<Map.Entry<?,?>>() {
-                @Override public boolean apply(Entry<?, ?> input) {
-                    return input != null && input.getKey() != null && input.getValue() != null;
-                }}));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/ImmutableSetConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/ImmutableSetConverter.java b/core/src/main/java/brooklyn/util/xstream/ImmutableSetConverter.java
deleted file mode 100644
index 11ee3ce..0000000
--- a/core/src/main/java/brooklyn/util/xstream/ImmutableSetConverter.java
+++ /dev/null
@@ -1,54 +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 brooklyn.util.xstream;
-
-import java.util.Collection;
-
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.converters.collections.CollectionConverter;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-import com.thoughtworks.xstream.mapper.Mapper;
-
-public class ImmutableSetConverter extends CollectionConverter {
-
-    public ImmutableSetConverter(Mapper mapper) {
-        super(mapper);
-    }
-
-    @Override
-    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
-        return ImmutableSet.class.isAssignableFrom(type);
-    }
-
-    // marshalling is the same
-    // so is unmarshalling the entries
-
-    // only differences are creating the overarching collection, which we do after the fact
-    // (optimizing format on disk as opposed to in-memory), and we discard null values 
-    // to avoid failing entirely.
-    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
-        Collection<?> collection = Lists.newArrayList();
-        populateCollection(reader, context, collection);
-        return ImmutableSet.copyOf(Iterables.filter(collection, Predicates.notNull()));
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/Inet4AddressConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/Inet4AddressConverter.java b/core/src/main/java/brooklyn/util/xstream/Inet4AddressConverter.java
deleted file mode 100644
index dbd704b..0000000
--- a/core/src/main/java/brooklyn/util/xstream/Inet4AddressConverter.java
+++ /dev/null
@@ -1,65 +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 brooklyn.util.xstream;
-
-import java.net.Inet4Address;
-import java.net.UnknownHostException;
-
-import brooklyn.util.exceptions.Exceptions;
-
-import com.thoughtworks.xstream.converters.Converter;
-import com.thoughtworks.xstream.converters.MarshallingContext;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-
-public class Inet4AddressConverter implements Converter {
-
-    @Override
-    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
-        return type.equals(Inet4Address.class);
-    }
-
-    @Override
-    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
-        Inet4Address addr = (Inet4Address) source;
-        writer.setValue(addr.getHostName()+"/"+addr.getHostAddress());
-    }
-
-    @Override
-    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
-        String hostSlashAddress = reader.getValue();
-        int i = hostSlashAddress.indexOf('/');
-        try {
-            if (i==-1) {
-                return Inet4Address.getByName(hostSlashAddress);
-            } else {
-                String host = hostSlashAddress.substring(0, i);
-                String addrS = hostSlashAddress.substring(i+1);
-                byte[] addr = new byte[4];
-                String[] addrSI = addrS.split("\\.");
-                for (int k=0; k<4; k++) addr[k] = (byte)(int)Integer.valueOf(addrSI[k]);
-                return Inet4Address.getByAddress(host, addr);
-            }
-        } catch (UnknownHostException e) {
-            throw Exceptions.propagate(e);
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/MapConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/MapConverter.java b/core/src/main/java/brooklyn/util/xstream/MapConverter.java
deleted file mode 100644
index 5ee2a6a..0000000
--- a/core/src/main/java/brooklyn/util/xstream/MapConverter.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 brooklyn.util.xstream;
-
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.Map;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.thoughtworks.xstream.converters.MarshallingContext;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.core.ReferencingMarshallingContext;
-import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-import com.thoughtworks.xstream.mapper.Mapper;
-
-/** equivalent to super, but cleaner methods, overridable, logging, and some retries */
-public class MapConverter extends com.thoughtworks.xstream.converters.collections.MapConverter {
-
-    private static final Logger log = LoggerFactory.getLogger(MapConverter.class);
-    
-    public MapConverter(Mapper mapper) {
-        super(mapper);
-    }
-
-    @SuppressWarnings({ "rawtypes" })
-    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
-        Map map = (Map) source;
-        try {
-            for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
-                Map.Entry entry = (Map.Entry) iterator.next();
-                marshalEntry(writer, context, entry);
-            }
-        } catch (ConcurrentModificationException e) {
-            log.debug("Map "
-                // seems there is no non-deprecated way to get the path...
-                + (context instanceof ReferencingMarshallingContext ? "at "+((ReferencingMarshallingContext)context).currentPath() : "")
-                + "["+source+"] modified while serializing; will fail, and retry may be attempted");
-            throw e;
-            // would be nice to attempt to re-serialize being slightly more defensive, as code below;
-            // but the code above may have written partial data so that is dangerous, we could have corrupted output. 
-            // if we could mark and restore in the output stream then we could do this below (but we don't have that in our stream),
-            // or we could try this copying code in the first instance (but that's slow);
-            // error is rare most of the time (e.g. attribute being updated) so we bail on this whole attempt
-            // and simply try serializing the map-owner (e.g. an entity) again.
-//            ImmutableList entries = ImmutableList.copyOf(map.entrySet());
-//            for (Iterator iterator = entries.iterator(); iterator.hasNext();) {
-//                Map.Entry entry = (Map.Entry) iterator.next();
-//                marshalEntry(writer, context, entry);                
-//            }
-        }
-    }
-
-    protected String getEntryNodeName() { return mapper().serializedClass(Map.Entry.class); }
-    
-    protected void marshalEntry(HierarchicalStreamWriter writer, MarshallingContext context, Map.Entry entry) {
-        ExtendedHierarchicalStreamWriterHelper.startNode(writer, getEntryNodeName(), Map.Entry.class);
-
-        writeItem(entry.getKey(), context, writer);
-        writeItem(entry.getValue(), context, writer);
-
-        writer.endNode();
-    }
-
-    protected void populateMap(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) {
-        while (reader.hasMoreChildren()) {
-            reader.moveDown();
-            unmarshalEntry(reader, context, map);
-            reader.moveUp();
-        }
-    }
-
-    protected void unmarshalEntry(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) {
-        reader.moveDown();
-        Object key = readItem(reader, context, map);
-        reader.moveUp();
-
-        reader.moveDown();
-        Object value = readItem(reader, context, map);
-        reader.moveUp();
-
-        map.put(key, value);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/MutableSetConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/MutableSetConverter.java b/core/src/main/java/brooklyn/util/xstream/MutableSetConverter.java
deleted file mode 100644
index 3432751..0000000
--- a/core/src/main/java/brooklyn/util/xstream/MutableSetConverter.java
+++ /dev/null
@@ -1,44 +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 brooklyn.util.xstream;
-
-import brooklyn.util.collections.MutableSet;
-
-import com.thoughtworks.xstream.converters.collections.CollectionConverter;
-import com.thoughtworks.xstream.mapper.Mapper;
-
-public class MutableSetConverter extends CollectionConverter {
-
-    // Although this class seems pointless (!), without registering an explicit converter for MutableSet then the
-    // declaration for Set interferes, causing MutableSet.map field to be null on deserialization.
-    
-    public MutableSetConverter(Mapper mapper) {
-        super(mapper);
-    }
-
-    @Override
-    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
-        return MutableSet.class.isAssignableFrom(type);
-    }
-
-    @Override
-    protected Object createCollection(Class type) {
-        return new MutableSet<Object>();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/StringKeyMapConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/StringKeyMapConverter.java b/core/src/main/java/brooklyn/util/xstream/StringKeyMapConverter.java
deleted file mode 100644
index 26aba7a..0000000
--- a/core/src/main/java/brooklyn/util/xstream/StringKeyMapConverter.java
+++ /dev/null
@@ -1,134 +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 brooklyn.util.xstream;
-
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.exceptions.Exceptions;
-import brooklyn.util.flags.TypeCoercions;
-import brooklyn.util.text.Identifiers;
-
-import com.thoughtworks.xstream.converters.MarshallingContext;
-import com.thoughtworks.xstream.converters.UnmarshallingContext;
-import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
-import com.thoughtworks.xstream.io.HierarchicalStreamReader;
-import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
-import com.thoughtworks.xstream.mapper.Mapper;
-
-/** converter which simplifies representation of a map for string-based keys,
- * to <key>value</key>, or <entry key="key" type="string">value</entry> 
- * @author alex
- *
- */
-public class StringKeyMapConverter extends MapConverter {
-
-    private static final Logger log = LoggerFactory.getLogger(StringKeyMapConverter.class);
-    
-    // full stop is technically allowed ... goes against "best practice" ... 
-    // but simplifies property maps, and is used elsewhere in xstream's repn
-    final static String VALID_XML_NODE_NAME_CHARS = Identifiers.JAVA_GOOD_NONSTART_CHARS + ".";
-
-    final static String VALID_XML_NODE_NAME_START_CHARS = Identifiers.JAVA_GOOD_START_CHARS + ".";
-
-    public StringKeyMapConverter(Mapper mapper) {
-        super(mapper);
-    }
-    
-    protected boolean isKeyValidForNodeName(String key) {
-        // return false to always write as <entry key="key" ...; otherwise only use that when key is not valid xml
-        return Identifiers.isValidToken(key, VALID_XML_NODE_NAME_START_CHARS, VALID_XML_NODE_NAME_CHARS);
-    }
-    
-    public boolean canConvert(Class type) {
-        return super.canConvert(type) || type.getName().equals(MutableMap.class.getName());
-    }
-    
-    @Override
-    protected void marshalEntry(HierarchicalStreamWriter writer, MarshallingContext context, Entry entry) {
-        if (entry.getKey() instanceof String) {
-            marshalStringKey(writer, context, entry);
-        } else {
-            super.marshalEntry(writer, context, entry);
-        }
-    }
-    
-    protected void marshalStringKey(HierarchicalStreamWriter writer, MarshallingContext context, Entry entry) {
-        String key = (String)entry.getKey();
-        String entryNodeName = getEntryNodeName();
-        boolean useKeyAsNodeName = (!key.equals(entryNodeName) && isKeyValidForNodeName(key));
-        if (useKeyAsNodeName) entryNodeName = key;
-        ExtendedHierarchicalStreamWriterHelper.startNode(writer, entryNodeName, Map.Entry.class);
-        if (!useKeyAsNodeName)
-            writer.addAttribute("key", key);
-        
-        Object value = entry.getValue();
-        if (entry.getValue()!=null && isInlineableType(value.getClass())) {
-            if (!(value instanceof String))
-                writer.addAttribute("type", mapper().serializedClass(entry.getValue().getClass()));
-            if (entry.getValue().getClass().isEnum())
-                writer.setValue(((Enum)entry.getValue()).name());
-            else
-                writer.setValue(""+entry.getValue());
-        } else {
-            writeItem(entry.getValue(), context, writer);
-        }
-        
-        writer.endNode();
-    }
-
-    protected boolean isInlineableType(Class<?> type) {
-        return TypeCoercions.isPrimitiveOrBoxer(type) || String.class.equals(type) || type.isEnum();
-    }
-    
-    @Override
-    protected void unmarshalEntry(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) {
-        String key = reader.getNodeName(); 
-        if (key.equals(getEntryNodeName())) key = reader.getAttribute("key");
-        if (key==null) {
-            super.unmarshalEntry(reader, context, map);
-        } else {
-            unmarshalStringKey(reader, context, map, key);
-        }
-    }
-
-    protected void unmarshalStringKey(HierarchicalStreamReader reader, UnmarshallingContext context, Map map, String key) {
-        String type = reader.getAttribute("type");
-        Object value;
-        if (type==null && reader.hasMoreChildren()) {
-            reader.moveDown();
-            value = readItem(reader, context, map);
-            reader.moveUp();
-        } else {
-            Class typeC = type!=null ? mapper().realClass(type) : String.class;
-            try {
-                value = TypeCoercions.coerce(reader.getValue(), typeC);
-            } catch (Exception e) {
-                log.warn("FAILED to coerce "+reader.getValue()+" to "+typeC+": "+e);
-                throw Exceptions.propagate(e);
-            }
-        }
-        map.put(key, value);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/brooklyn/util/xstream/XmlSerializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/xstream/XmlSerializer.java b/core/src/main/java/brooklyn/util/xstream/XmlSerializer.java
deleted file mode 100644
index 7220254..0000000
--- a/core/src/main/java/brooklyn/util/xstream/XmlSerializer.java
+++ /dev/null
@@ -1,97 +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 brooklyn.util.xstream;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-import brooklyn.util.collections.MutableList;
-import brooklyn.util.collections.MutableMap;
-import brooklyn.util.collections.MutableSet;
-
-import com.google.common.collect.ImmutableList;
-import com.thoughtworks.xstream.XStream;
-import com.thoughtworks.xstream.mapper.MapperWrapper;
-
-public class XmlSerializer<T> {
-
-    protected final XStream xstream;
-    
-    public XmlSerializer() {
-        xstream = new XStream() {
-            @Override
-            protected MapperWrapper wrapMapper(MapperWrapper next) {
-                MapperWrapper result = super.wrapMapper(next);
-                return XmlSerializer.this.wrapMapper(result);
-            }
-        };
-        
-        // list as array list is default
-        xstream.alias("map", Map.class, LinkedHashMap.class);
-        xstream.alias("set", Set.class, LinkedHashSet.class);
-        
-        xstream.registerConverter(new StringKeyMapConverter(xstream.getMapper()), /* priority */ 10);
-        xstream.alias("MutableMap", MutableMap.class);
-        xstream.alias("MutableSet", MutableSet.class);
-        xstream.alias("MutableList", MutableList.class);
-        
-        // Needs an explicit MutableSet converter!
-        // Without it, the alias for "set" seems to interfere with the MutableSet.map field, so it gets
-        // a null field on deserialization.
-        xstream.registerConverter(new MutableSetConverter(xstream.getMapper()));
-        
-        xstream.aliasType("ImmutableList", ImmutableList.class);
-        xstream.registerConverter(new ImmutableListConverter(xstream.getMapper()));
-        xstream.registerConverter(new ImmutableSetConverter(xstream.getMapper()));
-        xstream.registerConverter(new ImmutableMapConverter(xstream.getMapper()));
-
-        xstream.registerConverter(new EnumCaseForgivingConverter());
-        xstream.registerConverter(new Inet4AddressConverter());
-    }
-    
-    protected MapperWrapper wrapMapper(MapperWrapper next) {
-        return new CompilerIndependentOuterClassFieldMapper(next);
-    }
-
-    public void serialize(Object object, Writer writer) {
-        xstream.toXML(object, writer);
-    }
-
-    @SuppressWarnings("unchecked")
-    public T deserialize(Reader xml) {
-        return (T) xstream.fromXML(xml);
-    }
-
-    public String toString(T memento) {
-        Writer writer = new StringWriter();
-        serialize(memento, writer);
-        return writer.toString();
-    }
-
-    public T fromString(String xml) {
-        return deserialize(new StringReader(xml));
-    }
-
-}


[17/64] incubator-brooklyn git commit: [BROOKLYN-162] Refactor package in ./core/util

Posted by he...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/ExecWithLoggingHelpers.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/ExecWithLoggingHelpers.java b/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/ExecWithLoggingHelpers.java
new file mode 100644
index 0000000..9e96674
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/ExecWithLoggingHelpers.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.util.task.system.internal;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+
+import brooklyn.config.ConfigKey;
+
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.apache.brooklyn.core.util.internal.ssh.ShellAbstractTool;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.task.Tasks;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.stream.StreamGobbler;
+import brooklyn.util.stream.Streams;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Function;
+import com.google.common.base.Throwables;
+
+public abstract class ExecWithLoggingHelpers {
+
+    public static final ConfigKey<OutputStream> STDOUT = SshMachineLocation.STDOUT;
+    public static final ConfigKey<OutputStream> STDERR = SshMachineLocation.STDERR;
+    public static final ConfigKey<Boolean> NO_STDOUT_LOGGING = SshMachineLocation.NO_STDOUT_LOGGING;
+    public static final ConfigKey<Boolean> NO_STDERR_LOGGING = SshMachineLocation.NO_STDERR_LOGGING;
+    public static final ConfigKey<String> LOG_PREFIX = SshMachineLocation.LOG_PREFIX;
+
+    protected final String shortName;
+    protected Logger commandLogger = null;
+    
+    public interface ExecRunner {
+        public int exec(ShellTool ssh, Map<String,?> flags, List<String> cmds, Map<String,?> env);
+    }
+
+    protected abstract <T> T execWithTool(MutableMap<String, Object> toolCreationAndConnectionProperties, Function<ShellTool, T> runMethodOnTool);
+    protected abstract void preExecChecks();
+    protected abstract String getTargetName();
+    protected abstract String constructDefaultLoggingPrefix(ConfigBag execFlags);
+
+    /** takes a very short name for use in blocking details, e.g. SSH or Process */
+    public ExecWithLoggingHelpers(String shortName) {
+        this.shortName = shortName;
+    }
+
+    public ExecWithLoggingHelpers logger(Logger commandLogger) {
+        this.commandLogger = commandLogger;
+        return this;
+    }
+    
+    public int execScript(Map<String,?> props, String summaryForLogging, List<String> commands, Map<String,?> env) {
+        // TODO scriptHeader are the extra commands we expect the SshTool/ShellTool to add.
+        // Would be better if could get this from the ssh-tool, rather than assuming it will behave as
+        // we expect.
+        String scriptHeader = ShellAbstractTool.getOptionalVal(props, ShellTool.PROP_SCRIPT_HEADER);
+        
+        return execWithLogging(props, summaryForLogging, commands, env, scriptHeader, new ExecRunner() {
+                @Override public int exec(ShellTool ssh, Map<String, ?> flags, List<String> cmds, Map<String, ?> env) {
+                    return ssh.execScript(flags, cmds, env);
+                }});
+    }
+
+    protected static <T> T getOptionalVal(Map<String,?> map, ConfigKey<T> keyC) {
+        if (keyC==null) return null;
+        String key = keyC.getName();
+        if (map!=null && map.containsKey(key)) {
+            return TypeCoercions.coerce(map.get(key), keyC.getTypeToken());
+        } else {
+            return keyC.getDefaultValue();
+        }
+    }
+
+    public int execCommands(Map<String,?> props, String summaryForLogging, List<String> commands, Map<String,?> env) {
+        return execWithLogging(props, summaryForLogging, commands, env, new ExecRunner() {
+                @Override public int exec(ShellTool tool, Map<String,?> flags, List<String> cmds, Map<String,?> env) {
+                    return tool.execCommands(flags, cmds, env);
+                }});
+    }
+
+    public int execWithLogging(Map<String,?> props, final String summaryForLogging, final List<String> commands,
+            final Map<String,?> env, final ExecRunner execCommand) {
+        return execWithLogging(props, summaryForLogging, commands, env, null, execCommand);
+    }
+    
+    @SuppressWarnings("resource")
+    public int execWithLogging(Map<String,?> props, final String summaryForLogging, final List<String> commands,
+            final Map<String,?> env, String expectedCommandHeaders, final ExecRunner execCommand) {
+        if (commandLogger!=null && commandLogger.isDebugEnabled()) {
+            String allcmds = (Strings.isBlank(expectedCommandHeaders) ? "" : expectedCommandHeaders + " ; ") + Strings.join(commands, " ; ");
+            commandLogger.debug("{}, initiating "+shortName.toLowerCase()+" on machine {}{}: {}",
+                    new Object[] {summaryForLogging, getTargetName(),
+                    env!=null && !env.isEmpty() ? " (env "+env+")": "", allcmds});
+        }
+
+        if (commands.isEmpty()) {
+            if (commandLogger!=null && commandLogger.isDebugEnabled())
+                commandLogger.debug("{}, on machine {}, ending: no commands to run", summaryForLogging, getTargetName());
+            return 0;
+        }
+
+        final ConfigBag execFlags = new ConfigBag().putAll(props);
+        // some props get overridden in execFlags, so remove them from the tool flags
+        final ConfigBag toolFlags = new ConfigBag().putAll(props).removeAll(
+                LOG_PREFIX, STDOUT, STDERR, ShellTool.PROP_NO_EXTRA_OUTPUT);
+
+        execFlags.configure(ShellTool.PROP_SUMMARY, summaryForLogging);
+        
+        PipedOutputStream outO = null;
+        PipedOutputStream outE = null;
+        StreamGobbler gO=null, gE=null;
+        try {
+            preExecChecks();
+            
+            String logPrefix = execFlags.get(LOG_PREFIX);
+            if (logPrefix==null) logPrefix = constructDefaultLoggingPrefix(execFlags);
+
+            if (!execFlags.get(NO_STDOUT_LOGGING)) {
+                PipedInputStream insO = new PipedInputStream();
+                outO = new PipedOutputStream(insO);
+
+                String stdoutLogPrefix = "["+(logPrefix != null ? logPrefix+":stdout" : "stdout")+"] ";
+                gO = new StreamGobbler(insO, execFlags.get(STDOUT), commandLogger).setLogPrefix(stdoutLogPrefix);
+                gO.start();
+
+                execFlags.put(STDOUT, outO);
+            }
+
+            if (!execFlags.get(NO_STDERR_LOGGING)) {
+                PipedInputStream insE = new PipedInputStream();
+                outE = new PipedOutputStream(insE);
+
+                String stderrLogPrefix = "["+(logPrefix != null ? logPrefix+":stderr" : "stderr")+"] ";
+                gE = new StreamGobbler(insE, execFlags.get(STDERR), commandLogger).setLogPrefix(stderrLogPrefix);
+                gE.start();
+
+                execFlags.put(STDERR, outE);
+            }
+
+            Tasks.setBlockingDetails(shortName+" executing, "+summaryForLogging);
+            try {
+                return execWithTool(MutableMap.copyOf(toolFlags.getAllConfig()), new Function<ShellTool, Integer>() {
+                    public Integer apply(ShellTool tool) {
+                        int result = execCommand.exec(tool, MutableMap.copyOf(execFlags.getAllConfig()), commands, env);
+                        if (commandLogger!=null && commandLogger.isDebugEnabled()) 
+                            commandLogger.debug("{}, on machine {}, completed: return status {}",
+                                    new Object[] {summaryForLogging, getTargetName(), result});
+                        return result;
+                    }});
+
+            } finally {
+                Tasks.setBlockingDetails(null);
+            }
+
+        } catch (IOException e) {
+            if (commandLogger!=null && commandLogger.isDebugEnabled()) 
+                commandLogger.debug("{}, on machine {}, failed: {}", new Object[] {summaryForLogging, getTargetName(), e});
+            throw Throwables.propagate(e);
+        } finally {
+            // Must close the pipedOutStreams, otherwise input will never read -1 so StreamGobbler thread would never die
+            if (outO!=null) try { outO.flush(); } catch (IOException e) {}
+            if (outE!=null) try { outE.flush(); } catch (IOException e) {}
+            Streams.closeQuietly(outO);
+            Streams.closeQuietly(outE);
+
+            try {
+                if (gE!=null) { gE.join(); }
+                if (gO!=null) { gO.join(); }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                Throwables.propagate(e);
+            }
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/SystemProcessTaskFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/SystemProcessTaskFactory.java b/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/SystemProcessTaskFactory.java
new file mode 100644
index 0000000..4a6dacb
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/task/system/internal/SystemProcessTaskFactory.java
@@ -0,0 +1,131 @@
+/*
+ * 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.util.task.system.internal;
+
+import java.io.File;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.brooklyn.core.util.config.ConfigBag;
+import org.apache.brooklyn.core.util.internal.ssh.ShellTool;
+import org.apache.brooklyn.core.util.internal.ssh.process.ProcessTool;
+import org.apache.brooklyn.core.util.task.system.ProcessTaskWrapper;
+import org.apache.brooklyn.location.basic.SshMachineLocation;
+
+import brooklyn.util.collections.MutableMap;
+
+import com.google.common.base.Function;
+
+public class SystemProcessTaskFactory<T extends SystemProcessTaskFactory<T,RET>,RET> extends AbstractProcessTaskFactory<T, RET> {
+
+    private static final Logger log = LoggerFactory.getLogger(SystemProcessTaskFactory.class);
+    
+    // FIXME Plum this through?!
+    private File directory;
+    private Boolean loginShell;
+
+    public SystemProcessTaskFactory(String ...commands) {
+        super(commands);
+    }
+    
+    public T directory(File directory) {
+        markDirty();
+        this.directory = directory;
+        return self();
+    }
+    
+    public T loginShell(boolean loginShell) {
+        markDirty();
+        this.loginShell = loginShell;
+        return self();
+    }
+    
+    @Override
+    public T machine(SshMachineLocation machine) {
+        log.warn("Not permitted to set machines on "+this+" (ignoring - "+machine+")");
+        if (log.isDebugEnabled())
+            log.debug("Source of attempt to set machines on "+this+" ("+machine+")",
+                    new Throwable("Source of attempt to set machines on "+this+" ("+machine+")"));
+        return self();
+    }
+
+    @Override
+    public ProcessTaskWrapper<RET> newTask() {
+        return new SystemProcessTaskWrapper();
+    }
+
+    protected class SystemProcessTaskWrapper extends ProcessTaskWrapper<RET> {
+        protected final String taskTypeShortName;
+        
+        public SystemProcessTaskWrapper() {
+            this("Process");
+        }
+        public SystemProcessTaskWrapper(String taskTypeShortName) {
+            super(SystemProcessTaskFactory.this);
+            this.taskTypeShortName = taskTypeShortName;
+        }
+        @Override
+        protected ConfigBag getConfigForRunning() {
+            ConfigBag result = super.getConfigForRunning();
+            if (directory != null) config.put(ProcessTool.PROP_DIRECTORY, directory.getAbsolutePath());
+            if (loginShell != null) config.put(ProcessTool.PROP_LOGIN_SHELL, loginShell);
+            return result;
+        }
+        @Override
+        protected void run(ConfigBag config) {
+            if (Boolean.FALSE.equals(this.runAsScript)) {
+                this.exitCode = newExecWithLoggingHelpers().execCommands(config.getAllConfig(), getSummary(), getCommands(), getShellEnvironment());
+            } else { // runScript = null or TRUE
+                this.exitCode = newExecWithLoggingHelpers().execScript(config.getAllConfig(), getSummary(), getCommands(), getShellEnvironment());
+            }
+        }
+        @Override
+        protected String taskTypeShortName() { return taskTypeShortName; }
+    }
+    
+    protected ExecWithLoggingHelpers newExecWithLoggingHelpers() {
+        return new ExecWithLoggingHelpers("Process") {
+            @Override
+            protected <U> U execWithTool(MutableMap<String, Object> props, Function<ShellTool, U> task) {
+                // properties typically passed to both
+                if (log.isDebugEnabled() && props!=null && !props.isEmpty())
+                    log.debug("Ignoring flags "+props+" when running "+this);
+                return task.apply(new ProcessTool());
+            }
+            @Override
+            protected void preExecChecks() {}
+            @Override
+            protected String constructDefaultLoggingPrefix(ConfigBag execFlags) {
+                return "system.exec";
+            }
+            @Override
+            protected String getTargetName() {
+                return "local host";
+            }
+        }.logger(log);
+    }
+
+    /** concrete instance (for generics) */
+    public static class ConcreteSystemProcessTaskFactory<RET> extends SystemProcessTaskFactory<ConcreteSystemProcessTaskFactory<RET>, RET> {
+        public ConcreteSystemProcessTaskFactory(String ...commands) {
+            super(commands);
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/text/DataUriSchemeParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/text/DataUriSchemeParser.java b/core/src/main/java/org/apache/brooklyn/core/util/text/DataUriSchemeParser.java
new file mode 100644
index 0000000..d4ed26c
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/text/DataUriSchemeParser.java
@@ -0,0 +1,267 @@
+/*
+ * 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.util.text;
+
+import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URLDecoder;
+import java.nio.charset.Charset;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import brooklyn.util.exceptions.Exceptions;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.io.BaseEncoding;
+//import com.sun.jersey.core.util.Base64;
+
+/** implementation (currently hokey) of RFC-2397 data: URI scheme.
+ * see: http://stackoverflow.com/questions/12353552/any-rfc-2397-data-uri-parser-for-java */
+public class DataUriSchemeParser {
+
+    public static final String PROTOCOL_PREFIX = "data:";
+    public static final String DEFAULT_MIME_TYPE = "text/plain";
+    public static final String DEFAULT_CHARSET = "US-ASCII";
+    
+    private final String url;
+    private int parseIndex = 0;
+    private boolean isParsed = false;
+    private boolean allowMissingComma = false;
+    private boolean allowSlashesAfterColon = false;
+    private boolean allowOtherLaxities = false;
+    
+    private String mimeType;
+    private byte[] data;
+    private Map<String,String> parameters = new LinkedHashMap<String,String>();
+
+    public DataUriSchemeParser(String url) {
+        this.url = Preconditions.checkNotNull(url, "url");
+    }
+
+    // ---- static conveniences -----
+    
+    public static String toString(String url) {
+        return new DataUriSchemeParser(url).lax().parse().getDataAsString();
+    }
+
+    public static byte[] toBytes(String url) {
+        return new DataUriSchemeParser(url).lax().parse().getData();
+    }
+
+    // ---- accessors (once it is parsed) -----------
+    
+    public String getCharset() {
+        String charset = parameters.get("charset");
+        if (charset!=null) return charset;
+        return DEFAULT_CHARSET;
+    }
+
+    public String getMimeType() {
+        assertParsed();
+        if (mimeType!=null) return mimeType;
+        return DEFAULT_MIME_TYPE;
+    }
+    
+    public Map<String, String> getParameters() {
+        return ImmutableMap.<String, String>copyOf(parameters);
+    }
+
+    public byte[] getData() {
+        assertParsed();
+        return data;
+    }
+    
+    public ByteArrayInputStream getDataAsInputStream() {
+        return new ByteArrayInputStream(getData());
+    }
+
+    public String getDataAsString() {
+        return new String(getData(), Charset.forName(getCharset()));
+    }
+
+    // ---- config ------------------
+    
+    public synchronized DataUriSchemeParser lax() {
+        return allowMissingComma(true).allowSlashesAfterColon(true).allowOtherLaxities(true);
+    }
+        
+    public synchronized DataUriSchemeParser allowMissingComma(boolean allowMissingComma) {
+        assertNotParsed();
+        this.allowMissingComma = allowMissingComma;
+        return this;
+    }
+    
+    public synchronized DataUriSchemeParser allowSlashesAfterColon(boolean allowSlashesAfterColon) {
+        assertNotParsed();
+        this.allowSlashesAfterColon = allowSlashesAfterColon;
+        return this;
+    }
+    
+    private synchronized DataUriSchemeParser allowOtherLaxities(boolean allowOtherLaxities) {
+        assertNotParsed();
+        this.allowOtherLaxities = allowOtherLaxities;
+        return this;
+    }
+    
+    private void assertNotParsed() {
+        if (isParsed) throw new IllegalStateException("Operation not permitted after parsing");
+    }
+
+    private void assertParsed() {
+        if (!isParsed) throw new IllegalStateException("Operation not permitted before parsing");
+    }
+
+    public synchronized DataUriSchemeParser parse() {
+        try {
+            return parseChecked();
+        } catch (Exception e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+    
+    public synchronized DataUriSchemeParser parseChecked() throws UnsupportedEncodingException, MalformedURLException {
+        if (isParsed) return this;
+        
+        skipOptional(PROTOCOL_PREFIX);
+        if (allowSlashesAfterColon)
+            while (skipOptional("/")) ;
+        
+        if (allowMissingComma && remainder().indexOf(',')==-1) {
+            mimeType = DEFAULT_MIME_TYPE;
+            parameters.put("charset", DEFAULT_CHARSET);
+        } else {        
+            parseMediaType();
+            parseParameterOrParameterValues();
+            skipRequired(",");
+        }
+        
+        parseData();
+        
+        isParsed = true;
+        return this;
+    }
+
+    private void parseMediaType() throws MalformedURLException {
+        if (remainder().startsWith(";") || remainder().startsWith(","))
+            return;
+        int slash = remainder().indexOf("/");
+        if (slash==-1) throw new MalformedURLException("Missing required '/' in MIME type of data: URL");
+        String type = read(slash);
+        skipRequired("/");
+        int next = nextSemiOrComma();
+        String subtype = read(next);
+        mimeType = type+"/"+subtype;
+    }
+
+    private String read(int next) {
+        String result = remainder().substring(0, next);
+        parseIndex += next;
+        return result;
+    }
+
+    private int nextSemiOrComma() throws MalformedURLException {
+        int semi = remainder().indexOf(';');
+        int comma = remainder().indexOf(',');
+        if (semi<0 && comma<0) throw new MalformedURLException("Missing required ',' in data: URL");
+        if (semi<0) return comma;
+        if (comma<0) return semi;
+        return Math.min(semi, comma);
+    }
+
+    private void parseParameterOrParameterValues() throws MalformedURLException {
+        while (true) {
+            if (!remainder().startsWith(";")) return;
+            parseIndex++;
+            int eq = remainder().indexOf('=');
+            String word, value;
+            int nextSemiOrComma = nextSemiOrComma();
+            if (eq==-1 || eq>nextSemiOrComma) {
+                word = read(nextSemiOrComma);
+                value = null;
+            } else {
+                word = read(eq);
+                if (remainder().startsWith("\"")) {
+                    // is quoted
+                    parseIndex++;
+                    int nextUnescapedQuote = nextUnescapedQuote();
+                    value = "\"" + read(nextUnescapedQuote);
+                } else {
+                    value = read(nextSemiOrComma());
+                }
+            }
+            parameters.put(word, value);
+        }
+    }
+
+    private int nextUnescapedQuote() throws MalformedURLException {
+        int i=0;
+        String r = remainder();
+        boolean escaped = false;
+        while (i<r.length()) {
+            if (escaped) {
+                escaped = false;
+            } else {
+                if (r.charAt(i)=='"') return i;
+                if (r.charAt(i)=='\\') escaped = true;
+            }
+            i++;
+        }
+        throw new MalformedURLException("Unclosed double-quote in data: URL");
+    }
+
+    private void parseData() throws UnsupportedEncodingException, MalformedURLException {
+        if (parameters.containsKey("base64")) {
+            checkNoParamValue("base64");
+            data = BaseEncoding.base64().decode(remainder());
+        } else if (parameters.containsKey("base64url")) {
+            checkNoParamValue("base64url");
+            data = BaseEncoding.base64Url().decode(remainder());
+        } else {
+            data = URLDecoder.decode(remainder(), getCharset()).getBytes(Charset.forName(getCharset()));
+        }
+    }
+
+    private void checkNoParamValue(String param) throws MalformedURLException {
+        if (allowOtherLaxities) return; 
+        String value = parameters.get(param);
+        if (value!=null)
+            throw new MalformedURLException(param+" parameter must not take a value ("+value+") in data: URL");
+    }
+
+    private String remainder() {
+        return url.substring(parseIndex);
+    }
+
+    private boolean skipOptional(String word) {
+        if (remainder().startsWith(word)) {
+            parseIndex += word.length();
+            return true;
+        }
+        return false;
+    }
+
+    private void skipRequired(String word) throws MalformedURLException {
+        if (!remainder().startsWith(word))
+            throw new MalformedURLException("Missing required '"+word+"' at position "+parseIndex+" of data: URL");
+        parseIndex += word.length();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/text/TemplateProcessor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/text/TemplateProcessor.java b/core/src/main/java/org/apache/brooklyn/core/util/text/TemplateProcessor.java
new file mode 100644
index 0000000..6fb3c15
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/text/TemplateProcessor.java
@@ -0,0 +1,398 @@
+/*
+ * 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.util.text;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.drivers.EntityDriver;
+import org.apache.brooklyn.api.event.AttributeSensor;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.management.ManagementContext;
+import org.apache.brooklyn.core.management.internal.ManagementContextInternal;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.event.basic.DependentConfiguration;
+import brooklyn.event.basic.Sensors;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.text.Strings;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+
+import freemarker.cache.StringTemplateLoader;
+import freemarker.template.Configuration;
+import freemarker.template.ObjectWrapper;
+import freemarker.template.Template;
+import freemarker.template.TemplateHashModel;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+
+/** A variety of methods to assist in Freemarker template processing,
+ * including passing in maps with keys flattened (dot-separated namespace),
+ * and accessing {@link ManagementContext} brooklyn.properties 
+ * and {@link Entity}, {@link EntityDriver}, and {@link Location} methods and config.
+ * <p>
+ * See {@link #processTemplateContents(String, ManagementContextInternal, Map)} for
+ * a description of how management access is done.
+ */
+public class TemplateProcessor {
+
+    private static final Logger log = LoggerFactory.getLogger(TemplateProcessor.class);
+
+    protected static TemplateModel wrapAsTemplateModel(Object o) throws TemplateModelException {
+        if (o instanceof Map) return new DotSplittingTemplateModel((Map<?,?>)o);
+        return ObjectWrapper.DEFAULT_WRAPPER.wrap(o);
+    }
+    
+    /** @deprecated since 0.7.0 use {@link #processTemplateFile(String, Map)} */ @Deprecated
+    public static String processTemplate(String templateFileName, Map<String, ? extends Object> substitutions) {
+        return processTemplateFile(templateFileName, substitutions);
+    }
+    
+    /** As per {@link #processTemplateContents(String, Map)}, but taking a file. */
+    public static String processTemplateFile(String templateFileName, Map<String, ? extends Object> substitutions) {
+        String templateContents;
+        try {
+            templateContents = Files.toString(new File(templateFileName), Charsets.UTF_8);
+        } catch (IOException e) {
+            log.warn("Error loading file " + templateFileName, e);
+            throw Exceptions.propagate(e);
+        }
+        return processTemplateContents(templateContents, substitutions);
+    }
+
+    /** @deprecated since 0.7.0 use {@link #processTemplateFile(String, EntityDriver, Map)} */ @Deprecated
+    public static String processTemplate(String templateFileName, EntityDriver driver, Map<String, ? extends Object> extraSubstitutions) {
+        return processTemplateFile(templateFileName, driver, extraSubstitutions);
+    }
+    
+    /** Processes template contents according to {@link EntityAndMapTemplateModel}. */
+    public static String processTemplateFile(String templateFileName, EntityDriver driver, Map<String, ? extends Object> extraSubstitutions) {
+        String templateContents;
+        try {
+            templateContents = Files.toString(new File(templateFileName), Charsets.UTF_8);
+        } catch (IOException e) {
+            log.warn("Error loading file " + templateFileName, e);
+            throw Exceptions.propagate(e);
+        }
+        return processTemplateContents(templateContents, driver, extraSubstitutions);
+    }
+
+    /** Processes template contents according to {@link EntityAndMapTemplateModel}. */
+    public static String processTemplateContents(String templateContents, EntityDriver driver, Map<String,? extends Object> extraSubstitutions) {
+        return processTemplateContents(templateContents, new EntityAndMapTemplateModel(driver, extraSubstitutions));
+    }
+
+    /** Processes template contents according to {@link EntityAndMapTemplateModel}. */
+    public static String processTemplateContents(String templateContents, ManagementContext managementContext, Map<String,? extends Object> extraSubstitutions) {
+        return processTemplateContents(templateContents, new EntityAndMapTemplateModel(managementContext, extraSubstitutions));
+    }
+
+    /**
+     * A Freemarker {@link TemplateHashModel} which will correctly handle entries of the form "a.b" in this map,
+     * matching against template requests for "${a.b}".
+     * <p>
+     * Freemarker requests "a" in a map when given such a request, and expects that to point to a map
+     * with a key "b". This model provides such maps even for "a.b" in a map.
+     * <p>
+     * However if "a" <b>and</b> "a.b" are in the map, this will <b>not</b> currently do the deep mapping.
+     * (It does not have enough contextual information from Freemarker to handle this case.) */
+    public static final class DotSplittingTemplateModel implements TemplateHashModel {
+        protected final Map<?,?> map;
+
+        protected DotSplittingTemplateModel(Map<?,?> map) {
+            this.map = map;
+        }
+
+        @Override
+        public boolean isEmpty() { return map!=null && map.isEmpty(); }
+
+        public boolean contains(String key) {
+            if (map==null) return false;
+            if (map.containsKey(key)) return true;
+            for (Map.Entry<?,?> entry: map.entrySet()) {
+                String k = Strings.toString(entry.getKey());
+                if (k.startsWith(key+".")) {
+                    // contains this prefix
+                    return true;
+                }
+            }
+            return false;
+        }
+        
+        @Override
+        public TemplateModel get(String key) throws TemplateModelException {
+            if (map==null) return null;
+            try {
+                if (map.containsKey(key)) 
+                    return wrapAsTemplateModel( map.get(key) );
+                
+                Map<String,Object> result = MutableMap.of();
+                for (Map.Entry<?,?> entry: map.entrySet()) {
+                    String k = Strings.toString(entry.getKey());
+                    if (k.startsWith(key+".")) {
+                        String k2 = Strings.removeFromStart(k, key+".");
+                        result.put(k2, entry.getValue());
+                    }
+                }
+                if (!result.isEmpty()) 
+                        return wrapAsTemplateModel( result );
+                
+            } catch (Exception e) {
+                Exceptions.propagateIfFatal(e);
+                throw new IllegalStateException("Error accessing config '"+key+"'"+": "+e, e);
+            }
+            
+            return null;
+        }
+        
+        @Override
+        public String toString() {
+            return getClass().getName()+"["+map+"]";
+        }
+    }
+    
+    /** FreeMarker {@link TemplateHashModel} which resolves keys inside the given entity or management context.
+     * Callers are required to include dots for dot-separated keys.
+     * Freemarker will only due this when in inside bracket notation in an outer map, as in <code>${outer['a.b.']}</code>; 
+     * as a result this is intended only for use by {@link EntityAndMapTemplateModel} where 
+     * a caller has used bracked notation, as in <code>${mgmt['key.subkey']}</code>. */
+    protected static final class EntityConfigTemplateModel implements TemplateHashModel {
+        protected final EntityInternal entity;
+        protected final ManagementContext mgmt;
+
+        protected EntityConfigTemplateModel(EntityInternal entity) {
+            this.entity = entity;
+            this.mgmt = entity.getManagementContext();
+        }
+
+        protected EntityConfigTemplateModel(ManagementContext mgmt) {
+            this.entity = null;
+            this.mgmt = mgmt;
+        }
+
+        @Override
+        public boolean isEmpty() { return false; }
+
+        @Override
+        public TemplateModel get(String key) throws TemplateModelException {
+            try {
+                Object result = null;
+                
+                if (entity!=null)
+                    result = entity.getConfig(ConfigKeys.builder(Object.class).name(key).build());
+                if (result==null && mgmt!=null)
+                    result = mgmt.getConfig().getConfig(ConfigKeys.builder(Object.class).name(key).build());
+                
+                if (result!=null)
+                    return wrapAsTemplateModel( result );
+                
+            } catch (Exception e) {
+                Exceptions.propagateIfFatal(e);
+                throw new IllegalStateException("Error accessing config '"+key+"'"
+                    + (entity!=null ? " on "+entity : "")+": "+e, e);
+            }
+            
+            return null;
+        }
+        
+        @Override
+        public String toString() {
+            return getClass().getName()+"["+entity+"]";
+        }
+    }
+
+    protected final static class EntityAttributeTemplateModel implements TemplateHashModel {
+        protected final EntityInternal entity;
+
+        protected EntityAttributeTemplateModel(EntityInternal entity) {
+            this.entity = entity;
+        }
+
+        @Override
+        public boolean isEmpty() throws TemplateModelException {
+            return false;
+        }
+
+        @Override
+        public TemplateModel get(String key) throws TemplateModelException {
+            Object result;
+            try {
+                result = Entities.submit(entity, DependentConfiguration.attributeWhenReady(entity,
+                        Sensors.builder(Object.class, key).persistence(AttributeSensor.SensorPersistenceMode.NONE).build())).get();
+            } catch (Exception e) {
+                throw Exceptions.propagate(e);
+            }
+            if (result == null) {
+                return null;
+            } else {
+                return wrapAsTemplateModel(result);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getName()+"["+entity+"]";
+        }
+    }
+
+    /**
+     * Provides access to config on an entity or management context, using
+     * <code>${config['entity.config.key']}</code> or <code>${mgmt['brooklyn.properties.key']}</code> notation,
+     * and also allowing access to <code>getX()</code> methods on entity (interface) or driver
+     * using <code>${entity.x}</code> or <code><${driver.x}</code>.
+     * Optional extra properties can be supplied, treated as per {@link DotSplittingTemplateModel}.
+     */
+    protected static final class EntityAndMapTemplateModel implements TemplateHashModel {
+        protected final EntityInternal entity;
+        protected final EntityDriver driver;
+        protected final ManagementContext mgmt;
+        protected final DotSplittingTemplateModel extraSubstitutionsModel;
+
+        protected EntityAndMapTemplateModel(ManagementContext mgmt, Map<String,? extends Object> extraSubstitutions) {
+            this.entity = null;
+            this.driver = null;
+            this.mgmt = mgmt;
+            this.extraSubstitutionsModel = new DotSplittingTemplateModel(extraSubstitutions);
+        }
+
+        protected EntityAndMapTemplateModel(EntityDriver driver, Map<String,? extends Object> extraSubstitutions) {
+            this.driver = driver;
+            this.entity = (EntityInternal) driver.getEntity();
+            this.mgmt = entity.getManagementContext();
+            this.extraSubstitutionsModel = new DotSplittingTemplateModel(extraSubstitutions);
+        }
+
+        protected EntityAndMapTemplateModel(EntityInternal entity, Map<String,? extends Object> extraSubstitutions) {
+            this.entity = entity;
+            this.driver = null;
+            this.mgmt = entity.getManagementContext();
+            this.extraSubstitutionsModel = new DotSplittingTemplateModel(extraSubstitutions);
+        }
+
+        @Override
+        public boolean isEmpty() { return false; }
+
+        @Override
+        public TemplateModel get(String key) throws TemplateModelException {
+            if (extraSubstitutionsModel.contains(key))
+                return wrapAsTemplateModel( extraSubstitutionsModel.get(key) );
+
+            if ("entity".equals(key) && entity!=null)
+                return wrapAsTemplateModel( entity );
+            if ("config".equals(key)) {
+                if (entity!=null)
+                    return new EntityConfigTemplateModel(entity);
+                else
+                    return new EntityConfigTemplateModel(mgmt);
+            }
+            if ("mgmt".equals(key)) {
+                return new EntityConfigTemplateModel(mgmt);
+            }
+
+            if ("driver".equals(key) && driver!=null)
+                return wrapAsTemplateModel( driver );
+            if ("location".equals(key)) {
+                if (driver!=null && driver.getLocation()!=null)
+                    return wrapAsTemplateModel( driver.getLocation() );
+                if (entity!=null)
+                    return wrapAsTemplateModel( Iterables.getOnlyElement( entity.getLocations() ) );
+            }
+            if ("attribute".equals(key)) {
+                return new EntityAttributeTemplateModel(entity);
+            }
+            
+            if (mgmt!=null) {
+                // TODO deprecated in 0.7.0, remove after next version
+                // ie not supported to access global props without qualification
+                Object result = mgmt.getConfig().getConfig(ConfigKeys.builder(Object.class).name(key).build());
+                if (result!=null) { 
+                    log.warn("Deprecated access of global brooklyn.properties value for "+key+"; should be qualified with 'mgmt.'");
+                    return wrapAsTemplateModel( result );
+                }
+            }
+            
+            if ("javaSysProps".equals(key))
+                return wrapAsTemplateModel( System.getProperties() );
+
+            return null;
+        }
+        
+        @Override
+        public String toString() {
+            return getClass().getName()+"["+(entity!=null ? entity : mgmt)+"]";
+        }
+    }
+
+    /** Processes template contents with the given items in scope as per {@link EntityAndMapTemplateModel}. */
+    public static String processTemplateContents(String templateContents, final EntityInternal entity, Map<String,? extends Object> extraSubstitutions) {
+        return processTemplateContents(templateContents, new EntityAndMapTemplateModel(entity, extraSubstitutions));
+    }
+    
+    /** Processes template contents using the given map, passed to freemarker,
+     * with dot handling as per {@link DotSplittingTemplateModel}. */
+    public static String processTemplateContents(String templateContents, final Map<String, ? extends Object> substitutions) {
+        TemplateHashModel root;
+        try {
+            root = substitutions != null
+                ? (TemplateHashModel)wrapAsTemplateModel(substitutions)
+                : null;
+        } catch (TemplateModelException e) {
+            throw new IllegalStateException("Unable to set up TemplateHashModel to parse template, given "+substitutions+": "+e, e);
+        }
+        
+        return processTemplateContents(templateContents, root);
+    }
+    
+    /** Processes template contents against the given {@link TemplateHashModel}. */
+    public static String processTemplateContents(String templateContents, final TemplateHashModel substitutions) {
+        try {
+            Configuration cfg = new Configuration();
+            StringTemplateLoader templateLoader = new StringTemplateLoader();
+            templateLoader.putTemplate("config", templateContents);
+            cfg.setTemplateLoader(templateLoader);
+            Template template = cfg.getTemplate("config");
+
+            // TODO could expose CAMP '$brooklyn:' style dsl, based on template.createProcessingEnvironment
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            Writer out = new OutputStreamWriter(baos);
+            template.process(substitutions, out);
+            out.flush();
+
+            return new String(baos.toByteArray());
+        } catch (Exception e) {
+            log.warn("Error processing template (propagating): "+e, e);
+            log.debug("Template which could not be parsed (causing "+e+") is:"
+                + (Strings.isMultiLine(templateContents) ? "\n"+templateContents : templateContents));
+            throw Exceptions.propagate(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/CompilerIndependentOuterClassFieldMapper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/CompilerIndependentOuterClassFieldMapper.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/CompilerIndependentOuterClassFieldMapper.java
new file mode 100644
index 0000000..68c7382
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/CompilerIndependentOuterClassFieldMapper.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.util.xstream;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.thoughtworks.xstream.core.Caching;
+import com.thoughtworks.xstream.mapper.Mapper;
+import com.thoughtworks.xstream.mapper.MapperWrapper;
+
+/**
+ * <p>Compiler independent outer class field mapper.</p>
+ * <p>Different compilers generate different indexes for the names of outer class reference
+ *    field (this$N) leading to deserialization errors.</p>
+ * <ul>
+ *   <li> eclipse-[groovy-]compiler counts all outer static classes
+ *   <li> OpenJDK/Oracle/IBM compiler starts at 0, regardless of the nesting level
+ * </ul>
+ * <p>The mapper will be able to update field names for instances with a single this$N
+ *    field only (including those from parent classes).</p>
+ * <p>For difference between generated field names compare
+ *    {@code src/test/java/brooklyn/util/xstream/compiler_compatibility_eclipse.xml} and
+ *    {@code src/test/java/brooklyn/util/xstream/compiler_compatibility_oracle.xml},
+ *    generated from {@code org.apache.brooklyn.core.util.xstream.CompilerCompatibilityTest}</p>
+ * <p>JLS 1.1 relevant section, copied verbatim for a lack of reliable URL:</p>
+ * <blockquote>
+ *  <p>Java 1.1 compilers are strongly encouraged, though not required, to use the
+ *     following naming conventions when implementing inner classes. Compilers may
+ *     not use synthetic names of the forms defined here for any other purposes.</p>
+ *  <p>A synthetic field pointing to the outermost enclosing instance is named this$0.
+ *     The next-outermost enclosing instance is this$1, and so forth. (At most one such
+ *     field is necessary in any given inner class.) A synthetic field containing a copy
+ *     of a constant v is named val$v. These fields are final.</p>
+ * </blockquote>
+ * <p>Currently available at
+ *    http://web.archive.org/web/20000830111107/http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc10.html</p>
+ */
+public class CompilerIndependentOuterClassFieldMapper extends MapperWrapper implements Caching {
+    public static final Logger LOG = LoggerFactory.getLogger(CompilerIndependentOuterClassFieldMapper.class);
+
+    private static final String OUTER_CLASS_FIELD_PREFIX = "this$";
+
+    private final Map<String, Collection<String>> classOuterFields = new ConcurrentHashMap<String, Collection<String>>();
+
+    public CompilerIndependentOuterClassFieldMapper(Mapper wrapped) {
+        super(wrapped);
+        classOuterFields.put(Object.class.getName(), Collections.<String>emptyList());
+    }
+
+    @Override
+    public String realMember(@SuppressWarnings("rawtypes") Class type, String serialized) {
+        // Let com.thoughtworks.xstream.mapper.OuterClassMapper also run on the input.
+        String serializedFieldName = super.realMember(type, serialized);
+
+        if (serializedFieldName.startsWith(OUTER_CLASS_FIELD_PREFIX)) {
+            Collection<String> compiledFieldNames = findOuterClassFieldNames(type);
+            if (compiledFieldNames.size() == 0) {
+                throw new IllegalStateException("Unable to find any outer class fields in " + type + ", searching specifically for " + serializedFieldName);
+            }
+
+            Set<String> uniqueFieldNames = new HashSet<String>(compiledFieldNames);
+            String deserializeFieldName;
+            if (!compiledFieldNames.contains(serializedFieldName)) {
+                String msg =
+                        "Unable to find outer class field " + serializedFieldName + " in class " + type + ". " +
+                        "This could be caused by " +
+                        "1) changing the class (or one of its parents) to a static or " +
+                        "2) moving the class to a different lexical level (enclosing classes) or " +
+                        "3) using a different compiler (i.e eclipse vs oracle) at the time the object was serialized. ";
+                if (uniqueFieldNames.size() == 1) {
+                    // Try to fix the field naming only for the case with a single field or 
+                    // multiple fields with the same name, in which case XStream puts defined-in
+                    // for the field declared in super.
+                    //
+                    // We don't have access to the XML elements from here to check for same name
+                    // so we check the target class instead. This should work most of the time, but
+                    // if code is recompiled in such a way that the new instance has fields with
+                    // different names, where only the field of the extending class is renamed and
+                    // the super field is not, then the instance will be deserialized incorrectly -
+                    // the super field will be assigned both times. If the field type is incompatible
+                    // then a casting exception will be thrown, if it's the same then only the warning
+                    // below will indicate of a possible problem down the line - most probably NPE on
+                    // the this$N field.
+                    deserializeFieldName = compiledFieldNames.iterator().next();
+                    LOG.warn(msg + "Will use the field " + deserializeFieldName + " instead.");
+                } else {
+                    // Multiple fields with differing names case - don't try to fix it.
+                    // Better fail with an explicit error, and have someone fix it manually,
+                    // than try to fix it here non-reliably and have it fail down the line
+                    // with some unrelated error.
+                    // XStream will fail later with a field not found exception.
+                    LOG.error(msg + "Will fail with a field not found exception. " +
+                            "Edit the persistence state manually and update the field names. "+
+                            "Existing field names are " + uniqueFieldNames);
+                    deserializeFieldName = serializedFieldName;
+                }
+            } else {
+                if (uniqueFieldNames.size() > 1) {
+                    // Log at debug level as the actual problem would occur in very specific cases. Only
+                    // useful when the compiler is changed, otherwise leads to false positives.
+                    LOG.debug("Deserializing the non-static class " + type + " with multiple outer class fields " + uniqueFieldNames + ". " +
+                            "When changing compilers it's possible that the instance won't be able to be deserialized due to changed outer class field names. " +
+                            "In those cases deserialization could fail with field not found exception or class cast exception following this log line.");
+                }
+                deserializeFieldName = serializedFieldName;
+            }
+
+            return deserializeFieldName;
+        } else {
+            return serializedFieldName;
+        }
+    }
+    
+    private Collection<String> findOuterClassFieldNames(Class<?> type) {
+        Collection<String> fields = classOuterFields.get(type.getName());
+        if (fields == null) {
+            fields = new ArrayList<String>();
+            addOuterClassFields(type, fields);
+            classOuterFields.put(type.getName(), fields);
+        }
+        return fields;
+    }
+    
+    private void addOuterClassFields(Class<?> type, Collection<String> fields) {
+        for (Field field : type.getDeclaredFields()) {
+            if (field.isSynthetic()) {
+                fields.add(field.getName());
+            }
+        }
+        if (type.getSuperclass() != null) {
+            addOuterClassFields(type.getSuperclass(), fields);
+        }
+    }
+
+    @Override
+    public void flushCache() {
+        classOuterFields.keySet().retainAll(Collections.singletonList(Object.class.getName()));
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingConverter.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingConverter.java
new file mode 100644
index 0000000..7d95568
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingConverter.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.util.xstream;
+
+import brooklyn.util.exceptions.Exceptions;
+
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.converters.enums.EnumConverter;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+
+/** ... except this doesn't seem to get applied when we think it should
+ * (normal xstream.resgisterConverter doesn't apply to enums) */
+public class EnumCaseForgivingConverter extends EnumConverter {
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
+        Class type = context.getRequiredType();
+        if (type.getSuperclass() != Enum.class) {
+            type = type.getSuperclass(); // polymorphic enums
+        }
+        String token = reader.getValue();
+        // this is the new bit (overriding superclass to accept case-insensitive)
+        return resolve(type, token);
+    }
+
+    public static <T extends Enum<T>> T resolve(Class<T> type, String token) {
+        try {
+            return Enum.valueOf(type, token.toUpperCase());
+        } catch (Exception e) {
+            
+            // new stuff here:  try reading case insensitive
+            
+            Exceptions.propagateIfFatal(e);
+            try {
+                for (T v: type.getEnumConstants())
+                    if (v.name().equalsIgnoreCase(token)) return v;
+                throw e;
+            } catch (Exception e2) {
+                throw Exceptions.propagate(e2);
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingSingleValueConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingSingleValueConverter.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingSingleValueConverter.java
new file mode 100644
index 0000000..4bc507c
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/EnumCaseForgivingSingleValueConverter.java
@@ -0,0 +1,35 @@
+/*
+ * 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.util.xstream;
+
+import com.thoughtworks.xstream.converters.enums.EnumSingleValueConverter;
+
+public class EnumCaseForgivingSingleValueConverter extends EnumSingleValueConverter {
+
+    private final Class enumType;
+
+    public EnumCaseForgivingSingleValueConverter(Class type) {
+        super(type);
+        enumType = type;
+    }
+
+    public Object fromString(String str) {
+        return EnumCaseForgivingConverter.resolve(enumType, str);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableListConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableListConverter.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableListConverter.java
new file mode 100644
index 0000000..a59cfa8
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableListConverter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util.xstream;
+
+import java.util.Collection;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.converters.collections.CollectionConverter;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.mapper.Mapper;
+
+public class ImmutableListConverter extends CollectionConverter {
+
+    public ImmutableListConverter(Mapper mapper) {
+        super(mapper);
+    }
+
+    @Override
+    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
+        return ImmutableList.class.isAssignableFrom(type);
+    }
+
+    // marshalling is the same
+    // so is unmarshalling the entries
+
+    // only differences are creating the overarching collection, which we do after the fact
+    // (optimizing format on disk as opposed to in-memory), and we discard null values 
+    // to avoid failing entirely.
+    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
+        Collection<?> collection = Lists.newArrayList();
+        populateCollection(reader, context, collection);
+        return ImmutableList.copyOf(Iterables.filter(collection, Predicates.notNull()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableMapConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableMapConverter.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableMapConverter.java
new file mode 100644
index 0000000..00e44dd
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableMapConverter.java
@@ -0,0 +1,56 @@
+/*
+ * 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.util.xstream;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.mapper.Mapper;
+
+public class ImmutableMapConverter extends MapConverter {
+
+    public ImmutableMapConverter(Mapper mapper) {
+        super(mapper);
+    }
+
+    @Override
+    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
+        return ImmutableMap.class.isAssignableFrom(type);
+    }
+
+    // marshalling is the same
+    // so is unmarshalling the entries
+
+    // only differences are creating the overarching collection, which we do after the fact
+    // (optimizing format on disk as opposed to in-memory), and we discard null key/values 
+    // to avoid failing entirely.
+    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
+        Map<?, ?> map = Maps.newLinkedHashMap();
+        populateMap(reader, context, map);
+        return ImmutableMap.copyOf(Maps.filterEntries(map, new Predicate<Map.Entry<?,?>>() {
+                @Override public boolean apply(Entry<?, ?> input) {
+                    return input != null && input.getKey() != null && input.getValue() != null;
+                }}));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableSetConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableSetConverter.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableSetConverter.java
new file mode 100644
index 0000000..76975ff
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/ImmutableSetConverter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util.xstream;
+
+import java.util.Collection;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.converters.collections.CollectionConverter;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.mapper.Mapper;
+
+public class ImmutableSetConverter extends CollectionConverter {
+
+    public ImmutableSetConverter(Mapper mapper) {
+        super(mapper);
+    }
+
+    @Override
+    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
+        return ImmutableSet.class.isAssignableFrom(type);
+    }
+
+    // marshalling is the same
+    // so is unmarshalling the entries
+
+    // only differences are creating the overarching collection, which we do after the fact
+    // (optimizing format on disk as opposed to in-memory), and we discard null values 
+    // to avoid failing entirely.
+    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
+        Collection<?> collection = Lists.newArrayList();
+        populateCollection(reader, context, collection);
+        return ImmutableSet.copyOf(Iterables.filter(collection, Predicates.notNull()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/Inet4AddressConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/Inet4AddressConverter.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/Inet4AddressConverter.java
new file mode 100644
index 0000000..53133c1
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/Inet4AddressConverter.java
@@ -0,0 +1,65 @@
+/*
+ * 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.util.xstream;
+
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
+
+import brooklyn.util.exceptions.Exceptions;
+
+import com.thoughtworks.xstream.converters.Converter;
+import com.thoughtworks.xstream.converters.MarshallingContext;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+
+public class Inet4AddressConverter implements Converter {
+
+    @Override
+    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
+        return type.equals(Inet4Address.class);
+    }
+
+    @Override
+    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
+        Inet4Address addr = (Inet4Address) source;
+        writer.setValue(addr.getHostName()+"/"+addr.getHostAddress());
+    }
+
+    @Override
+    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
+        String hostSlashAddress = reader.getValue();
+        int i = hostSlashAddress.indexOf('/');
+        try {
+            if (i==-1) {
+                return Inet4Address.getByName(hostSlashAddress);
+            } else {
+                String host = hostSlashAddress.substring(0, i);
+                String addrS = hostSlashAddress.substring(i+1);
+                byte[] addr = new byte[4];
+                String[] addrSI = addrS.split("\\.");
+                for (int k=0; k<4; k++) addr[k] = (byte)(int)Integer.valueOf(addrSI[k]);
+                return Inet4Address.getByAddress(host, addr);
+            }
+        } catch (UnknownHostException e) {
+            throw Exceptions.propagate(e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/MapConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/MapConverter.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/MapConverter.java
new file mode 100644
index 0000000..752ef70
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/MapConverter.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.core.util.xstream;
+
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.thoughtworks.xstream.converters.MarshallingContext;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.core.ReferencingMarshallingContext;
+import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import com.thoughtworks.xstream.mapper.Mapper;
+
+/** equivalent to super, but cleaner methods, overridable, logging, and some retries */
+public class MapConverter extends com.thoughtworks.xstream.converters.collections.MapConverter {
+
+    private static final Logger log = LoggerFactory.getLogger(MapConverter.class);
+    
+    public MapConverter(Mapper mapper) {
+        super(mapper);
+    }
+
+    @SuppressWarnings({ "rawtypes" })
+    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
+        Map map = (Map) source;
+        try {
+            for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();) {
+                Map.Entry entry = (Map.Entry) iterator.next();
+                marshalEntry(writer, context, entry);
+            }
+        } catch (ConcurrentModificationException e) {
+            log.debug("Map "
+                // seems there is no non-deprecated way to get the path...
+                + (context instanceof ReferencingMarshallingContext ? "at "+((ReferencingMarshallingContext)context).currentPath() : "")
+                + "["+source+"] modified while serializing; will fail, and retry may be attempted");
+            throw e;
+            // would be nice to attempt to re-serialize being slightly more defensive, as code below;
+            // but the code above may have written partial data so that is dangerous, we could have corrupted output. 
+            // if we could mark and restore in the output stream then we could do this below (but we don't have that in our stream),
+            // or we could try this copying code in the first instance (but that's slow);
+            // error is rare most of the time (e.g. attribute being updated) so we bail on this whole attempt
+            // and simply try serializing the map-owner (e.g. an entity) again.
+//            ImmutableList entries = ImmutableList.copyOf(map.entrySet());
+//            for (Iterator iterator = entries.iterator(); iterator.hasNext();) {
+//                Map.Entry entry = (Map.Entry) iterator.next();
+//                marshalEntry(writer, context, entry);                
+//            }
+        }
+    }
+
+    protected String getEntryNodeName() { return mapper().serializedClass(Map.Entry.class); }
+    
+    protected void marshalEntry(HierarchicalStreamWriter writer, MarshallingContext context, Map.Entry entry) {
+        ExtendedHierarchicalStreamWriterHelper.startNode(writer, getEntryNodeName(), Map.Entry.class);
+
+        writeItem(entry.getKey(), context, writer);
+        writeItem(entry.getValue(), context, writer);
+
+        writer.endNode();
+    }
+
+    protected void populateMap(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) {
+        while (reader.hasMoreChildren()) {
+            reader.moveDown();
+            unmarshalEntry(reader, context, map);
+            reader.moveUp();
+        }
+    }
+
+    protected void unmarshalEntry(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) {
+        reader.moveDown();
+        Object key = readItem(reader, context, map);
+        reader.moveUp();
+
+        reader.moveDown();
+        Object value = readItem(reader, context, map);
+        reader.moveUp();
+
+        map.put(key, value);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/MutableSetConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/MutableSetConverter.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/MutableSetConverter.java
new file mode 100644
index 0000000..4b7bcbc
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/MutableSetConverter.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util.xstream;
+
+import brooklyn.util.collections.MutableSet;
+
+import com.thoughtworks.xstream.converters.collections.CollectionConverter;
+import com.thoughtworks.xstream.mapper.Mapper;
+
+public class MutableSetConverter extends CollectionConverter {
+
+    // Although this class seems pointless (!), without registering an explicit converter for MutableSet then the
+    // declaration for Set interferes, causing MutableSet.map field to be null on deserialization.
+    
+    public MutableSetConverter(Mapper mapper) {
+        super(mapper);
+    }
+
+    @Override
+    public boolean canConvert(@SuppressWarnings("rawtypes") Class type) {
+        return MutableSet.class.isAssignableFrom(type);
+    }
+
+    @Override
+    protected Object createCollection(Class type) {
+        return new MutableSet<Object>();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/StringKeyMapConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/StringKeyMapConverter.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/StringKeyMapConverter.java
new file mode 100644
index 0000000..86a4cd0
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/StringKeyMapConverter.java
@@ -0,0 +1,134 @@
+/*
+ * 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.util.xstream;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.brooklyn.core.util.flags.TypeCoercions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.exceptions.Exceptions;
+import brooklyn.util.text.Identifiers;
+
+import com.thoughtworks.xstream.converters.MarshallingContext;
+import com.thoughtworks.xstream.converters.UnmarshallingContext;
+import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriterHelper;
+import com.thoughtworks.xstream.io.HierarchicalStreamReader;
+import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
+import com.thoughtworks.xstream.mapper.Mapper;
+
+/** converter which simplifies representation of a map for string-based keys,
+ * to <key>value</key>, or <entry key="key" type="string">value</entry> 
+ * @author alex
+ *
+ */
+public class StringKeyMapConverter extends MapConverter {
+
+    private static final Logger log = LoggerFactory.getLogger(StringKeyMapConverter.class);
+    
+    // full stop is technically allowed ... goes against "best practice" ... 
+    // but simplifies property maps, and is used elsewhere in xstream's repn
+    final static String VALID_XML_NODE_NAME_CHARS = Identifiers.JAVA_GOOD_NONSTART_CHARS + ".";
+
+    final static String VALID_XML_NODE_NAME_START_CHARS = Identifiers.JAVA_GOOD_START_CHARS + ".";
+
+    public StringKeyMapConverter(Mapper mapper) {
+        super(mapper);
+    }
+    
+    protected boolean isKeyValidForNodeName(String key) {
+        // return false to always write as <entry key="key" ...; otherwise only use that when key is not valid xml
+        return Identifiers.isValidToken(key, VALID_XML_NODE_NAME_START_CHARS, VALID_XML_NODE_NAME_CHARS);
+    }
+    
+    public boolean canConvert(Class type) {
+        return super.canConvert(type) || type.getName().equals(MutableMap.class.getName());
+    }
+    
+    @Override
+    protected void marshalEntry(HierarchicalStreamWriter writer, MarshallingContext context, Entry entry) {
+        if (entry.getKey() instanceof String) {
+            marshalStringKey(writer, context, entry);
+        } else {
+            super.marshalEntry(writer, context, entry);
+        }
+    }
+    
+    protected void marshalStringKey(HierarchicalStreamWriter writer, MarshallingContext context, Entry entry) {
+        String key = (String)entry.getKey();
+        String entryNodeName = getEntryNodeName();
+        boolean useKeyAsNodeName = (!key.equals(entryNodeName) && isKeyValidForNodeName(key));
+        if (useKeyAsNodeName) entryNodeName = key;
+        ExtendedHierarchicalStreamWriterHelper.startNode(writer, entryNodeName, Map.Entry.class);
+        if (!useKeyAsNodeName)
+            writer.addAttribute("key", key);
+        
+        Object value = entry.getValue();
+        if (entry.getValue()!=null && isInlineableType(value.getClass())) {
+            if (!(value instanceof String))
+                writer.addAttribute("type", mapper().serializedClass(entry.getValue().getClass()));
+            if (entry.getValue().getClass().isEnum())
+                writer.setValue(((Enum)entry.getValue()).name());
+            else
+                writer.setValue(""+entry.getValue());
+        } else {
+            writeItem(entry.getValue(), context, writer);
+        }
+        
+        writer.endNode();
+    }
+
+    protected boolean isInlineableType(Class<?> type) {
+        return TypeCoercions.isPrimitiveOrBoxer(type) || String.class.equals(type) || type.isEnum();
+    }
+    
+    @Override
+    protected void unmarshalEntry(HierarchicalStreamReader reader, UnmarshallingContext context, Map map) {
+        String key = reader.getNodeName(); 
+        if (key.equals(getEntryNodeName())) key = reader.getAttribute("key");
+        if (key==null) {
+            super.unmarshalEntry(reader, context, map);
+        } else {
+            unmarshalStringKey(reader, context, map, key);
+        }
+    }
+
+    protected void unmarshalStringKey(HierarchicalStreamReader reader, UnmarshallingContext context, Map map, String key) {
+        String type = reader.getAttribute("type");
+        Object value;
+        if (type==null && reader.hasMoreChildren()) {
+            reader.moveDown();
+            value = readItem(reader, context, map);
+            reader.moveUp();
+        } else {
+            Class typeC = type!=null ? mapper().realClass(type) : String.class;
+            try {
+                value = TypeCoercions.coerce(reader.getValue(), typeC);
+            } catch (Exception e) {
+                log.warn("FAILED to coerce "+reader.getValue()+" to "+typeC+": "+e);
+                throw Exceptions.propagate(e);
+            }
+        }
+        map.put(key, value);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/699b3f65/core/src/main/java/org/apache/brooklyn/core/util/xstream/XmlSerializer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/util/xstream/XmlSerializer.java b/core/src/main/java/org/apache/brooklyn/core/util/xstream/XmlSerializer.java
new file mode 100644
index 0000000..3b3b582
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/util/xstream/XmlSerializer.java
@@ -0,0 +1,97 @@
+/*
+ * 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.util.xstream;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import brooklyn.util.collections.MutableList;
+import brooklyn.util.collections.MutableMap;
+import brooklyn.util.collections.MutableSet;
+
+import com.google.common.collect.ImmutableList;
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.mapper.MapperWrapper;
+
+public class XmlSerializer<T> {
+
+    protected final XStream xstream;
+    
+    public XmlSerializer() {
+        xstream = new XStream() {
+            @Override
+            protected MapperWrapper wrapMapper(MapperWrapper next) {
+                MapperWrapper result = super.wrapMapper(next);
+                return XmlSerializer.this.wrapMapper(result);
+            }
+        };
+        
+        // list as array list is default
+        xstream.alias("map", Map.class, LinkedHashMap.class);
+        xstream.alias("set", Set.class, LinkedHashSet.class);
+        
+        xstream.registerConverter(new StringKeyMapConverter(xstream.getMapper()), /* priority */ 10);
+        xstream.alias("MutableMap", MutableMap.class);
+        xstream.alias("MutableSet", MutableSet.class);
+        xstream.alias("MutableList", MutableList.class);
+        
+        // Needs an explicit MutableSet converter!
+        // Without it, the alias for "set" seems to interfere with the MutableSet.map field, so it gets
+        // a null field on deserialization.
+        xstream.registerConverter(new MutableSetConverter(xstream.getMapper()));
+        
+        xstream.aliasType("ImmutableList", ImmutableList.class);
+        xstream.registerConverter(new ImmutableListConverter(xstream.getMapper()));
+        xstream.registerConverter(new ImmutableSetConverter(xstream.getMapper()));
+        xstream.registerConverter(new ImmutableMapConverter(xstream.getMapper()));
+
+        xstream.registerConverter(new EnumCaseForgivingConverter());
+        xstream.registerConverter(new Inet4AddressConverter());
+    }
+    
+    protected MapperWrapper wrapMapper(MapperWrapper next) {
+        return new CompilerIndependentOuterClassFieldMapper(next);
+    }
+
+    public void serialize(Object object, Writer writer) {
+        xstream.toXML(object, writer);
+    }
+
+    @SuppressWarnings("unchecked")
+    public T deserialize(Reader xml) {
+        return (T) xstream.fromXML(xml);
+    }
+
+    public String toString(T memento) {
+        Writer writer = new StringWriter();
+        serialize(memento, writer);
+        return writer.toString();
+    }
+
+    public T fromString(String xml) {
+        return deserialize(new StringReader(xml));
+    }
+
+}