Merge pull request #1137 from richardcloudsoft/brooklynnode-more-fixes

BrooklynNode - more fixes
diff --git a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
index 4d79601..60feca8 100644
--- a/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
+++ b/core/src/main/java/brooklyn/util/flags/TypeCoercions.java
@@ -33,7 +33,9 @@
 
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
+import com.google.common.base.Splitter;
 import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.primitives.Primitives;
 import com.google.common.reflect.TypeToken;
@@ -468,5 +470,11 @@
                 return Double.valueOf(input);
             }
         });
+        registerAdapter(String.class, List.class, new Function<String,List>() {
+            @Override
+            public List<String> apply(final String input) {
+                return ImmutableList.copyOf(Splitter.on(",").trimResults().omitEmptyStrings().split(input));
+            }
+        });
     }
 }
diff --git a/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java b/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java
index ce51754..aae24e3 100644
--- a/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java
+++ b/core/src/test/java/brooklyn/util/internal/TypeCoercionsTest.java
@@ -95,6 +95,12 @@
     }
 
     @Test
+    public void testStringToListCoercion() {
+        List<?> s = TypeCoercions.coerce("a,b,c", List.class);
+        Assert.assertEquals(s, ImmutableList.of("a", "b", "c"));
+    }
+
+    @Test
     public void testAs() {
         Integer x = TypeCoercions.coerce(new WithAs("3"), Integer.class);
         Assert.assertEquals(x, (Integer)3);
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
index 8a166ac..6ea1af6 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNode.java
@@ -147,9 +147,8 @@
             String.class, "brooklynnode.webconsole.bindAddress", "Specifies the IP address of the NIC to bind the Brooklyn Management Console to", null);
 
     @SetFromFlag("classpath")
-    @Beta // ideally this should be List<String>, but this will require support for defining lists in brooklyn.properties
-    public static final BasicAttributeSensorAndConfigKey<String> CLASSPATH = new BasicAttributeSensorAndConfigKey(
-            String.class, "brooklynnode.classpath", "classpath to use, as a string of semi-colon separated URL entries", null);
+    public static final BasicAttributeSensorAndConfigKey<List<String>> CLASSPATH = new BasicAttributeSensorAndConfigKey(
+            List.class, "brooklynnode.classpath", "classpath to use", null);
 
     @SetFromFlag("portMapper")
     public static final ConfigKey<Function<? super Integer, ? extends Integer>> PORT_MAPPER = (ConfigKey) ConfigKeys.newConfigKey(Function.class,
diff --git a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
index 686e08c..05c02ab 100644
--- a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
@@ -42,14 +42,12 @@
         return BrooklynNodeDriver.class;
     }
 
-    public Iterable<String> getClasspath() {
-        String classpath = getConfig(CLASSPATH);
-        if (Strings.isBlank(classpath)) {
+    public List<String> getClasspath() {
+        List<String> classpath = getConfig(CLASSPATH);
+        if (classpath == null || classpath.isEmpty()) {
             classpath = getManagementContext().getConfig().getConfig(CLASSPATH);
         }
-        return Strings.isNonBlank(classpath)
-                ? Splitter.on(';').trimResults().omitEmptyStrings().split(classpath)
-                : ImmutableList.<String>of();
+        return classpath;
     }
     
     protected List<String> getEnabledHttpProtocols() {
diff --git a/software/base/src/test/java/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java b/software/base/src/test/java/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
index 6436d6e..49e325e 100644
--- a/software/base/src/test/java/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
+++ b/software/base/src/test/java/brooklyn/entity/brooklynnode/BrooklynNodeIntegrationTest.java
@@ -7,6 +7,7 @@
 import java.net.URI;
 import java.util.List;
 
+import brooklyn.config.BrooklynProperties;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -175,6 +176,69 @@
     }
 
     @Test(groups="Integration")
+    public void testCopiesClasspathEntriesInConfigKey() throws Exception {
+        String content = "abc=def";
+        File classpathEntry1 = File.createTempFile("first", ".properties");
+        File classpathEntry2 = File.createTempFile("second", ".properties");
+        Files.write(content, classpathEntry1, Charsets.UTF_8);
+        Files.write(content, classpathEntry2, Charsets.UTF_8);
+        File tempDir = Files.createTempDir();
+        File expectedFile1 = new File(new File(tempDir, "lib"), classpathEntry1.getName());
+        File expectedFile2 = new File(new File(tempDir, "lib"), classpathEntry2.getName());
+
+        try {
+            BrooklynNode brooklynNode = app.createAndManageChild(EntitySpec.create(BrooklynNode.class)
+                    .configure(BrooklynNode.WEB_CONSOLE_BIND_ADDRESS, "127.0.0.1")
+                    .configure(BrooklynNode.SUGGESTED_RUN_DIR, tempDir.getAbsolutePath())
+                    .configure(BrooklynNode.CLASSPATH, ImmutableList.of(classpathEntry1.getAbsolutePath(), classpathEntry2.getAbsolutePath()))
+                    );
+            app.start(locs);
+
+            assertEquals(Files.readLines(expectedFile1, Charsets.UTF_8), ImmutableList.of(content));
+            assertEquals(Files.readLines(expectedFile2, Charsets.UTF_8), ImmutableList.of(content));
+        } finally {
+            expectedFile1.delete();
+            expectedFile2.delete();
+            tempDir.delete();
+            classpathEntry1.delete();
+            classpathEntry2.delete();
+        }
+    }
+
+    @Test(groups="Integration")
+    public void testCopiesClasspathEntriesInBrooklynProperties() throws Exception {
+        String content = "abc=def";
+        File classpathEntry1 = File.createTempFile("first", ".properties");
+        File classpathEntry2 = File.createTempFile("second", ".properties");
+        Files.write(content, classpathEntry1, Charsets.UTF_8);
+        Files.write(content, classpathEntry2, Charsets.UTF_8);
+        File tempDir = Files.createTempDir();
+        File expectedFile1 = new File(new File(tempDir, "lib"), classpathEntry1.getName());
+        File expectedFile2 = new File(new File(tempDir, "lib"), classpathEntry2.getName());
+
+        try {
+            String propName = BrooklynNode.CLASSPATH.getName();
+            String propValue = classpathEntry1.toURI().toString() + "," + classpathEntry2.toURI().toString();
+            ((BrooklynProperties)app.getManagementContext().getConfig()).put(propName, propValue);
+    
+            BrooklynNode brooklynNode = app.createAndManageChild(EntitySpec.create(BrooklynNode.class)
+                    .configure(BrooklynNode.WEB_CONSOLE_BIND_ADDRESS, "127.0.0.1")
+                    .configure(BrooklynNode.SUGGESTED_RUN_DIR, tempDir.getAbsolutePath())
+                    );
+            app.start(locs);
+
+            assertEquals(Files.readLines(expectedFile1, Charsets.UTF_8), ImmutableList.of(content));
+            assertEquals(Files.readLines(expectedFile2, Charsets.UTF_8), ImmutableList.of(content));
+        } finally {
+            expectedFile1.delete();
+            expectedFile2.delete();
+            tempDir.delete();
+            classpathEntry1.delete();
+            classpathEntry2.delete();
+        }
+    }
+
+    @Test(groups="Integration")
     public void testSetsBrooklynWebConsolePort() throws Exception {
         BrooklynNode brooklynNode = app.createAndManageChild(EntitySpec.create(BrooklynNode.class)
                 .configure(BrooklynNode.WEB_CONSOLE_BIND_ADDRESS, "127.0.0.1")