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

[1/9] git commit: add some more tests for enricher rebind (but none of these are the culprit for the multiple-enrichers-being-added)

Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master 8a4d1324b -> d67444a3e


add some more tests for enricher rebind (but none of these are the culprit for the multiple-enrichers-being-added)


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

Branch: refs/heads/master
Commit: e6b7af4c3489a6be616937d4a0d54db6e653e9a9
Parents: 424bda6
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jul 31 01:23:35 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Jul 31 02:15:05 2014 -0400

----------------------------------------------------------------------
 .../entity/rebind/RebindEnricherTest.java       | 38 ++++++++++++++++++++
 1 file changed, 38 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6b7af4c/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 0a65cd1..a2bdbb7 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindEnricherTest.java
@@ -23,8 +23,11 @@ import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
+import java.util.Collection;
 import java.util.Map;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
@@ -33,17 +36,21 @@ import brooklyn.enricher.Enrichers;
 import brooklyn.enricher.basic.AbstractEnricher;
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.Entities;
 import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.basic.EntityPredicates;
 import brooklyn.entity.group.DynamicCluster;
 import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.basic.Sensors;
 import brooklyn.location.LocationSpec;
 import brooklyn.location.basic.SimulatedLocation;
+import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
 import brooklyn.test.EntityTestUtils;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.test.entity.TestEntity;
+import brooklyn.test.entity.TestEntityImpl;
 import brooklyn.util.flags.SetFromFlag;
 import brooklyn.util.text.StringFunctions;
 
@@ -54,6 +61,8 @@ import com.google.common.collect.Iterables;
 
 public class RebindEnricherTest extends RebindTestFixtureWithApp {
 
+    private static final Logger log = LoggerFactory.getLogger(RebindEnricherTest.class);
+    
     public static AttributeSensor<String> METRIC1 = Sensors.newStringSensor("RebindEnricherTest.metric1");
     public static AttributeSensor<String> METRIC2 = Sensors.newStringSensor("RebindEnricherTest.metric2");
     
@@ -155,6 +164,7 @@ public class RebindEnricherTest extends RebindTestFixtureWithApp {
     @Test
     public void testRestoresConfig() throws Exception {
         origApp.addEnricher(EnricherSpec.create(MyEnricher.class)
+                .displayName("My Enricher")
                 .configure(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME, "myVal for with setFromFlag noShortName")
                 .configure(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME, "myVal for setFromFlag withShortName")
                 .configure(MyEnricher.MY_CONFIG_WITHOUT_SETFROMFLAG, "myVal for witout setFromFlag"));
@@ -162,6 +172,7 @@ public class RebindEnricherTest extends RebindTestFixtureWithApp {
         newApp = (TestApplication) rebind();
         MyEnricher newEnricher = (MyEnricher) Iterables.getOnlyElement(newApp.getEnrichers());
         
+        assertEquals(newEnricher.getName(), "My Enricher");
         assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName");
         assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName");
         assertEquals(newEnricher.getConfig(MyEnricher.MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag");
@@ -249,4 +260,31 @@ public class RebindEnricherTest extends RebindTestFixtureWithApp {
             super(flags);
         }
     }
+    
+    public static class MyTestEntityWithEnricher extends TestEntityImpl {
+        @Override
+        public void init() {
+            super.init();
+            addEnricher(EnricherSpec.create(MyEnricher.class));
+        }
+    }
+
+    @Test
+    // this was never a problem, but wanted to confirm
+    // we were seeing enrichers and policies added multiple times, but that was due to 
+    // SoftwareProcessImpl.callRebindHooks calling connectSensors an extra time
+    // as a workaround for when sensors, enrichers, and policies were not being persisted
+    public void testEntityCreatingItsEnricherDoesNotReCreateIt() throws Exception {
+        TestEntity e1 = origApp.createAndManageChild(EntitySpec.create(TestEntity.class, MyTestEntityWithEnricher.class));
+        Collection<Enricher> e1e = e1.getEnrichers();
+        log.info("enrichers1: "+e1e);
+
+        newApp = (TestApplication) rebind();
+        Entity e2 = Iterables.getOnlyElement( Entities.descendants(newApp, EntityPredicates.idEqualTo(e1.getId())) );
+        Collection<Enricher> e2e = e2.getEnrichers();
+        log.info("enrichers2: "+e2e);
+        
+        assertEquals(e1e.size(), e2e.size());
+    }
+
 }


[7/9] git commit: fix more of the explicit places where enrichers could be re-added on rebind

Posted by al...@apache.org.
fix more of the explicit places where enrichers could be re-added on rebind


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

Branch: refs/heads/master
Commit: 6416d446196bdfb0e0723414e524fc0b673d8fa3
Parents: 5114552
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jul 31 03:38:34 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Jul 31 03:40:09 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java   | 7 ++++---
 .../entity/webapp/JavaWebAppSoftwareProcessImpl.java         | 8 ++++----
 .../java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java  | 1 -
 3 files changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6416d446/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
----------------------------------------------------------------------
diff --git a/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java b/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
index 373dc29..0671678 100644
--- a/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
+++ b/software/nosql/src/main/java/brooklyn/entity/nosql/cassandra/CassandraNodeImpl.java
@@ -328,6 +328,8 @@ public class CassandraNodeImpl extends SoftwareProcessImpl implements CassandraN
         
         Entities.getRequiredUrlConfig(this, CASSANDRA_CONFIG_TEMPLATE_URL);
         Entities.getRequiredUrlConfig(this, CASSANDRA_RACKDC_CONFIG_TEMPLATE_URL);
+        
+        connectEnrichers();
     }
     
     private volatile JmxFeed jmxFeed;
@@ -464,15 +466,14 @@ public class CassandraNodeImpl extends SoftwareProcessImpl implements CassandraN
                         }))
                 .build();
         
-        connectEnrichers();
+        jmxMxBeanFeed = JavaAppUtils.connectMXBeanSensors(this);
     }
-
+    
     protected void connectEnrichers() {
         connectEnrichers(Duration.TEN_SECONDS);
     }
     
     protected void connectEnrichers(Duration windowPeriod) {
-        jmxMxBeanFeed = JavaAppUtils.connectMXBeanSensors(this);
         JavaAppUtils.connectJavaAppServerPolicies(this);
 
         addEnricher(TimeWeightedDeltaEnricher.<Long>getPerSecondDeltaEnricher(this, READ_COMPLETED, READS_PER_SECOND_LAST));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6416d446/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
index 2b6ab29..2ea3f48 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/JavaWebAppSoftwareProcessImpl.java
@@ -64,13 +64,13 @@ public abstract class JavaWebAppSoftwareProcessImpl extends SoftwareProcessImpl
     }
 
     @Override
