add tests for YAML DSL, including serializability, and fix some minor 
serializability issues but not #1422


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

Branch: refs/heads/master
Commit: 3d0cbf4da22b1db6f75ca92a8a9e60244b97c2ab
Parents: 94355d4
Author: Alex Heneveld <alex.henev...@cloudsoftcorp.com>
Authored: Thu May 29 03:13:31 2014 +0100
Committer: Alex Heneveld <alex.henev...@cloudsoftcorp.com>
Committed: Thu May 29 03:44:30 2014 +0100

----------------------------------------------------------------------
 .../brooklyn/entity/basic/EntityPredicates.java |  22 +--
 .../brooklyn/entity/rebind/RebindTestUtils.java |   5 +-
 .../spi/dsl/BrooklynDslDeferredSupplier.java    |   6 +-
 .../spi/dsl/methods/BrooklynDslCommon.java      |   8 +-
 .../brooklyn/spi/dsl/methods/DslComponent.java  |  25 ++-
 .../camp/brooklyn/AbstractYamlTest.java         |  10 +-
 .../camp/brooklyn/DslAndRebindYamlTest.java     | 168 +++++++++++++++++++
 .../camp/brooklyn/EntitiesYamlTest.java         |   2 +-
 ...aWebAppWithDslYamlRebindIntegrationTest.java | 105 ++++++++++++
 ...-java-web-app-spec-and-db-with-function.yaml |  21 +++
 .../util/guava/SerializablePredicate.java       |   8 +
 11 files changed, 360 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/core/src/main/java/brooklyn/entity/basic/EntityPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/basic/EntityPredicates.java 
b/core/src/main/java/brooklyn/entity/basic/EntityPredicates.java
index 930412d..a7b3373 100644
--- a/core/src/main/java/brooklyn/entity/basic/EntityPredicates.java
+++ b/core/src/main/java/brooklyn/entity/basic/EntityPredicates.java
@@ -8,14 +8,16 @@ import brooklyn.entity.Entity;
 import brooklyn.entity.Group;
 import brooklyn.event.AttributeSensor;
 import brooklyn.location.Location;
+import brooklyn.util.guava.SerializablePredicate;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Predicate;
 