-    protected void connectSensors() {
-        super.connectSensors();
-
+    public void init() {
+        super.init();
+        
         WebAppServiceMethods.connectWebAppServerPolicies(this);
         JavaAppUtils.connectJavaAppServerPolicies(this);
     }
-
+    
     //just provide better typing
     public JavaWebAppDriver getDriver() {
         return (JavaWebAppDriver) super.getDriver();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6416d446/software/webapp/src/main/java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
index 8e3587d..ce8fdec 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/jetty/Jetty6ServerImpl.java
@@ -84,7 +84,6 @@ public class Jetty6ServerImpl extends JavaWebAppSoftwareProcessImpl implements J
                     .build());
 
             jmxFeedMx = JavaAppUtils.connectMXBeanSensors(this);
-            JavaAppUtils.connectJavaAppServerPolicies(this);
         } else {
             // if not using JMX
             log.warn("Jetty running without JMX monitoring; limited visibility of service available");


[9/9] git commit: This closes #101

Posted by al...@apache.org.
This closes #101


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

Branch: refs/heads/master
Commit: d67444a3e1d04e0935b782068122035087b02ee5
Parents: 8a4d132 059d03f
Author: Aled Sage <al...@gmail.com>
Authored: Fri Aug 1 17:47:00 2014 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Fri Aug 1 17:47:00 2014 +0100

----------------------------------------------------------------------
 .../brooklyn/entity/basic/AbstractEntity.java   |  65 +++++++++++-
 .../policy/basic/AbstractEntityAdjunct.java     |   1 +
 .../java/brooklyn/util/file/ArchiveBuilder.java | 102 ++++++++++++++-----
 .../entity/rebind/RebindEnricherTest.java       |  38 +++++++
 .../brooklyn/test/entity/TestApplication.java   |  10 +-
 .../test/entity/TestApplicationImpl.java        |   7 ++
 .../brooklyn/util/file/ArchiveBuilderTest.java  |  51 +++++++++-
 .../brooklynnode/BrooklynNodeSshDriver.java     |   2 +-
 .../entity/java/VanillaJavaAppImpl.java         |   2 +-
 .../entity/java/VanillaJavaAppSshDriver.java    |   3 +-
 .../brooklyn/entity/java/EntityPollingTest.java |  15 +--
 .../brooklyn/entity/java/JmxSupportTest.java    |  14 +--
 .../entity/java/VanillaJavaAppRebindTest.java   |  63 ++++++++++--
 .../entity/java/VanillaJavaAppTest.java         |   7 +-
 .../storm/StormAbstractCloudLiveTest.java       |  18 ++--
 .../nosql/cassandra/CassandraNodeImpl.java      |   7 +-
 .../entity/proxy/AbstractControllerImpl.java    |  11 +-
 .../entity/webapp/DynamicWebAppClusterImpl.java |   9 +-
 .../webapp/JavaWebAppSoftwareProcessImpl.java   |   8 +-
 .../entity/webapp/jetty/Jetty6ServerImpl.java   |   1 -
 .../java/brooklyn/test/EntityTestUtils.java     |  12 ++-
 21 files changed, 357 insertions(+), 89 deletions(-)
----------------------------------------------------------------------



[2/9] git commit: increase JMX poll frequency slightly (to 3s rather than 500ms) as it's a bit expensive

Posted by al...@apache.org.
increase JMX poll frequency slightly (to 3s rather than 500ms) as it's a bit expensive


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

Branch: refs/heads/master
Commit: 424bda6845aeb67a42e4da2038598a34929493ce
Parents: e58b744
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jul 31 02:13:52 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Jul 31 02:15:05 2014 -0400

----------------------------------------------------------------------
 .../src/main/java/brooklyn/entity/java/VanillaJavaAppImpl.java     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/424bda68/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 c163251..64577e2 100644
--- a/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppImpl.java
@@ -80,7 +80,7 @@ public class VanillaJavaAppImpl extends SoftwareProcessImpl implements VanillaJa
         super.connectSensors();
 
         if (((VanillaJavaAppDriver) getDriver()).isJmxEnabled()) {
-            jmxPollPeriod = (jmxPollPeriod > 0) ? jmxPollPeriod : 500;
+            jmxPollPeriod = (jmxPollPeriod > 0) ? jmxPollPeriod : 3000;
             jmxFeed = JavaAppUtils.connectMXBeanSensors(this, jmxPollPeriod);
         }
 


[4/9] git commit: add failing test for enrichers being added multiple times on rebind

Posted by al...@apache.org.
add failing test for enrichers being added multiple times on rebind


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

Branch: refs/heads/master
Commit: d135df402c3b93f69772418babec004678cebd94
Parents: e6b7af4
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jul 31 02:14:27 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Jul 31 02:15:30 2014 -0400

----------------------------------------------------------------------
 .../entity/java/VanillaJavaAppRebindTest.java   | 59 +++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/d135df40/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 19d6082..7ba7e36 100644
--- a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
@@ -24,20 +24,26 @@ import java.io.File;
 
 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.enricher.RollingTimeWindowMeanEnricher;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.java.JavaOptsTest.TestingJavaOptsVanillaJavaAppImpl;
 import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.entity.rebind.RebindTestUtils;
+import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.Sensors;
 import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.test.EntityTestUtils;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
+import brooklyn.util.time.Duration;
+import brooklyn.util.time.Time;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
@@ -113,7 +119,58 @@ public class VanillaJavaAppRebindTest {
         VanillaJavaApp javaProcess2 = (VanillaJavaApp) Iterables.find(app.getChildren(), Predicates.instanceOf(VanillaJavaApp.class));
         EntityTestUtils.assertAttributeEqualsEventually(javaProcess2, VanillaJavaApp.SERVICE_UP, false);
         
-        // check that it was quick (previously it hung for 
+        // check that it was quick (previously it hung)
         assertTrue(rebindTime < 30*1000, "rebindTime="+rebindTime);
     }
+    
+    
+    @Test(groups="Integration")
+    public void testEnrichersOnRebindJavaApp() throws Exception {
+        VanillaJavaApp javaProcess = app.addChild(EntitySpec.create(VanillaJavaApp.class, EnrichedVanillaJavaAppImpl.class)
+            .configure("main", MAIN_CLASS.getCanonicalName()).configure("classpath", ImmutableList.of(BROOKLYN_THIS_CLASSPATH)));
+
+        Entities.manage(javaProcess);
+        app.start(ImmutableList.of(loc));
+
+        EntityTestUtils.assertAttributeEventuallyNonNull(javaProcess, EnrichedVanillaJavaAppImpl.AVG1);
+        EntityTestUtils.assertAttributeEventuallyNonNull(javaProcess, EnrichedVanillaJavaAppImpl.AVG2);
+        LOG.info("Got avg "+javaProcess.getAttribute(EnrichedVanillaJavaAppImpl.AVG1));
+
+        rebind();
+        VanillaJavaApp javaProcess2 = (VanillaJavaApp) Iterables.find(app.getChildren(), Predicates.instanceOf(VanillaJavaApp.class));
+
+        // check sensors working
+        EntityTestUtils.assertAttributeEventually(javaProcess2, EnrichedVanillaJavaAppImpl.PROCESS_CPU_TIME, 
+            Predicates.not(Predicates.equalTo(javaProcess2.getAttribute(EnrichedVanillaJavaAppImpl.PROCESS_CPU_TIME))));
+        LOG.info("Avg now "+javaProcess2.getAttribute(EnrichedVanillaJavaAppImpl.AVG1));
+        
+        // check enrichers are functioning
+        EntityTestUtils.assertAttributeEventually(javaProcess2, EnrichedVanillaJavaAppImpl.AVG1, 
+            Predicates.not(Predicates.equalTo(javaProcess2.getAttribute(EnrichedVanillaJavaAppImpl.AVG1))));
+        EntityTestUtils.assertAttributeEventually(javaProcess2, EnrichedVanillaJavaAppImpl.AVG2,
+            Predicates.not(Predicates.equalTo(javaProcess2.getAttribute(EnrichedVanillaJavaAppImpl.AVG2))));
+        LOG.info("Avg now "+javaProcess2.getAttribute(EnrichedVanillaJavaAppImpl.AVG1));
+        
+        // and check we don't have too many
+        Assert.assertEquals(javaProcess2.getEnrichers().size(), javaProcess.getEnrichers().size());
+    }
+
+    public static class EnrichedVanillaJavaAppImpl extends VanillaJavaAppImpl {
+        private static final AttributeSensor<Double> AVG1 = Sensors.newDoubleSensor("avg1");
+        private static final AttributeSensor<Double> AVG2 = Sensors.newDoubleSensor("avg2");
+        
+        @Override
+        public void onManagementStarted() {
+            super.onManagementStarted();
+            LOG.info("mgmt started for "+this);
+            addEnricher(new RollingTimeWindowMeanEnricher<Double>(this, PROCESS_CPU_TIME, AVG1, Duration.TEN_SECONDS));
+        }
+        @Override
+        protected void connectSensors() {
+            super.connectSensors();
+            LOG.info("connecting sensors for "+this);
+            addEnricher(new RollingTimeWindowMeanEnricher<Double>(this, PROCESS_CPU_TIME, AVG2, Duration.TEN_SECONDS));
+        }
+    }
+
 }


[6/9] git commit: explicitly fix two of the instances where enrichers and policies were being added again on rebind

Posted by al...@apache.org.
explicitly fix two of the instances where enrichers and policies were being added again on rebind


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

Branch: refs/heads/master
Commit: 51145520aced1b20a482f78bde4b43cfa4697b8d
Parents: d135df4
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jul 31 02:55:35 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Jul 31 03:40:09 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/entity/proxy/AbstractControllerImpl.java    | 11 ++++++++++-
 .../brooklyn/entity/webapp/DynamicWebAppClusterImpl.java |  9 +++++++--
 2 files changed, 17 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/51145520/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java b/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java
index 9542b88..9e0b151 100644
--- a/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/proxy/AbstractControllerImpl.java
@@ -32,8 +32,8 @@ import org.slf4j.LoggerFactory;
 import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
 import brooklyn.entity.basic.Entities;
-import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.basic.Lifecycle;
 import brooklyn.entity.basic.SoftwareProcessImpl;
 import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
 import brooklyn.entity.group.Cluster;
@@ -42,6 +42,7 @@ import brooklyn.event.AttributeSensor;
 import brooklyn.event.feed.ConfigToAttributes;
 import brooklyn.location.access.BrooklynAccessUtils;
 import brooklyn.management.Task;
+import brooklyn.policy.Policy;
 import brooklyn.policy.PolicySpec;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.guava.Maybe;
@@ -110,6 +111,14 @@ public abstract class AbstractControllerImpl extends SoftwareProcessImpl impleme
             LOG.warn("Call to addServerPoolMemberTrackingPolicy when serverPoolMemberTrackingPolicy already exists, in {}", this);
             removeServerPoolMemberTrackingPolicy();
         }
+        for (Policy p: getPolicies()) {
+            if (p instanceof ServerPoolMemberTrackerPolicy) {
+                // TODO want a more elegant idiom for this!
+                LOG.info(this+" picking up "+p+" as the tracker (already set, often due to rebind)");
+                serverPoolMemberTrackerPolicy = (ServerPoolMemberTrackerPolicy) p;
+                return;
+            }
+        }
         
         AttributeSensor<?> hostAndPortSensor = getConfig(HOST_AND_PORT_SENSOR);
         AttributeSensor<?> hostnameSensor = getConfig(HOSTNAME_SENSOR);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/51145520/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
----------------------------------------------------------------------
diff --git a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
index 1b40195..bfdc666 100644
--- a/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
+++ b/software/webapp/src/main/java/brooklyn/entity/webapp/DynamicWebAppClusterImpl.java
@@ -76,7 +76,8 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
     }
     
     @Override