+@SuppressWarnings("serial")
 public class EntityPredicates {
 
     public static <T> Predicate<Entity> idEqualTo(final T val) {
-        return new Predicate<Entity>() {
+        return new SerializablePredicate<Entity>() {
             @Override
             public boolean apply(@Nullable Entity input) {
                 return (input != null) && Objects.equal(input.getId(), val);
@@ -24,7 +26,7 @@ public class EntityPredicates {
     }
     
     public static <T> Predicate<Entity> displayNameEqualTo(final T val) {
-        return new Predicate<Entity>() {
+        return new SerializablePredicate<Entity>() {
             @Override
             public boolean apply(@Nullable Entity input) {
                 return (input != null) && 
Objects.equal(input.getDisplayName(), val);
@@ -33,7 +35,7 @@ public class EntityPredicates {
     }
     
     public static Predicate<Entity> applicationIdEqualTo(final String val) {
-        return new Predicate<Entity>() {
+        return new SerializablePredicate<Entity>() {
             @Override
             public boolean apply(@Nullable Entity input) {
                 return (input != null) && val.equals(input.getApplicationId());
@@ -42,7 +44,7 @@ public class EntityPredicates {
     }
 
     public static <T> Predicate<Entity> attributeEqualTo(final 
AttributeSensor<T> attribute, final T val) {
-        return new Predicate<Entity>() {
+        return new SerializablePredicate<Entity>() {
             @Override
             public boolean apply(@Nullable Entity input) {
                 return (input != null) && 
Objects.equal(input.getAttribute(attribute), val);
@@ -51,7 +53,7 @@ public class EntityPredicates {
     }
     
     public static <T> Predicate<Entity> configEqualTo(final ConfigKey<T> 
configKey, final T val) {
-        return new Predicate<Entity>() {
+        return new SerializablePredicate<Entity>() {
             @Override
             public boolean apply(@Nullable Entity input) {
                 return (input != null) && 
Objects.equal(input.getConfig(configKey), val);
@@ -60,7 +62,7 @@ public class EntityPredicates {
     }
 
     public static <T> Predicate<Entity> configEqualTo(final HasConfigKey<T> 
configKey, final T val) {
-        return new Predicate<Entity>() {
+        return new SerializablePredicate<Entity>() {
             @Override
             public boolean apply(@Nullable Entity input) {
                 return (input != null) && 
Objects.equal(input.getConfig(configKey), val);
@@ -72,7 +74,7 @@ public class EntityPredicates {
      * Returns a predicate that determines if a given entity is a direct child 
of this {@code parent}.
      */
     public static <T> Predicate<Entity> isChildOf(final Entity parent) {
-        return new Predicate<Entity>() {
+        return new SerializablePredicate<Entity>() {
             @Override
             public boolean apply(@Nullable Entity input) {
                 return (input != null) && Objects.equal(input.getParent(), 
parent);
@@ -81,7 +83,7 @@ public class EntityPredicates {
     }
 
     public static <T> Predicate<Entity> isMemberOf(final Group group) {
-        return new Predicate<Entity>() {
+        return new SerializablePredicate<Entity>() {
             @Override
             public boolean apply(@Nullable Entity input) {
                 return (input != null) && group.hasMember(input);
@@ -94,7 +96,7 @@ public class EntityPredicates {
      * (i.e. {@code entity.getLocations().contains(location)}).
      */
     public static <T> Predicate<Entity> withLocation(final Location location) {
-        return new Predicate<Entity>() {
+        return new SerializablePredicate<Entity>() {
             @Override
             public boolean apply(@Nullable Entity input) {
                 return (input != null) && 
input.getLocations().contains(location);
@@ -103,7 +105,7 @@ public class EntityPredicates {
     }
     
     public static <T> Predicate<Entity> managed() {
-        return new Predicate<Entity>() {
+        return new SerializablePredicate<Entity>() {
             @Override
             public boolean apply(@Nullable Entity input) {
                 return (input != null) && Entities.isManaged(input);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java 
b/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
index 6dab484..aef7b92 100644
--- a/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
+++ b/core/src/test/java/brooklyn/entity/rebind/RebindTestUtils.java
@@ -24,6 +24,7 @@ import brooklyn.location.Location;
 import brooklyn.management.ManagementContext;
 import brooklyn.management.internal.LocalManagementContext;
 import brooklyn.mementos.BrooklynMemento;
+import brooklyn.test.entity.LocalManagementContextForTests;
 import brooklyn.util.javalang.Serializers;
 import brooklyn.util.javalang.Serializers.ObjectReplacer;
 import brooklyn.util.time.Duration;
@@ -127,9 +128,9 @@ public class RebindTestUtils {
         public LocalManagementContext buildUnstarted() {
             LocalManagementContext unstarted;
             if (properties != null) {
-                unstarted = new LocalManagementContext(properties);
+                unstarted = new LocalManagementContextForTests(properties);
             } else {
-                unstarted = new LocalManagementContext();
+                unstarted = new LocalManagementContextForTests();
             }
             BrooklynMementoPersisterToMultiFile newPersister = new 
BrooklynMementoPersisterToMultiFile(mementoDir, classLoader);
             ((RebindManagerImpl) 
unstarted.getRebindManager()).setPeriodicPersistPeriod(Duration.of(persistPeriodMillis,
 TimeUnit.MILLISECONDS));

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslDeferredSupplier.java
----------------------------------------------------------------------
diff --git 
a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslDeferredSupplier.java
 
b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslDeferredSupplier.java
index 5d60ea2..9fe4458 100644
--- 
a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslDeferredSupplier.java
+++ 
b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/BrooklynDslDeferredSupplier.java
@@ -1,5 +1,7 @@
 package io.brooklyn.camp.brooklyn.spi.dsl;
 
+import java.io.Serializable;
+
 import io.brooklyn.camp.spi.Assembly;
 import io.brooklyn.camp.spi.AssemblyTemplate;
 import io.brooklyn.camp.spi.resolve.interpret.PlanInterpretationNode;
@@ -36,7 +38,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
  * (TODO the precise semantics of this are under development.)
  * <p>
  **/
-public abstract class BrooklynDslDeferredSupplier<T> implements 
DeferredSupplier<T>, TaskFactory<Task<T>> {
+public abstract class BrooklynDslDeferredSupplier<T> implements 
DeferredSupplier<T>, TaskFactory<Task<T>>, Serializable {
+
+    private static final long serialVersionUID = -8789624905412198233L;
 
     private static final Logger log = 
LoggerFactory.getLogger(BrooklynDslDeferredSupplier.class);
     

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
----------------------------------------------------------------------
diff --git 
a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
 
b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
index 9620a9a..15df932 100644
--- 
a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
+++ 
b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
@@ -38,10 +38,16 @@ public class BrooklynDslCommon {
             return String.format(pattern, args);
         }
         return new BrooklynDslDeferredSupplier<String>() {
+            private static final long serialVersionUID = -4849297712650560863L;
+
             @Override
             public Task<String> newTask() {
                 return DependentConfiguration.formatString(pattern, args);
             }
+            @Override
+            public String toString() {
+                return "$brooklyn:formatString("+pattern+")";
+            }
         };
     }
 
@@ -49,7 +55,7 @@ public class BrooklynDslCommon {
     //       but that would require refactoring of Brooklyn DSL
     // TODO: Should use catalog's classloader, rather than Class.forName; how 
to get that? Should we return a future?!
     /** returns a Sensor from the given entity type */
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     public static Object sensor(String clazzName, String sensorName) {
         try {
             Class<?> clazz = Class.forName(clazzName);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
----------------------------------------------------------------------
diff --git 
a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
 
b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
index 5bbed47..69e80b4 100644
--- 
a/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
+++ 
b/usage/camp/src/main/java/io/brooklyn/camp/brooklyn/spi/dsl/methods/DslComponent.java
@@ -27,7 +27,9 @@ import com.google.common.collect.Sets;
 
 public class DslComponent extends BrooklynDslDeferredSupplier<Entity> {
 
-       private final String componentId;
+    private static final long serialVersionUID = -7715984495268724954L;
+    
+    private final String componentId;
        private final Scope scope;
 
        public DslComponent(String componentId) {
@@ -89,7 +91,8 @@ public class DslComponent extends 
BrooklynDslDeferredSupplier<Entity> {
     
        public BrooklynDslDeferredSupplier<?> attributeWhenReady(final String 
sensorName) {
                return new BrooklynDslDeferredSupplier<Object>() {
-                       @SuppressWarnings("unchecked")
+            private static final long serialVersionUID = 1740899524088902383L;
+            @SuppressWarnings("unchecked")
             @Override
                        public Task<Object> newTask() {
                                Entity targetEntity = DslComponent.this.get();
@@ -99,11 +102,16 @@ public class DslComponent extends 
BrooklynDslDeferredSupplier<Entity> {
                                }
                                return (Task<Object>) 
DependentConfiguration.attributeWhenReady(targetEntity, 
(AttributeSensor<?>)targetSensor);
                        }
+                       @Override
+                       public String toString() {
+                           return 
DslComponent.this.toString()+"."+"attributeWhenReady("+sensorName+")";
+                       }
                };
        }
        
        public BrooklynDslDeferredSupplier<Object> config(final String keyName) 
{
         return new BrooklynDslDeferredSupplier<Object>() {
+            private static final long serialVersionUID = -4735177561947722511L;
             @Override
             public Task<Object> newTask() {
                 return Tasks.builder().name("retrieving config for 
"+keyName).dynamic(false).body(new Callable<Object>() {
@@ -114,6 +122,10 @@ public class DslComponent extends 
BrooklynDslDeferredSupplier<Entity> {
                     }
                 }).build();
             }
+            @Override
+            public String toString() {
+                return DslComponent.this.toString()+"."+"config("+keyName+")";
+            }
         };
     }
        
@@ -148,4 +160,13 @@ public class DslComponent extends 
BrooklynDslDeferredSupplier<Entity> {
            }
        }
 
+
+    @Override
+    public String toString() {
+        return "$brooklyn:component("+
+            (scope==Scope.GLOBAL ? "" : scope+", ")+
+            componentId+
+            ")";
+    }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java
----------------------------------------------------------------------
diff --git 
a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java 
b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java
index 514a5c8..08872fb 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/AbstractYamlTest.java
@@ -26,8 +26,8 @@ public abstract class AbstractYamlTest {
     private static final Logger LOG = 
LoggerFactory.getLogger(AbstractYamlTest.class);
 
     private ManagementContext brooklynMgmt;
-    private BrooklynCampPlatform platform;
-    private BrooklynCampPlatformLauncherNoServer launcher;
+    protected BrooklynCampPlatform platform;
+    protected BrooklynCampPlatformLauncherNoServer launcher;
     
     public AbstractYamlTest() {
         super();
@@ -40,7 +40,7 @@ public abstract class AbstractYamlTest {
         launcher = new BrooklynCampPlatformLauncherNoServer() {
             @Override
             protected LocalManagementContext newMgmtContext() {
-                return new LocalManagementContextForTests();
+                return newTestManagementContext();
             }
         };
         launcher.launch();
@@ -48,6 +48,10 @@ public abstract class AbstractYamlTest {
         platform = launcher.getCampPlatform();
     }
 
+    protected LocalManagementContext newTestManagementContext() {
+        return new LocalManagementContextForTests();
+    }
+    
     @AfterMethod(alwaysRun = true)
     public void teardown() {
         if (brooklynMgmt != null) Entities.destroyAll(brooklynMgmt);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
----------------------------------------------------------------------
diff --git 
a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java 
b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
new file mode 100644
index 0000000..f6449e7
--- /dev/null
+++ 
b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
@@ -0,0 +1,168 @@
+package io.brooklyn.camp.brooklyn;
+
+import java.io.File;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.Application;
+import brooklyn.entity.Entity;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.rebind.RebindTestUtils;
+import brooklyn.event.basic.Sensors;
+import brooklyn.management.ManagementContext;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.test.entity.TestEntity;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.task.Tasks;
+
+import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+
+@Test
+public class DslAndRebindYamlTest extends AbstractYamlTest {
+    
+    private static final Logger log = 
LoggerFactory.getLogger(DslAndRebindYamlTest.class);
+    
+    protected ClassLoader classLoader = getClass().getClassLoader();
+    protected File mementoDir;
+    protected Set<ManagementContext> mgmtContexts = MutableSet.of();
+
+    @Override
+    protected LocalManagementContext newTestManagementContext() {
+        if (mementoDir!=null) throw new IllegalStateException("already created 
mgmt context");
+        mementoDir = Files.createTempDir();
+        LocalManagementContext mgmt = 
RebindTestUtils.newPersistingManagementContext(mementoDir, classLoader, 1);
+        mgmtContexts.add(mgmt);
+        return mgmt;
+    }
+    
+    @AfterMethod(alwaysRun = true)
+    @Override
+    public void teardown() {
+        for (ManagementContext mgmt: mgmtContexts) Entities.destroyAll(mgmt);
+        super.teardown();
+        mementoDir = null;
+        mgmtContexts.clear();
+    }
+
+    @Override
+    protected Logger getLogger() {
+        return log;
+    }
+
+    public Application rebind(Application app) throws Exception {
+        RebindTestUtils.waitForPersisted(app);
+        // not strictly needed, but for good measure:
+        RebindTestUtils.checkCurrentMementoSerializable(app);
+        Application result = RebindTestUtils.rebind(mementoDir, 
getClass().getClassLoader());
+        mgmtContexts.add(result.getManagementContext());
+        return result;
+    }
+
+
+    protected Entity setupAndCheckTestEntityInBasicTemplateWith(String 
...extras) throws Exception {
+        Entity app = 
createAndStartApplication("test-entity-basic-template.yaml", extras);
+        waitForApplicationTasks(app);
+
+        Assert.assertEquals(app.getDisplayName(), 
"test-entity-basic-template");
+
+        log.info("App started:");
+        Entities.dumpInfo(app);
+        
+        Assert.assertTrue(app.getChildren().iterator().hasNext(), "Expected 
app to have child entity");
+        Entity entity = app.getChildren().iterator().next();
+        Assert.assertTrue(entity instanceof TestEntity, "Expected TestEntity, 
found " + entity.getClass());
+        
+        return (TestEntity)entity;
+    }
+
+    public static <T> T getConfigInTask(final Entity entity, final 
ConfigKey<T> key) {
+        return Entities.submit(entity, Tasks.<T>builder().body(new 
Callable<T>() {
+            @Override
+            public T call() throws Exception {
+                return entity.getConfig(key);
+            }
+        }).build()).getUnchecked();
+    }
+    
+    @Test
+    public void testDslAttributeWhenReady() throws Exception {
+        Entity testEntity = entityWithAttributeWhenReady();
+        
((EntityInternal)testEntity).setAttribute(Sensors.newStringSensor("foo"), 
"bar");
+        Assert.assertEquals(getConfigInTask(testEntity, TestEntity.CONF_NAME), 
"bar");
+    }
+
+    @Test
+    public void testDslAttributeWhenReadyRebind() throws Exception {
+        Entity testEntity = entityWithAttributeWhenReady();
+        
((EntityInternal)testEntity).setAttribute(Sensors.newStringSensor("foo"), 
"bar");
+        Application app2 = rebind(testEntity.getApplication());
+        Entity e2 = Iterables.getOnlyElement( app2.getChildren() );
+        
+        Assert.assertEquals(getConfigInTask(e2, TestEntity.CONF_NAME), "bar");
+    }
+
+    private Entity entityWithAttributeWhenReady() throws Exception {
+        return setupAndCheckTestEntityInBasicTemplateWith( 
+            "  id: x",
+            "  brooklyn.config:",
+            "    test.confName: 
$brooklyn:component(\"x\").attributeWhenReady(\"foo\")");
+    }
+
+
+    @Test
+    public void testDslConfigFromRoot() throws Exception {
+        Entity testEntity = entityWithConfigFromRoot();
+        Assert.assertEquals(getConfigInTask(testEntity, TestEntity.CONF_NAME), 
"bar");
+    }
+
+    @Test
+    public void testDslConfigFromRootRebind() throws Exception {
+        Entity testEntity = entityWithConfigFromRoot();
+        Application app2 = rebind(testEntity.getApplication());
+        Entity e2 = Iterables.getOnlyElement( app2.getChildren() );
+        
+        Assert.assertEquals(getConfigInTask(e2, TestEntity.CONF_NAME), "bar");
+    }
+
+    private Entity entityWithConfigFromRoot() throws Exception {
+        return setupAndCheckTestEntityInBasicTemplateWith( 
+            "  id: x",
+            "  brooklyn.config:",
+            "    test.confName: $brooklyn:component(\"x\").config(\"foo\")",
+            "brooklyn.config:",
+            "  foo: bar");
+    }
+
+
+    @Test
+    public void testDslFormatString() throws Exception {
+        Entity testEntity = entityWithFormatString();
+        Assert.assertEquals(getConfigInTask(testEntity, TestEntity.CONF_NAME), 
"hello world");
+    }
+
+    @Test
+    public void testDslFormatStringRebind() throws Exception {
+        Entity testEntity = entityWithFormatString();
+        Application app2 = rebind(testEntity.getApplication());
+        Entity e2 = Iterables.getOnlyElement( app2.getChildren() );
+        
+        Assert.assertEquals(getConfigInTask(e2, TestEntity.CONF_NAME), "hello 
world");
+    }
+
+    private Entity entityWithFormatString() throws Exception {
+        return setupAndCheckTestEntityInBasicTemplateWith( 
+            "  id: x",
+            "  brooklyn.config:",
+            "    test.confName: $brooklyn:formatString(\"hello %s\", 
\"world\")");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
----------------------------------------------------------------------
diff --git 
a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java 
b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
index ddd95a0..46c728c 100644
--- a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
+++ b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/EntitiesYamlTest.java
@@ -47,7 +47,7 @@ import com.google.common.collect.Iterables;
 
 @Test
 public class EntitiesYamlTest extends AbstractYamlTest {
-    private static final Logger log = 
LoggerFactory.getLogger(EnrichersYamlTest.class);
+    private static final Logger log = 
LoggerFactory.getLogger(EntitiesYamlTest.class);
 
     protected Entity setupAndCheckTestEntityInBasicTemplateWith(String 
...extras) throws Exception {
         Entity app = 
createAndStartApplication("test-entity-basic-template.yaml", extras);

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/JavaWebAppWithDslYamlRebindIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/JavaWebAppWithDslYamlRebindIntegrationTest.java
 
b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/JavaWebAppWithDslYamlRebindIntegrationTest.java
new file mode 100644
index 0000000..cbd32bf
--- /dev/null
+++ 
b/usage/camp/src/test/java/io/brooklyn/camp/brooklyn/JavaWebAppWithDslYamlRebindIntegrationTest.java
@@ -0,0 +1,105 @@
+package io.brooklyn.camp.brooklyn;
+
+import io.brooklyn.camp.spi.Assembly;
+import io.brooklyn.camp.spi.AssemblyTemplate;
+
+import java.io.File;
+import java.io.Reader;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+
+import brooklyn.entity.Application;
+import brooklyn.entity.basic.BrooklynTaskTags;
+import brooklyn.entity.basic.Entities;
+import brooklyn.entity.rebind.RebindTestUtils;
+import brooklyn.management.ManagementContext;
+import brooklyn.management.Task;
+import brooklyn.management.internal.LocalManagementContext;
+import brooklyn.util.ResourceUtils;
+import brooklyn.util.collections.MutableSet;
+import brooklyn.util.stream.Streams;
+
+import com.google.common.io.Files;
+
+@Test
+public class JavaWebAppWithDslYamlRebindIntegrationTest extends 
AbstractYamlTest {
+    
+    private static final Logger log = 
LoggerFactory.getLogger(JavaWebAppWithDslYamlRebindIntegrationTest.class);
+    
+    protected ClassLoader classLoader = getClass().getClassLoader();
+    protected File mementoDir;
+    protected Set<ManagementContext> mgmtContexts = MutableSet.of();
+
+    @Override
+    protected LocalManagementContext newTestManagementContext() {
+        if (mementoDir!=null) throw new IllegalStateException("already created 
mgmt context");
+        mementoDir = Files.createTempDir();
+        LocalManagementContext mgmt = 
RebindTestUtils.newPersistingManagementContext(mementoDir, classLoader, 1);
+        mgmtContexts.add(mgmt);
+        return mgmt;
+    }
+    
+    @AfterMethod(alwaysRun = true)
+    @Override
+    public void teardown() {
+        for (ManagementContext mgmt: mgmtContexts) Entities.destroyAll(mgmt);
+        super.teardown();
+        mementoDir = null;
+        mgmtContexts.clear();
+    }
+
+    @Override
+    protected Logger getLogger() {
+        return log;
+    }
+
+    public Application rebind(Application app) throws Exception {
+        RebindTestUtils.waitForPersisted(app);
+        // optionally for good measure can also check this:
+//        RebindTestUtils.checkCurrentMementoSerializable(app);
+        Application result = RebindTestUtils.rebind(mementoDir, 
getClass().getClassLoader());
+        mgmtContexts.add(result.getManagementContext());
+        return result;
+    }
+
+    /** as {@link JavaWebAppsIntegrationTest#testWithDbDeploy()} but with 
rebind */
+    @Test(groups="Integration")
+    public void testJavaWebAppDeployAndRebind() throws Exception {
+        Reader input = Streams.reader(new 
ResourceUtils(this).getResourceFromUrl("java-web-app-and-db-with-function.yaml"));
+        AssemblyTemplate at = platform.pdp().registerDeploymentPlan(input);
+
+        Assembly assembly = at.getInstantiator().newInstance().instantiate(at, 
platform);
+        final Application app = (Application) 
mgmt().getEntityManager().getEntity(assembly.getId());
+
+        Set<Task<?>> tasks = 
BrooklynTaskTags.getTasksInEntityContext(mgmt().getExecutionManager(), app);
+        for (Task<?> t: tasks) t.blockUntilEnded();
+        Entities.dumpInfo(app);
+
+        Application app2 = rebind(app);
+        Assert.assertEquals(app2.getChildren().size(), 2);
+    }
+
+    // failing test based on 
https://github.com/brooklyncentral/brooklyn/issues/1422
+    @Test(groups="Integration", enabled=false)
+    public void testJavaWebWithMemberSpecRebind() throws Exception {
+        Reader input = Streams.reader(new 
ResourceUtils(this).getResourceFromUrl("test-java-web-app-spec-and-db-with-function.yaml"));
+        AssemblyTemplate at = platform.pdp().registerDeploymentPlan(input);
+
+        Assembly assembly = at.getInstantiator().newInstance().instantiate(at, 
platform);
+        final Application app = (Application) 
mgmt().getEntityManager().getEntity(assembly.getId());
+
+        Set<Task<?>> tasks = 
BrooklynTaskTags.getTasksInEntityContext(mgmt().getExecutionManager(), app);
+        for (Task<?> t: tasks) t.blockUntilEnded();
+        Entities.dumpInfo(app);
+
+        Application app2 = rebind(app);
+        Assert.assertEquals(app2.getChildren().size(), 2);
+    }
+    
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/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
new file mode 100644
index 0000000..ab1fe67
--- /dev/null
+++ 
b/usage/camp/src/test/resources/test-java-web-app-spec-and-db-with-function.yaml
@@ -0,0 +1,21 @@
+name: java-cluster-db-example
+location: localhost
+services:
+- serviceType: brooklyn.entity.webapp.ControlledDynamicWebAppCluster
+  name: My Web
+  brooklyn.config:
+    proxy.http.port: 9210+
+    http.port: 9280+
+  memberSpec:
+    $brooklyn:entitySpec:
+      type: brooklyn.entity.webapp.jboss.JBoss7Server
+      brooklyn.config:
+        wars.root: 
http://search.maven.org/remotecontent?filepath=io/brooklyn/example/brooklyn-example-hello-world-sql-webapp/0.6.0/brooklyn-example-hello-world-sql-webapp-0.6.0.war
+        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
+  id: db
+  name: My DB
+  brooklyn.config:
+    datastore.creation.script.url: classpath://visitors-creation-script.sql

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/3d0cbf4d/utils/common/src/main/java/brooklyn/util/guava/SerializablePredicate.java
----------------------------------------------------------------------
diff --git 
a/utils/common/src/main/java/brooklyn/util/guava/SerializablePredicate.java 
b/utils/common/src/main/java/brooklyn/util/guava/SerializablePredicate.java
new file mode 100644
index 0000000..067b985
--- /dev/null
+++ b/utils/common/src/main/java/brooklyn/util/guava/SerializablePredicate.java
@@ -0,0 +1,8 @@
+package brooklyn.util.guava;
+
+import java.io.Serializable;
+
+import com.google.common.base.Predicate;
+
+public interface SerializablePredicate<T> extends Predicate<T>, Serializable {
+}

Reply via email to