-    public void onManagementBecomingMaster() {
+    public void init() {
+        super.init();
         // Enricher attribute setup.  A way of automatically discovering these (but avoiding
         // averaging things like HTTP port and response codes) would be neat.
         List<? extends List<? extends AttributeSensor<? extends Number>>> summingEnricherSetup = ImmutableList.of(
@@ -120,7 +121,11 @@ public class DynamicWebAppClusterImpl extends DynamicClusterImpl implements Dyna
                     .computingAverage()
                     .build());
         }
-
+    }
+    
+    public void onManagementStarted() {
+        super.onManagementStarted();
+        
         subscribeToMembers(this, SERVICE_UP, new SensorEventListener<Boolean>() {
             @Override public void onEvent(SensorEvent<Boolean> event) {
                 if (!isRebinding()) {


[8/9] git commit: address code review comments

Posted by al...@apache.org.
address code review comments


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

Branch: refs/heads/master
Commit: 059d03f40e7a7246faae1210c627a6634ec79af1
Parents: cc64c47
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Aug 1 02:16:26 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Aug 1 02:16:26 2014 -0400

----------------------------------------------------------------------
 .../main/java/brooklyn/entity/basic/AbstractEntity.java | 11 +++++++++--
 .../brooklyn/entity/java/VanillaJavaAppRebindTest.java  | 10 +++-------
 .../src/main/java/brooklyn/test/EntityTestUtils.java    | 12 +++++++++++-
 3 files changed, 23 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/059d03f4/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 105586a..0d0ec2f 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -1157,8 +1157,15 @@ public abstract class AbstractEntity implements EntityLocal, EntityInternal {
     private <T> boolean hasApparentlyEqualsAndWarn(Collection<? extends T> items, T newItem) {
         T oldItem = findApparentlyEquals(items, newItem);
         if (oldItem!=null) {
-            LOG.warn("Adding to "+this+", "+newItem+" appears identical to existing "+oldItem+"; will remove after adding");
-            return true;
+            if (isRebinding()) {
+                LOG.warn("Adding to "+this+", "+newItem+" appears identical to existing "+oldItem+"; will remove after adding. "
+                    + "Underlying addition should be checked as this behavior will likely be removed without further notice.");
+                return true;
+            } else {
+                LOG.warn("Adding to "+this+", "+newItem+" appears identical to existing "+oldItem+"; may get removed on rebind. "
+                    + "If unintended, addition should be removed. If intended, enricher should be modified so difference is apparent.");
+                return false;
+            }
         } else {
             return false;
         }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/059d03f4/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 7ba7e36..4600cd7 100644
--- a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
@@ -43,7 +43,6 @@ import brooklyn.test.entity.TestApplication;
 import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.time.Duration;
-import brooklyn.util.time.Time;
 
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
@@ -140,15 +139,12 @@ public class VanillaJavaAppRebindTest {
         VanillaJavaApp javaProcess2 = (VanillaJavaApp) Iterables.find(app.getChildren(), Predicates.instanceOf(VanillaJavaApp.class));
 
         // check sensors working
-        EntityTestUtils.assertAttributeEventually(javaProcess2, EnrichedVanillaJavaAppImpl.PROCESS_CPU_TIME, 
-            Predicates.not(Predicates.equalTo(javaProcess2.getAttribute(EnrichedVanillaJavaAppImpl.PROCESS_CPU_TIME))));
+        EntityTestUtils.assertAttributeChangesEventually(javaProcess2, EnrichedVanillaJavaAppImpl.PROCESS_CPU_TIME); 
         LOG.info("Avg now "+javaProcess2.getAttribute(EnrichedVanillaJavaAppImpl.AVG1));
         
         // check enrichers are functioning
-        EntityTestUtils.assertAttributeEventually(javaProcess2, EnrichedVanillaJavaAppImpl.AVG1, 
-            Predicates.not(Predicates.equalTo(javaProcess2.getAttribute(EnrichedVanillaJavaAppImpl.AVG1))));
-        EntityTestUtils.assertAttributeEventually(javaProcess2, EnrichedVanillaJavaAppImpl.AVG2,
-            Predicates.not(Predicates.equalTo(javaProcess2.getAttribute(EnrichedVanillaJavaAppImpl.AVG2))));
+        EntityTestUtils.assertAttributeChangesEventually(javaProcess2, EnrichedVanillaJavaAppImpl.AVG1); 
+        EntityTestUtils.assertAttributeChangesEventually(javaProcess2, EnrichedVanillaJavaAppImpl.AVG2);
         LOG.info("Avg now "+javaProcess2.getAttribute(EnrichedVanillaJavaAppImpl.AVG1));
         
         // and check we don't have too many

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/059d03f4/usage/test-support/src/main/java/brooklyn/test/EntityTestUtils.java
----------------------------------------------------------------------
diff --git a/usage/test-support/src/main/java/brooklyn/test/EntityTestUtils.java b/usage/test-support/src/main/java/brooklyn/test/EntityTestUtils.java
index 75dd2d7..43b3322 100644
--- a/usage/test-support/src/main/java/brooklyn/test/EntityTestUtils.java
+++ b/usage/test-support/src/main/java/brooklyn/test/EntityTestUtils.java
@@ -35,6 +35,7 @@ import brooklyn.event.SensorEvent;
 import brooklyn.event.SensorEventListener;
 import brooklyn.management.SubscriptionHandle;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
@@ -125,7 +126,8 @@ public class EntityTestUtils {
                 assertEquals(members.size(), expected, "members="+members);
             }});
     }
-    
+
+    /** checks that the entity's value for this attribute changes, by registering a subscription and checking the value */
     public static void assertAttributeChangesEventually(final Entity entity, final AttributeSensor<?> attribute) {
         final Object origValue = entity.getAttribute(attribute);
         final AtomicBoolean changed = new AtomicBoolean();
@@ -144,4 +146,12 @@ public class EntityTestUtils {
             ((EntityLocal)entity).unsubscribe(entity, handle);
         }
     }
+    
+    /** alternate version of {@link #assertAttributeChangesEventually(Entity, AttributeSensor)} not using subscriptions and 
+     * with simpler code, for comparison */
+    @Beta
+    public static <T> void assertAttributeChangesEventually2(final Entity entity, final AttributeSensor<T> attribute) {
+        assertAttributeEventually(entity, attribute, 
+            Predicates.not(Predicates.equalTo(entity.getAttribute(attribute))));
+    }
 }


[3/9] git commit: fix vanilla-java integration tests, and clarify the API and fix paths used in ArchiveBuilder which caused the problems (jars can't use "./" prefix, and these jars had "./test-classes/" !); also clean up warnings and javadoc

Posted by al...@apache.org.
fix vanilla-java integration tests, and clarify the API and fix paths used in ArchiveBuilder which caused the problems (jars can't use "./" prefix, and these jars had "./test-classes/" !);
also clean up warnings and javadoc


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

Branch: refs/heads/master
Commit: e58b744f0274d0c2e9587c78e8eeb786507067cd
Parents: 07bfb05
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jul 31 01:25:20 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Jul 31 02:15:05 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/entity/basic/AbstractEntity.java   |  12 ++-
 .../java/brooklyn/util/file/ArchiveBuilder.java | 102 ++++++++++++++-----
 .../brooklyn/test/entity/TestApplication.java   |  10 +-
 .../test/entity/TestApplicationImpl.java        |   7 ++
 .../brooklyn/util/file/ArchiveBuilderTest.java  |  51 +++++++++-
 .../brooklynnode/BrooklynNodeSshDriver.java     |   2 +-
 .../entity/java/VanillaJavaAppSshDriver.java    |   3 +-
 .../brooklyn/entity/java/EntityPollingTest.java |  15 +--
 .../brooklyn/entity/java/JmxSupportTest.java    |  14 +--
 .../entity/java/VanillaJavaAppRebindTest.java   |   8 +-
 .../entity/java/VanillaJavaAppTest.java         |   7 +-
 .../storm/StormAbstractCloudLiveTest.java       |  18 ++--
 12 files changed, 174 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/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 438f407..d2ae2e1 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -1212,7 +1212,7 @@ public abstract class AbstractEntity implements EntityLocal, EntityInternal {
 
     /**
      * Invoked by {@link EntityManagementSupport} when this entity is becoming managed (i.e. it has a working
-     * management context, but before the entity is visible to other entities).
+     * management context, but before the entity is visible to other entities), including during a rebind.
      */
     public void onManagementStarting() {
         if (isLegacyConstruction()) {
@@ -1227,24 +1227,26 @@ public abstract class AbstractEntity implements EntityLocal, EntityInternal {
      */
     public void onManagementStarted() {}
     
-    // FIXME Really deprecated? I don't want folk to have to override createManagementSupport for simple use-cases
     /**
      * Invoked by {@link ManagementContext} when this entity becomes managed at a particular management node,
      * including the initial management started and subsequent management node master-change for this entity.
-     * @deprecated since 0.4.0 override EntityManagementSupport.onManagementStarting if customization needed
+     * @deprecated since 0.4.0 override EntityManagementSupport.onManagementStarted if customization needed
      */
     public void onManagementBecomingMaster() {}
     
-    // FIXME Really deprecated? I don't want folk to have to override createManagementSupport for simple use-cases
     /**
      * Invoked by {@link ManagementContext} when this entity becomes mastered at a particular management node,
      * including the final management end and subsequent management node master-change for this entity.
-     * @deprecated since 0.4.0 override EntityManagementSupport.onManagementStopping if customization needed
+     * @deprecated since 0.4.0 override EntityManagementSupport.onManagementStopped if customization needed
      */
     public void onManagementNoLongerMaster() {}
 
     /**
      * Invoked by {@link EntityManagementSupport} when this entity is fully unmanaged.
+     * <p>
+     * Note that the activies possible here (when unmanaged) are limited, 
+     * and that this event may be caused by either a brooklyn node itself being demoted
+     * (so the entity is managed elsewhere) or by a controlled shutdown.
      */
     public void onManagementStopped() {
         if (getManagementContext().isRunning()) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/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
index b8e1d30..b5c98f5 100644
--- a/core/src/main/java/brooklyn/util/file/ArchiveBuilder.java
+++ b/core/src/main/java/brooklyn/util/file/ArchiveBuilder.java
@@ -25,6 +25,7 @@ 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;
@@ -36,7 +37,9 @@ import brooklyn.util.exceptions.Exceptions;
 import brooklyn.util.file.ArchiveUtils.ArchiveType;
 import brooklyn.util.os.Os;
 
-import com.google.common.collect.Maps;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
 import com.google.common.io.ByteStreams;
 import com.google.common.io.Files;
 
@@ -85,10 +88,10 @@ public class ArchiveBuilder {
         return new ArchiveBuilder(ArchiveType.JAR);
     }
 
-    private ArchiveType type;
+    private final ArchiveType type;
     private File archive;
     private Manifest manifest;
-    private Map<String, File> entries = Maps.newHashMap();
+    private Multimap<String, File> entries = LinkedHashMultimap.create();
 
     private ArchiveBuilder() {
         this(ArchiveType.ZIP);
@@ -142,10 +145,10 @@ public class ArchiveBuilder {
     }
 
     /**
-     * Add the file located at the {@code filePath} to the archive.
+     * Add the file located at the {@code filePath} to the archive, 
+     * with some complicated base-name strategies.
      *
-     * @see #add(File)
-     */
+     * @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)));
@@ -163,7 +166,7 @@ public class ArchiveBuilder {
      * 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());
@@ -179,7 +182,7 @@ public class ArchiveBuilder {
      * to the archive.
      * <p>
      * Uses the {@code filePath} as the name of the file in the archive. Note that the
-     * two path components are simply concatenated using {@link Os#mergePaths(String...)}
+     * file is found by concatenating the two path components using {@link Os#mergePaths(String...)}
      * which may not behave as expected if the {@code filePath} is absolute or points to
      * a location above the current directory.
      * <p>
@@ -188,17 +191,29 @@ public class ArchiveBuilder {
      *
      * @see #entry(String, String)
      */
-    public ArchiveBuilder add(String baseDir, String filePath) {
+    public ArchiveBuilder addRelativeToBaseDir(String baseDir, String filePath) {
         checkNotNull(baseDir, "baseDir");
         checkNotNull(filePath, "filePath");
         return entry(Os.mergePaths(".", filePath), Os.mergePaths(baseDir, filePath));
     }
+    /** @deprecated since 0.7.0 use {@link #addRelativeToBaseDir(String, String)}, or
+     * one of the other add methods if adding relative to baseDir was not intended */ @Deprecated
+    public ArchiveBuilder add(String baseDir, String filePath) {
+        return addRelativeToBaseDir(baseDir, filePath);
+    }
+     
+    /** 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)));
@@ -206,21 +221,33 @@ public class ArchiveBuilder {
 
     /**
      * 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 addDir(File dir) {
+    public ArchiveBuilder addDirContentsAt(File dir, String archiveParentDir) {
         checkNotNull(dir, "dir");
-        return entry(".", 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) {
@@ -234,7 +261,7 @@ public class ArchiveBuilder {
      * 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");
@@ -277,14 +304,15 @@ public class ArchiveBuilder {
      */
     public ArchiveBuilder entries(Map<String, File> entries) {
         checkNotNull(entries, "entries");
-        this.entries.putAll(entries);
+        for (Map.Entry<String, File> entry: entries.entrySet())
+            this.entries.put(entry.getKey(), entry.getValue());
         return this;
     }
 
     /**
-     * Generates the archive and ouputs it to the given stream, ignoring any file name.
+     * Generates the archive and outputs it to the given stream, ignoring any file name.
      * <p>
-     * This will add a manifest filw if the type is a Jar archive.
+     * This will add a manifest file if the type is a Jar archive.
      */
     public void stream(OutputStream output) {
         try {
@@ -296,7 +324,7 @@ public class ArchiveBuilder {
                 target = new JarOutputStream(output, manifest);
             }
             for (String entry : entries.keySet()) {
-                entry(entry, entries.get(entry), target);
+                addToArchive(entry, entries.get(entry), target);
             }
             target.close();
         } catch (IOException ioe) {
@@ -319,7 +347,7 @@ public class ArchiveBuilder {
      */
     public File create() {
         if (archive == null) {
-            File temp = Os.newTempFile("brooklyn-archive", "");
+            File temp = Os.newTempFile("brooklyn-archive", type.toString());
             temp.deleteOnExit();
             named(temp);
         }
@@ -343,26 +371,50 @@ public class ArchiveBuilder {
      * 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 entry(String path, File source, ZipOutputStream target) throws IOException {
+    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 (source.isDirectory()) {
+        if (isDirectory) {
             name += "/";
             JarEntry entry = new JarEntry(name);
-            entry.setTime(source.lastModified());
+            
+            long lastModified=-1;
+            for (File source: sources)
+                if (source.lastModified()>lastModified)
+                    lastModified = source.lastModified();
+            
+            entry.setTime(lastModified);
             target.putNextEntry(entry);
             target.closeEntry();
 
-            Iterable<File> children = Files.fileTreeTraverser().children(source);
-            for (File child : children) {
-                entry(Os.mergePaths(path, child.getName()), child, target);
+            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);
         ByteStreams.copy(Files.newInputStreamSupplier(source), target);
         target.closeEntry();
     }
+    
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/core/src/test/java/brooklyn/test/entity/TestApplication.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/test/entity/TestApplication.java b/core/src/test/java/brooklyn/test/entity/TestApplication.java
index cc0a628..3978090 100644
--- a/core/src/test/java/brooklyn/test/entity/TestApplication.java
+++ b/core/src/test/java/brooklyn/test/entity/TestApplication.java
@@ -18,6 +18,8 @@
  */
 package brooklyn.test.entity;
 
+import java.util.Map;
+
 import brooklyn.entity.Entity;
 import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.EntityInternal;
@@ -27,6 +29,7 @@ import brooklyn.entity.proxying.ImplementedBy;
 import brooklyn.event.AttributeSensor;
 import brooklyn.event.basic.Sensors;
 import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
+import brooklyn.management.ManagementContext;
 
 /**
  * Mock application for testing.
@@ -40,10 +43,15 @@ public interface TestApplication extends StartableApplication, EntityInternal {
     public <T extends Entity> T createAndManageChild(EntitySpec<T> spec);
 
     public LocalhostMachineProvisioningLocation newLocalhostProvisioningLocation();
+    public LocalhostMachineProvisioningLocation newLocalhostProvisioningLocation(Map<?,?> flags);
 
     public static class Factory {
+        public static TestApplication newManagedInstanceForTests(ManagementContext mgmt) {
+            return ApplicationBuilder.newManagedApp(TestApplication.class, mgmt);
+        }
         public static TestApplication newManagedInstanceForTests() {
-            return ApplicationBuilder.newManagedApp(TestApplication.class, new LocalManagementContextForTests());
+            return newManagedInstanceForTests(new LocalManagementContextForTests());
         }
     }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/core/src/test/java/brooklyn/test/entity/TestApplicationImpl.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/test/entity/TestApplicationImpl.java b/core/src/test/java/brooklyn/test/entity/TestApplicationImpl.java
index 8a9031f..ae5c963 100644
--- a/core/src/test/java/brooklyn/test/entity/TestApplicationImpl.java
+++ b/core/src/test/java/brooklyn/test/entity/TestApplicationImpl.java
@@ -29,6 +29,7 @@ import brooklyn.entity.basic.AbstractApplication;
 import brooklyn.entity.proxying.EntitySpec;
 import brooklyn.event.Sensor;
 import brooklyn.event.SensorEventListener;
+import brooklyn.location.LocationSpec;
 import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import brooklyn.management.SubscriptionHandle;
 import brooklyn.util.logging.LoggingSetup;
@@ -76,9 +77,15 @@ public class TestApplicationImpl extends AbstractApplication implements TestAppl
         return "Application["+id.substring(Math.max(0, id.length()-8))+"]";
     }
 
+    @Override
     public LocalhostMachineProvisioningLocation newLocalhostProvisioningLocation() {
         return (LocalhostMachineProvisioningLocation) getManagementContext().getLocationRegistry().resolve("localhost");
     }
+    @Override
+    public LocalhostMachineProvisioningLocation newLocalhostProvisioningLocation(Map<?,?> flags) {
+        return (LocalhostMachineProvisioningLocation) getManagementContext().getLocationManager().createLocation(
+            LocationSpec.create(LocalhostMachineProvisioningLocation.class).configure(flags));
+    }
 
     @Override
     protected void logApplicationLifecycle(String message) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/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
index 5840229..222a312 100644
--- a/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java
+++ b/core/src/test/java/brooklyn/util/file/ArchiveBuilderTest.java
@@ -19,6 +19,7 @@
 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;
@@ -26,6 +27,7 @@ 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;
 
@@ -34,6 +36,7 @@ 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;
 
@@ -50,7 +53,7 @@ import com.google.common.io.Files;
 @Test
 public class ArchiveBuilderTest {
 
-    private File parentDir, tmpDir;
+    private File parentDir, tmpDir, tmpDir2;
     private Predicate<ZipEntry> isDirectory = new Predicate<ZipEntry>() {
                 @Override
                 public boolean apply(@Nullable ZipEntry input) {
@@ -60,18 +63,22 @@ public class ArchiveBuilderTest {
 
     @BeforeClass
     public void createTmpDirAndFiles() throws IOException {
-        parentDir = new File(Os.tmp(), Identifiers.makeRandomId(4));
+        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().addDir(tmpDir).create();
+        File archive = ArchiveBuilder.zip().addDirContentsAt(tmpDir, ".").create();
         archive.deleteOnExit();
 
         List<ZipEntry> entries = Lists.newArrayList();
@@ -88,17 +95,51 @@ public class ArchiveBuilderTest {
         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.add(new File(tmpDir, fileName).getAbsolutePath());
+            builder.addAt(new File(tmpDir, fileName), ".");
         }
         File archive = builder.create();
         archive.deleteOnExit();
@@ -126,7 +167,7 @@ public class ArchiveBuilderTest {
         ArchiveBuilder builder = ArchiveBuilder.zip();
         String baseDir = tmpDir.getName();
         for (String fileName : Arrays.asList("data01.txt", "data02.txt", "data03.txt")) {
-            builder.add(parentDir.getPath(), Os.mergePaths(baseDir, fileName));
+            builder.addRelativeToBaseDir(parentDir.getPath(), Os.mergePaths(baseDir, fileName));
         }
         File archive = builder.create();
         archive.deleteOnExit();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/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 b2d24af..74b3f14 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
@@ -202,7 +202,7 @@ public class BrooklynNodeSshDriver extends JavaSoftwareProcessSshDriver implemen
         for (String entry : getEntity().getClasspath()) {
             // If a local folder, then create archive from contents first
             if (Urls.isDirectory(entry)) {
-                File jarFile = ArchiveBuilder.jar().add(entry).create();
+                File jarFile = ArchiveBuilder.jar().addDirContentsAt(new File(entry), "").create();
                 entry = jarFile.getAbsolutePath();
             }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/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 8cd237e..e746677 100644
--- a/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppSshDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/java/VanillaJavaAppSshDriver.java
@@ -88,7 +88,7 @@ public class VanillaJavaAppSshDriver extends JavaSoftwareProcessSshDriver implem
         for (String entry : entity.getClasspath()) {
             // If a local folder, then create archive from contents first
             if (Urls.isDirectory(entry)) {
-                File jarFile = ArchiveBuilder.jar().add(entry).create();
+                File jarFile = ArchiveBuilder.jar().addDirContentsAt(new File(entry), "").create();
                 entry = jarFile.getAbsolutePath();
             }
 
@@ -126,6 +126,7 @@ public class VanillaJavaAppSshDriver extends JavaSoftwareProcessSshDriver implem
     }
 
     public String getClasspath() {
+        @SuppressWarnings("unchecked")
         List<String> files = getEntity().getAttribute(VanillaJavaApp.CLASSPATH_FILES);
         if (files == null || files.isEmpty()) {
             return null;

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/software/base/src/test/java/brooklyn/entity/java/EntityPollingTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/java/EntityPollingTest.java b/software/base/src/test/java/brooklyn/entity/java/EntityPollingTest.java
index 7960a07..4aeeef5 100644
--- a/software/base/src/test/java/brooklyn/entity/java/EntityPollingTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/EntityPollingTest.java
@@ -27,7 +27,6 @@ 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.basic.SoftwareProcess;
 import brooklyn.entity.java.UsesJmx.JmxAgentModes;
@@ -38,7 +37,6 @@ import brooklyn.event.feed.jmx.JmxFeed;
 import brooklyn.location.MachineLocation;
 import brooklyn.location.basic.SshMachineLocation;
 import brooklyn.test.EntityTestUtils;
-import brooklyn.test.GeneralisedDynamicMBean;
 import brooklyn.test.JmxService;
 import brooklyn.test.entity.TestApplication;
 import brooklyn.util.collections.MutableMap;
@@ -51,9 +49,6 @@ public class EntityPollingTest {
 
     private static final Logger LOG = LoggerFactory.getLogger(EntityPollingTest.class);
 
-    private static final int TIMEOUT_MS = 5000;
-    private static final int SHORT_WAIT = 250;
-    
     private JmxService jmxService;
     private TestApplication app;
     private SoftwareProcess entity;
@@ -72,7 +67,6 @@ public class EntityPollingTest {
     }
 
     private static final String attributeName = "myattrib";
-    private static final String opName = "myop";
 
     public static class SubVanillaJavaApp extends VanillaJavaAppImpl {
         private JmxFeed feed;
@@ -95,6 +89,7 @@ public class EntityPollingTest {
             if (feed != null) feed.stop();
         }
         
+        @SuppressWarnings({ "rawtypes", "unchecked" })
         @Override
         public Class getDriverInterface() {
             return null;
@@ -149,7 +144,7 @@ public class EntityPollingTest {
     @Test(groups="Integration")
     public void testSimpleConnection() throws Exception {
         jmxService = new JmxService("localhost", 40123);
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(attributeName, "myval"), objectName);
+        jmxService.registerMBean(ImmutableMap.of(attributeName, "myval"), objectName);
 
         app.start(ImmutableList.of(new SshMachineLocation(MutableMap.of("address", "localhost"))));
         
@@ -166,7 +161,7 @@ public class EntityPollingTest {
                 try {
                     Thread.sleep(2000);
                     jmxService = new JmxService("localhost", 40123);
-                    GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(attributeName, "myval"), objectName);
+                    jmxService.registerMBean(ImmutableMap.of(attributeName, "myval"), objectName);
                 } catch (Exception e) {
                     LOG.error("Error in testEntityWithDelayedJmxStartupWillKeepRetrying", e);
                     throw Exceptions.propagate(e);
@@ -187,7 +182,7 @@ public class EntityPollingTest {
     @Test(groups="Integration")
     public void testJmxConnectionGoesDownRequiringReconnect() throws Exception {
         jmxService = new JmxService("localhost", 40123);
-        GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(attributeName, "myval"), objectName);
+        jmxService.registerMBean(ImmutableMap.of(attributeName, "myval"), objectName);
 
         app.start(ImmutableList.of(new SshMachineLocation(MutableMap.of("address", "localhost"))));
         
@@ -202,7 +197,7 @@ public class EntityPollingTest {
 
         // Restart MBeanServer, and set attribute to different value; expect it to be polled again
         jmxService = new JmxService("localhost", 40123);
-        GeneralisedDynamicMBean mbean2 = jmxService.registerMBean(ImmutableMap.of(attributeName, "myval2"), objectName);
+        jmxService.registerMBean(ImmutableMap.of(attributeName, "myval2"), objectName);
         
         EntityTestUtils.assertAttributeEqualsEventually(entity, stringAttribute, "myval2");
     }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/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 236f359..8bd3547 100644
--- a/software/base/src/test/java/brooklyn/entity/java/JmxSupportTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/JmxSupportTest.java
@@ -26,7 +26,6 @@ import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.Test;
 
-import brooklyn.entity.basic.ApplicationBuilder;
 import brooklyn.entity.basic.Entities;
 import brooklyn.entity.java.UsesJmx.JmxAgentModes;
 import brooklyn.test.entity.TestApplication;
@@ -35,6 +34,7 @@ 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;
 import brooklyn.util.text.Strings;
 
 @Test
@@ -51,14 +51,14 @@ public class JmxSupportTest {
     
     // defaults to JMXMP for most locations (or, in this case, if it does not yet know the location)
     public void testJmxAutodetect() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        app = TestApplication.Factory.newManagedInstanceForTests();
         JmxSupport support = new JmxSupport(app, null);
         
         Assert.assertEquals(support.getJmxAgentMode(), JmxAgentModes.JMXMP_AND_RMI);
     }
 
     public void testJmxmpJarExistence() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        app = TestApplication.Factory.newManagedInstanceForTests();
         app.setConfig(JmxSupport.JMX_AGENT_MODE, JmxAgentModes.JMXMP);
         JmxSupport support = new JmxSupport(app, null);
         
@@ -70,7 +70,7 @@ public class JmxSupportTest {
     }
     
     public void testJmxrmiJarExistence() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        app = TestApplication.Factory.newManagedInstanceForTests();
         JmxSupport support = new JmxSupport(app, null);
         app.setConfig(JmxSupport.JMX_AGENT_MODE, JmxAgentModes.JMX_RMI_CUSTOM_AGENT);
         
@@ -97,7 +97,7 @@ public class JmxSupportTest {
 
     @Test(groups="Integration")
     public void testJmxmpJarHostedValidity() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        app = TestApplication.Factory.newManagedInstanceForTests();
         app.setConfig(JmxSupport.JMX_AGENT_MODE, JmxAgentModes.JMXMP);
         JmxSupport support = new JmxSupport(app, null);
 
@@ -108,7 +108,7 @@ public class JmxSupportTest {
     
     @Test(groups="Integration")
     public void testJmxrmiJarHostedValidity() {
-        app = ApplicationBuilder.newManagedApp(TestApplication.class);
+        app = TestApplication.Factory.newManagedInstanceForTests();
         JmxSupport support = new JmxSupport(app, null);
         app.setConfig(JmxSupport.JMX_AGENT_MODE, JmxAgentModes.JMX_RMI_CUSTOM_AGENT);
         
@@ -119,7 +119,7 @@ public class JmxSupportTest {
     private void checkValidArchive(String url, long minSize) {
         byte[] bytes;
         try {
-            bytes = ResourceUtils.readFullyBytes(ResourceUtils.create(this).getResourceFromUrl(url));
+            bytes = Streams.readFully(ResourceUtils.create(this).getResourceFromUrl(url));
             log.info("read "+bytes.length+" bytes from "+url+" for "+JavaClassNames.callerNiceClassAndMethod(1));
         } catch (Exception e) {
             log.warn("Unable to read URL "+url+" for " +JavaClassNames.callerNiceClassAndMethod(1)+

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/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 f7a133f..19d6082 100644
--- a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppRebindTest.java
@@ -36,7 +36,6 @@ import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
 import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.test.EntityTestUtils;
 import brooklyn.test.entity.TestApplication;
-import brooklyn.test.entity.TestApplicationImpl;
 import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 
@@ -49,8 +48,6 @@ public class VanillaJavaAppRebindTest {
 
     private static final Logger LOG = LoggerFactory.getLogger(VanillaJavaAppRebindTest.class);
     
-    private static final long TIMEOUT_MS = 10*1000;
-
     private static String BROOKLYN_THIS_CLASSPATH = null;
     private static Class<?> MAIN_CLASS = ExampleVanillaMain.class;
 
@@ -68,9 +65,8 @@ public class VanillaJavaAppRebindTest {
         if (BROOKLYN_THIS_CLASSPATH==null) {
             BROOKLYN_THIS_CLASSPATH = ResourceUtils.create(MAIN_CLASS).getClassLoaderDir();
         }
-        app = new TestApplicationImpl();
-        loc = new LocalhostMachineProvisioningLocation(MutableMap.of("address", "localhost"));
-        Entities.startManagement(app, managementContext);
+        app = TestApplication.Factory.newManagedInstanceForTests(managementContext);
+        loc = app.newLocalhostProvisioningLocation(MutableMap.of("address", "localhost"));
     }
 
     @AfterMethod(alwaysRun = true)

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/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 851aebd..a1347bf 100644
--- a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java
+++ b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java
@@ -92,7 +92,7 @@ public class VanillaJavaAppTest {
             BROOKLYN_THIS_CLASSPATH = ResourceUtils.create(MAIN_CLASS).getClassLoaderDir();
         }
         app = TestApplication.Factory.newManagedInstanceForTests();
-        loc = new LocalhostMachineProvisioningLocation(MutableMap.of("address", "localhost"));
+        loc = app.newLocalhostProvisioningLocation(MutableMap.of("address", "localhost"));
     }
 
     @AfterMethod(alwaysRun = true)
@@ -126,7 +126,6 @@ public class VanillaJavaAppTest {
         final VanillaJavaApp javaProcess = app.createAndManageChild(EntitySpec.create(VanillaJavaApp.class)
             .configure("main", main).configure("classpath", ImmutableList.of(BROOKLYN_THIS_CLASSPATH))
             .configure("args", ImmutableList.of()));
-        Entities.startManagement(app);
         app.start(ImmutableList.of(loc));
         assertEquals(javaProcess.getAttribute(VanillaJavaApp.SERVICE_STATE), Lifecycle.RUNNING);
 
@@ -140,7 +139,6 @@ public class VanillaJavaAppTest {
         final VanillaJavaApp javaProcess = app.createAndManageChild(EntitySpec.create(VanillaJavaApp.class)
             .configure("main", main).configure("classpath", ImmutableList.of(BROOKLYN_THIS_CLASSPATH))
             .configure("args", ImmutableList.of()));
-        Entities.startManagement(app);
         app.start(ImmutableList.of(loc));
         
         // Memory MXBean
@@ -198,7 +196,6 @@ public class VanillaJavaAppTest {
         final VanillaJavaApp javaProcess = app.createAndManageChild(EntitySpec.create(VanillaJavaApp.class)
             .configure("main", main).configure("classpath", ImmutableList.of(BROOKLYN_THIS_CLASSPATH))
             .configure("args", ImmutableList.of()));
-        Entities.startManagement(app);
         app.start(ImmutableList.of(loc));
 
         JavaAppUtils.connectJavaAppServerPolicies((EntityLocal)javaProcess);
@@ -244,7 +241,6 @@ public class VanillaJavaAppTest {
             .configure("main", main).configure("classpath", ImmutableList.of(BROOKLYN_THIS_CLASSPATH))
             .configure("args", ImmutableList.of()));
         ((EntityLocal)javaProcess).setConfig(UsesJmx.JMX_PORT, PortRanges.fromInteger(port));
-        Entities.startManagement(app);
         app.start(ImmutableList.of(loc));
 
         assertEquals(javaProcess.getAttribute(UsesJmx.JMX_PORT), (Integer)port);
@@ -261,7 +257,6 @@ public class VanillaJavaAppTest {
         ((EntityLocal)javaProcess).setConfig(UsesJmx.JMX_PORT, PortRanges.fromInteger(port));
         ((EntityLocal)javaProcess).setConfig(UsesJmx.JMX_SSL_ENABLED, true);
         
-        Entities.startManagement(app);
         app.start(ImmutableList.of(loc));
         // will fail above if JMX can't connect, but also do some add'l checks
         

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e58b744f/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 c6024e9..e8cbcd6 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
@@ -52,9 +52,10 @@ import brooklyn.entity.zookeeper.ZooKeeperEnsemble;
 import brooklyn.location.Location;
 import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.test.EntityTestUtils;
+import brooklyn.util.ResourceUtils;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.file.ArchiveBuilder;
-import brooklyn.util.net.Urls;
+import brooklyn.util.os.Os;
 import brooklyn.util.time.Duration;
 import brooklyn.util.time.Time;
 
@@ -149,9 +150,10 @@ public abstract class StormAbstractCloudLiveTest extends BrooklynAppLiveTestSupp
         conf.setDebug(debug);
         conf.setNumWorkers(numOfWorkers);
 
-        // FIXME - won't work for anyone but andrea turli
-        // also, the JAR needs to be with ref to src/test/java to have the right package, no?
-        String jar = createJar("/Users/andrea/git/andreaturli/brooklyn/software/messaging/src/test/java/brooklyn/entity/messaging/storm/topologies");
+        // 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);
@@ -186,12 +188,12 @@ public abstract class StormAbstractCloudLiveTest extends BrooklynAppLiveTestSupp
         return false;
     }
     
-    private String createJar(String packageName) {
-        if (Urls.isDirectory(packageName)) {
-            File jarFile = ArchiveBuilder.jar().add(packageName).create("topologies.jar");
+    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 packageName; // An existing Jar archive?
+            return dir.getAbsolutePath(); // An existing Jar archive?
         }
     }
 


[5/9] git commit: add a fix for enrichers/policies being added multiple times on rebind, by declining to add an enricher which looks too much like one already present

Posted by al...@apache.org.
add a fix for enrichers/policies being added multiple times on rebind, by declining to add an enricher which looks too much like one already present


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

Branch: refs/heads/master
Commit: cc64c47935fcbeab694fae6a659f5766e7da8ee2
Parents: 6416d44
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Thu Jul 31 02:54:48 2014 -0400
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Thu Jul 31 03:40:09 2014 -0400

----------------------------------------------------------------------
 .../brooklyn/entity/basic/AbstractEntity.java   | 46 ++++++++++++++++++++
 .../policy/basic/AbstractEntityAdjunct.java     |  1 +
 2 files changed, 47 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cc64c479/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 d2ae2e1..105586a 100644
--- a/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
+++ b/core/src/main/java/brooklyn/entity/basic/AbstractEntity.java
@@ -26,12 +26,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
 import brooklyn.config.ConfigKey.HasConfigKey;
 import brooklyn.enricher.basic.AbstractEnricher;
+import brooklyn.enricher.basic.Aggregator;
 import brooklyn.entity.Application;
 import brooklyn.entity.Effector;
 import brooklyn.entity.Entity;
@@ -68,8 +70,10 @@ import brooklyn.management.internal.SubscriptionTracker;
 import brooklyn.mementos.EntityMemento;
 import brooklyn.policy.Enricher;
 import brooklyn.policy.EnricherSpec;
+import brooklyn.policy.EntityAdjunct;
 import brooklyn.policy.Policy;
 import brooklyn.policy.PolicySpec;
+import brooklyn.policy.basic.AbstractEntityAdjunct;
 import brooklyn.policy.basic.AbstractPolicy;
 import brooklyn.util.BrooklynLanguageExtensions;
 import brooklyn.util.collections.MutableList;
@@ -1085,11 +1089,15 @@ public abstract class AbstractEntity implements EntityLocal, EntityInternal {
 
     @Override
     public void addPolicy(Policy policy) {
+        List<Policy> old = MutableList.<Policy>copyOf(policies);
+
         policies.add((AbstractPolicy)policy);
         ((AbstractPolicy)policy).setEntity(this);
         
         getManagementSupport().getEntityChangeListener().onPolicyAdded(policy);
         emit(AbstractEntity.POLICY_ADDED, new PolicyDescriptor(policy));
+        
+        if (hasApparentlyEqualsAndWarn(old, policy)) removePolicy(policy);
     }
 
     @Override
@@ -1135,11 +1143,49 @@ public abstract class AbstractEntity implements EntityLocal, EntityInternal {
 
     @Override
     public void addEnricher(Enricher enricher) {
+        List<Enricher> old = MutableList.<Enricher>copyOf(enrichers);
+        
         enrichers.add((AbstractEnricher) enricher);
         ((AbstractEnricher)enricher).setEntity(this);
         
         getManagementSupport().getEntityChangeListener().onEnricherAdded(enricher);
         // TODO Could add equivalent of AbstractEntity.POLICY_ADDED for enrichers; no use-case for that yet
+        
+        if (hasApparentlyEqualsAndWarn(old, enricher)) removeEnricher(enricher);
+    }
+    
+    private <T> boolean hasApparentlyEqualsAndWarn(Collection<? extends T> items, T newItem) {
+        T oldItem = findApparentlyEquals(items, newItem);
+        if (oldItem!=null) {
+            LOG.warn("Adding to "+this+", "+newItem+" appears identical to existing "+oldItem+"; will remove after adding");
+            return true;
+        } else {
+            return false;
+        }
+    }
+    private <T> T findApparentlyEquals(Collection<? extends T> itemsCopy, T newItem) {
+        // FIXME workaround for issue where enrichers can get added multiple times on rebind,
+        // if it's added in onBecomingManager or connectSensors; the right fix will be more disciplined about how/where these are added
+        // (easier done when sensor feeds are persisted)
+        Class<?> beforeEntityAdjunct = newItem.getClass();
+        while (beforeEntityAdjunct.getSuperclass()!=null && !beforeEntityAdjunct.getSuperclass().equals(AbstractEntityAdjunct.class))
+            beforeEntityAdjunct = beforeEntityAdjunct.getSuperclass();
+        
+        for (T oldItem: itemsCopy) {
+            if (oldItem.getClass().equals(newItem.getClass())) {
+                if (EqualsBuilder.reflectionEquals(oldItem, newItem, false,
+                        // internal admin in 'beforeEntityAdjunct' should be ignored
+                        beforeEntityAdjunct,
+                        // known fields which shouldn't block equality checks:
+                        // from aggregator
+                        "transformation",
+                        // from averager
+                        "values", "timestamps", "lastAverage")) {
+                    return oldItem;
+                }
+            }
+        }
+        return null;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cc64c479/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 a5d324f..203ffa1 100644
--- a/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
+++ b/core/src/main/java/brooklyn/policy/basic/AbstractEntityAdjunct.java
@@ -396,6 +396,7 @@ public abstract class AbstractEntityAdjunct implements EntityAdjunct, Configurab
         return Objects.toStringHelper(getClass())
                 .add("name", name)
                 .add("running", isRunning())
+                .add("id", id)
                 .toString();
     }
 }