You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by dr...@apache.org on 2017/02/07 09:37:23 UTC

[1/4] brooklyn-server git commit: Urls.encode(String) specifies UTF-8

Repository: brooklyn-server
Updated Branches:
  refs/heads/master 5c5d578f4 -> 422e025ea


Urls.encode(String) specifies UTF-8

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

Branch: refs/heads/master
Commit: fa387821a0594fbd107f0edcb1ee73144a30987b
Parents: 5c5d578
Author: Aled Sage <al...@gmail.com>
Authored: Mon Feb 6 12:55:03 2017 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Feb 6 13:08:44 2017 +0000

----------------------------------------------------------------------
 .../java/org/apache/brooklyn/util/net/Urls.java | 36 +++++++++++++++---
 .../org/apache/brooklyn/util/net/UrlsTest.java  | 40 +++++++++++++++++++-
 2 files changed, 68 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fa387821/utils/common/src/main/java/org/apache/brooklyn/util/net/Urls.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/net/Urls.java b/utils/common/src/main/java/org/apache/brooklyn/util/net/Urls.java
index 717e8a2..ac60c96 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/net/Urls.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/net/Urls.java
@@ -19,6 +19,7 @@
 package org.apache.brooklyn.util.net;
 
 import java.io.File;
+import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -30,6 +31,7 @@ import java.util.List;
 
 import javax.annotation.Nullable;
 
+import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;
 
 import com.google.common.base.Function;
@@ -177,16 +179,38 @@ public class Urls {
         return result.toString();
     }
 
-    /** encodes the string suitable for use in a URL, using default character set
-     * (non-deprecated version of URLEncoder.encode) */
-    @SuppressWarnings("deprecation")
+    /**
+     * Encodes the string suitable for use in a URL, using default UTF-8 
+     * (version of URLEncoder.encode that does not throw checked exception)
+     */
     public static String encode(String text) {
-        return URLEncoder.encode(text);
+        /*
+         * TODO URLEncoder.encode is a HTML encoder, to make strings safe to use in 
+         * x-www-form-urlencoded. There is huge overlap between that and url-encoding, but
+         * they are not the same (e.g. space is converted to "+" rather than "%20", and
+         * "*" is not converted to "%2A").
+         * 
+         * Correct URL-encoding depends on which part of the URL it is. For example, guava's 
+         * UrlEscapers has separate escapers for path and fragment. Neither of these is 
+         * appropriate for escaping the password in "http://myusername@mypassword:myhost".
+         * 
+         * org.apache.commons.codec.net.URLCodec behaves the same as java.net.URLEncoder: it 
+         * is for "www-form-urlencoded".
+         */
+        try {
+            return URLEncoder.encode(text, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw Exceptions.propagate(e);
+        }
     }
+    
     /** As {@link #encode(String)} */
-    @SuppressWarnings("deprecation")
     public static String decode(String text) {
-        return URLDecoder.decode(text);
+        try {
+            return URLDecoder.decode(text, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw Exceptions.propagate(e);
+        }
     }
 
     /** returns the protocol (e.g. http) if one appears to be specified, or else null;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/fa387821/utils/common/src/test/java/org/apache/brooklyn/util/net/UrlsTest.java
----------------------------------------------------------------------
diff --git a/utils/common/src/test/java/org/apache/brooklyn/util/net/UrlsTest.java b/utils/common/src/test/java/org/apache/brooklyn/util/net/UrlsTest.java
index f775826..285fd8a 100644
--- a/utils/common/src/test/java/org/apache/brooklyn/util/net/UrlsTest.java
+++ b/utils/common/src/test/java/org/apache/brooklyn/util/net/UrlsTest.java
@@ -32,7 +32,7 @@ public class UrlsTest {
         Assert.assertEquals(Urls.toUrl(u).toString(), u);
         Assert.assertEquals(Urls.toUri(u).toString(), u);
         Assert.assertEquals(Urls.toUri(Urls.toUrl(u)).toString(), u);
-        Assert.assertEquals(Urls.toUrl(Urls.toUri(u)).toString(), u);        
+        Assert.assertEquals(Urls.toUrl(Urls.toUri(u)).toString(), u);
     }
     
     @Test
@@ -50,7 +50,29 @@ public class UrlsTest {
 
     @Test
     public void testPathEncode() throws Exception {
-        assertEquals(Urls.encode("name_with/%!"), "name_with%2F%25%21");
+        encodeAndDecodeUrl("simple", "simple");
+        encodeAndDecodeUrl("name_with/%!", "name_with%2F%25%21");
+
+        StringBuilder allcharsBuilder = new StringBuilder();
+        for (int i = 1; i < 128; i++) {
+            if (i == 32 || i == 42) continue; // See testUserOrPasswordOrHostEncode()
+            allcharsBuilder.append((char)i);
+        }
+        String allchars = allcharsBuilder.toString();
+        encodeAndDecodeUrl(allchars, "%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%21%22%23%24%25%26%27%28%29%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E%7F");
+    }
+
+    // TODO java.net.URLEncoder.encode() gets it wrong for:
+    //  " " (i.e. space - char %20). It turns that into "+" in the url.
+    //  "*" (i.e char %2A) is not escaped - this is wrong according to https://en.wikipedia.org/wiki/Percent-encoding (RFC 3986).
+    @Test(groups="Broken")
+    public void testUserOrPasswordOrHostEncode() throws Exception {
+        StringBuilder passwordBuilder = new StringBuilder();
+        for (int i = 1; i < 128; i++) {
+            passwordBuilder.append((char)i);
+        }
+        String allchars = passwordBuilder.toString();
+        encodeAndDecodeUrl(allchars, "%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E%7F");
     }
 
     @Test
@@ -88,4 +110,18 @@ public class UrlsTest {
         // tests for parsing are in core in ResourceUtilsTest
     }
 
+
+    @Test
+    public void testEncodeAndDecodeUrl() throws Exception {
+        encodeAndDecodeUrl("simple", "simple");
+        encodeAndDecodeUrl("!@#$%^&*", "%21%40%23%24%25%5E%26*"); // TODO "*" should really be encoded!
+        encodeAndDecodeUrl("a/b", "a%2Fb");
+    }
+    
+    private void encodeAndDecodeUrl(String val, String expectedEncoding) {
+        String actualEncoding = Urls.encode(val);
+        String actualDecoded = Urls.decode(actualEncoding);
+        assertEquals(actualDecoded, val, "Encode+decode does not match original: orig="+val+"; decoded="+actualDecoded);
+        assertEquals(actualEncoding, expectedEncoding, "Does not match expected encoding: orig="+val+"; decoded="+actualDecoded);
+    }
 }


[4/4] brooklyn-server git commit: This closes #551

Posted by dr...@apache.org.
This closes #551


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

Branch: refs/heads/master
Commit: 422e025eab4c7ae7f933ddcbeed0f54069b2e8fc
Parents: 5c5d578 9275edb
Author: Duncan Godwin <dr...@googlemail.com>
Authored: Tue Feb 7 09:35:46 2017 +0000
Committer: Duncan Godwin <dr...@googlemail.com>
Committed: Tue Feb 7 09:35:46 2017 +0000

----------------------------------------------------------------------
 .../spi/dsl/methods/BrooklynDslCommon.java      | 70 +++++++++++++++++++-
 .../camp/brooklyn/AbstractYamlRebindTest.java   | 47 +++++++------
 .../camp/brooklyn/DslAndRebindYamlTest.java     | 28 ++++++++
 .../catalog/CatalogOsgiLibraryTest.java         | 46 ++++++++++---
 .../brooklyn/camp/brooklyn/spi/dsl/DslTest.java | 37 +++++++++++
 .../core/sensor/DependentConfiguration.java     | 45 ++++++++++++-
 .../java/org/apache/brooklyn/util/net/Urls.java | 36 ++++++++--
 .../org/apache/brooklyn/util/net/UrlsTest.java  | 40 ++++++++++-
 8 files changed, 307 insertions(+), 42 deletions(-)
----------------------------------------------------------------------



[2/4] brooklyn-server git commit: BROOKLYN-421: Adds DSL for $brooklyn:urlEncode(...)

Posted by dr...@apache.org.
BROOKLYN-421: Adds DSL for $brooklyn:urlEncode(...)


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

Branch: refs/heads/master
Commit: 316452e578d7199227cf9a5472a4cde7bf2faf8a
Parents: fa38782
Author: Aled Sage <al...@gmail.com>
Authored: Fri Jan 20 22:29:07 2017 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Feb 6 14:20:09 2017 +0000

----------------------------------------------------------------------
 .../spi/dsl/methods/BrooklynDslCommon.java      | 70 +++++++++++++++++++-
 .../camp/brooklyn/DslAndRebindYamlTest.java     | 28 ++++++++
 .../catalog/CatalogOsgiLibraryTest.java         | 46 ++++++++++---
 .../brooklyn/camp/brooklyn/spi/dsl/DslTest.java | 37 +++++++++++
 .../core/sensor/DependentConfiguration.java     | 45 ++++++++++++-
 5 files changed, 213 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/316452e5/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
index 8340baf..be28492 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/methods/BrooklynDslCommon.java
@@ -62,6 +62,7 @@ import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.guava.Maybe;
 import org.apache.brooklyn.util.javalang.Reflections;
+import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.commons.beanutils.BeanUtils;
@@ -311,6 +312,27 @@ public class BrooklynDslCommon {
     }
 
     /**
+     * Returns the arg with characters escaped so it is a valid part of a URL, or a 
+     * {@link BrooklynDslDeferredSupplier} that returns this if the arguments are not yet fully 
+     * resolved.
+     * 
+     * See {@link Urls#encode(String)} for further details (it currently uses the encoding rules for
+     * "x-www-form-urlencoded")
+     * 
+     * Do not call with a whole URL unless you want everything escaped (e.g. "http://myhost" will be
+     * encoded as "http%3A%2F%2Fmyhost").
+     */
+    @DslAccessible
+    public static Object urlEncode(Object arg) {
+        if (resolved(arg)) {
+            // if all args are resolved, apply the transform now
+            return (arg == null) ? null : Urls.encode(arg.toString());
+        } else {
+            return new DslUrlEncode(arg);
+        }
+    }
+
+    /**
      * Returns a formatted string or a {@link BrooklynDslDeferredSupplier} if the arguments
      * are not yet fully resolved.
      */
@@ -332,6 +354,50 @@ public class BrooklynDslCommon {
             return new DslRegexReplacement(source, pattern, replacement);
         }
     }
+    
+    /**
+     * Deferred execution of escaping a URL.
+     *
+     * @see DependentConfiguration#urlEncode(Object)
+     */
+    protected static class DslUrlEncode extends BrooklynDslDeferredSupplier<String> {
+
+        private static final long serialVersionUID = -4849297712650560863L;
+
+        private final Object arg;
+
+        public DslUrlEncode(Object arg) {
+            this.arg = arg;
+        }
+
+        @Override
+        public final Maybe<String> getImmediately() {
+            return DependentConfiguration.urlEncodeImmediately(arg);
+        }
+
+        @Override
+        public Task<String> newTask() {
+            return DependentConfiguration.urlEncode(arg);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hashCode(arg);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) return true;
+            if (obj == null || getClass() != obj.getClass()) return false;
+            DslUrlEncode that = DslUrlEncode.class.cast(obj);
+            return Objects.equal(this.arg, that.arg);
+        }
+
+        @Override
+        public String toString() {
+            return "$brooklyn:urlEncode("+arg+")";
+        }
+    }
 
     /**
      * Deferred execution of String formatting.
@@ -342,8 +408,8 @@ public class BrooklynDslCommon {
 
         private static final long serialVersionUID = -4849297712650560863L;
 
-        private String pattern;
-        private Object[] args;
+        private final String pattern;
+        private final Object[] args;
 
         public DslFormatString(String pattern, Object ...args) {
             this.pattern = pattern;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/316452e5/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
index 9770338..a9c72c8 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/DslAndRebindYamlTest.java
@@ -453,6 +453,34 @@ public class DslAndRebindYamlTest extends AbstractYamlRebindTest {
     }
 
     @Test
+    public void testDslUrlEncode() throws Exception {
+        String unescapedVal = "name@domain?!/&:%";
+        String escapedVal = "name%40domain%3F%21%2F%26%3A%25";
+
+        String unescapedUrlFormat = "http://%s:password@mydomain.com";
+        String escapedUrl = "http://" + escapedVal + ":password@mydomain.com";
+        
+        Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
+                "  brooklyn.config:",
+                "    test.confObject: \"" + unescapedVal + "\"",
+                "    test.confName:",
+                "      $brooklyn:urlEncode:",
+                "      - $brooklyn:config(\"test.confObject\")",
+                "    test.confUrl:",
+                "      $brooklyn:formatString:",
+                "      - " + unescapedUrlFormat,
+                "      - $brooklyn:urlEncode:",
+                "        - $brooklyn:config(\"test.confObject\")");
+
+        Assert.assertEquals(getConfigInTask(testEntity, TestEntity.CONF_NAME), escapedVal);
+        Assert.assertEquals(getConfigInTask(testEntity, ConfigKeys.newStringConfigKey("test.confUrl")), escapedUrl);
+        
+        Entity e2 = rebind(testEntity);
+        Assert.assertEquals(getConfigInTask(e2, TestEntity.CONF_NAME), escapedVal);
+        Assert.assertEquals(getConfigInTask(e2, ConfigKeys.newStringConfigKey("test.confUrl")), escapedUrl);
+    }
+
+    @Test
     public void testDslEntityById() throws Exception {
         Entity testEntity = setupAndCheckTestEntityInBasicYamlWith(
                 "  id: x",

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/316452e5/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java
index 94adcdd..c504047 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogOsgiLibraryTest.java
@@ -53,7 +53,6 @@ import org.testng.annotations.Test;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.io.BaseEncoding;
-import com.google.common.net.UrlEscapers;
 
 public class CatalogOsgiLibraryTest extends AbstractYamlTest {
     
@@ -220,14 +219,34 @@ public class CatalogOsgiLibraryTest extends AbstractYamlTest {
         CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem("simple-osgi-library", "1.0");
         assertCatalogLibraryUrl(item, classpathUrl);
     }
-    
-    // TODO See https://issues.apache.org/jira/browse/BROOKLYN-421
-    //      Need to somehow escape the username and password (or include them explicitly as a 
-    //      "Authorization" header instead of embedding them in the URI).
+
     @Test(groups="Broken")
     public void testLibraryUrlUsingExternalizedConfigForCredentials() throws Exception {
+        runLibraryUrlUsingExternalizedConfigForCredentials(true);
+    }
+    
+    @Test
+    public void testLibraryUrlUsingExternalizedConfigForCredentialsLenient() throws Exception {
+        runLibraryUrlUsingExternalizedConfigForCredentials(false);
+    }
+    
+    /**
+     * See https://issues.apache.org/jira/browse/BROOKLYN-421.
+     * 
+     * TODO java.net.URLEncoder.encode() gets it wrong for:
+     * <ul>
+     *   <li>" " (i.e. space - char %20). It turns that into "+" in the url.
+     *   <li>"*" (i.e char %2A) is not escaped - this is wrong according to https://en.wikipedia.org/wiki/Percent-encoding (RFC 3986).
+     * </ul>
+     */
+    protected void runLibraryUrlUsingExternalizedConfigForCredentials(boolean includeUrlEncoderBrokenChars) throws Exception {
+        StringBuilder passwordBuilder = new StringBuilder();
+        for (int i = 1; i < 128; i++) {
+            if (!includeUrlEncoderBrokenChars && (i == 32 || i == 42)) continue;
+            passwordBuilder.append((char)i);
+        }
         String username = "myuser@mydomain.com";
-        String password = "Myp4ss@?/:!";
+        String password = passwordBuilder.toString();
         
         // Add an externalized config provider, which will return us a username + password
         Map<String, String> externalConfig = ImmutableMap.of("username", username, "password", password);
@@ -242,8 +261,10 @@ public class CatalogOsgiLibraryTest extends AbstractYamlTest {
                 "  libraries:",
                 "  - $brooklyn:formatString:",
                 "    - http://%s:%s@" + jarUrl.getHost() + ":" + jarUrl.getPort() + jarUrl.getPath(),
-                "    - $brooklyn:external(\"myprovider\", \"username\")",
-                "    - $brooklyn:external(\"myprovider\", \"password\")",
+                "    - $brooklyn:urlEncode:",
+                "      - $brooklyn:external(\"myprovider\", \"username\")",
+                "    - $brooklyn:urlEncode:",
+                "      - $brooklyn:external(\"myprovider\", \"password\")",
                 "  item:",
                 "    services:",
                 "    - type: org.apache.brooklyn.test.osgi.entities.SimpleApplication");
@@ -257,8 +278,13 @@ public class CatalogOsgiLibraryTest extends AbstractYamlTest {
         assertEquals(authHeader, expectedHeader, "headers=" + Arrays.toString(req.getAllHeaders()));
 
         // Expect url to have been correctly escaped
-        String escapedUsername = UrlEscapers.urlFragmentEscaper().escape(username);
-        String escapedPassword = UrlEscapers.urlFragmentEscaper().escape(password);
+        String escapedUsername = "myuser%40mydomain.com";
+        String escapedPassword;
+        if (includeUrlEncoderBrokenChars) {
+            escapedPassword = "%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E%7F";
+        } else {
+            escapedPassword = "%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F%21%22%23%24%25%26%27%28%29%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D%7E%7F";
+        }
         String expectedUrl = "http://" + escapedUsername + ":" + escapedPassword+ "@" + jarUrl.getHost() + ":" + jarUrl.getPort() + jarUrl.getPath();
         
         CatalogItem<?, ?> item = mgmt().getCatalog().getCatalogItem("simple-osgi-library", "1.0");

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/316452e5/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslTest.java
index 750b083..514a788 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/spi/dsl/DslTest.java
@@ -257,6 +257,43 @@ public class DslTest extends BrooklynAppUnitTestSupport {
     }
 
     @Test
+    public void testFormatString() throws Exception {
+        // literals (non-deferred) can be resolved immediately
+        assertEquals(BrooklynDslCommon.formatString("myval"), "myval");
+        assertEquals(BrooklynDslCommon.formatString("%s", "myval"), "myval");
+        
+        BrooklynDslDeferredSupplier<?> arg = BrooklynDslCommon.attributeWhenReady(TestApplication.MY_ATTRIBUTE.getName());
+        BrooklynDslDeferredSupplier<?> dsl = (BrooklynDslDeferredSupplier<?>) BrooklynDslCommon.formatString("%s", arg);
+        
+        Maybe<?> actualValue = execDslImmediately(dsl, String.class, app, true);
+        assertTrue(actualValue.isAbsent());
+
+        app.sensors().set(TestApplication.MY_ATTRIBUTE, "myval");
+        assertEquals(execDslEventually(dsl, String.class, app, Asserts.DEFAULT_LONG_TIMEOUT).get(), "myval");
+        assertEquals(execDslImmediately(dsl, String.class, app, true).get(), "myval");
+    }
+
+    @Test
+    public void testUrlEncode() throws Exception {
+        String origVal = "name@domain?!/&:%";
+        String encodedVal = "name%40domain%3F%21%2F%26%3A%25";
+        
+        // literals (non-deferred) can be resolved immediately
+        assertEquals(BrooklynDslCommon.urlEncode("myval"), "myval");
+        assertEquals(BrooklynDslCommon.urlEncode(origVal), encodedVal);
+        
+        BrooklynDslDeferredSupplier<?> arg = BrooklynDslCommon.attributeWhenReady(TestApplication.MY_ATTRIBUTE.getName());
+        BrooklynDslDeferredSupplier<?> dsl = (BrooklynDslDeferredSupplier<?>) BrooklynDslCommon.urlEncode(arg);
+        
+        Maybe<?> actualValue = execDslImmediately(dsl, String.class, app, true);
+        assertTrue(actualValue.isAbsent());
+
+        app.sensors().set(TestApplication.MY_ATTRIBUTE, origVal);
+        assertEquals(execDslEventually(dsl, String.class, app, Asserts.DEFAULT_LONG_TIMEOUT).get(), encodedVal);
+        assertEquals(execDslImmediately(dsl, String.class, app, true).get(), encodedVal);
+    }
+
+    @Test
     public void testEntityNotFound() throws Exception {
         BrooklynDslDeferredSupplier<?> dsl = BrooklynDslCommon.entity("myIdDoesNotExist");
         try {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/316452e5/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java b/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
index e4b899b..ca79d73 100644
--- a/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
+++ b/core/src/main/java/org/apache/brooklyn/core/sensor/DependentConfiguration.java
@@ -68,6 +68,7 @@ import org.apache.brooklyn.util.exceptions.RuntimeTimeoutException;
 import org.apache.brooklyn.util.groovy.GroovyJavaMethods;
 import org.apache.brooklyn.util.guava.Functionals;
 import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.net.Urls;
 import org.apache.brooklyn.util.text.StringFunctions;
 import org.apache.brooklyn.util.text.StringFunctions.RegexReplacer;
 import org.apache.brooklyn.util.text.Strings;
@@ -472,7 +473,7 @@ public class DependentConfiguration {
             if (arg instanceof TaskAdaptable) taskArgs.add((TaskAdaptable<Object>)arg);
             else if (arg instanceof TaskFactory) taskArgs.add( ((TaskFactory<TaskAdaptable<Object>>)arg).newTask() );
         }
-            
+        
         return transformMultiple(
             MutableMap.<String,String>of("displayName", "formatting '"+spec+"' with "+taskArgs.size()+" task"+(taskArgs.size()!=1?"s":"")), 
             new Function<List<Object>, String>() {
@@ -505,6 +506,48 @@ public class DependentConfiguration {
         return Maybe.of(String.format(spec, resolvedArgs.toArray()));
     }
 
+    /**
+     * @throws ImmediateSupplier.ImmediateUnsupportedException if cannot evaluate this in a timely manner
+     */
+    public static Maybe<String> urlEncodeImmediately(Object arg) {
+        Maybe<?> resolvedArg = resolveImmediately(arg);
+        if (resolvedArg.isAbsent()) return Maybe.absent();
+        if (resolvedArg.isNull()) return Maybe.<String>of((String)null);
+        
+        String resolvedString = resolvedArg.get().toString();
+        return Maybe.of(Urls.encode(resolvedString));
+    }
+
+    /** 
+     * Method which returns a Future containing an escaped URL string (see {@link Urls#encode(String)}).
+     * The arguments can be normal objects, tasks or {@link DeferredSupplier}s.
+     * tasks will be waited on (submitted if necessary) and their results substituted.
+     */
+    @SuppressWarnings("unchecked")
+    public static Task<String> urlEncode(final Object arg) {
+        List<TaskAdaptable<Object>> taskArgs = Lists.newArrayList();
+        if (arg instanceof TaskAdaptable) taskArgs.add((TaskAdaptable<Object>)arg);
+        else if (arg instanceof TaskFactory) taskArgs.add( ((TaskFactory<TaskAdaptable<Object>>)arg).newTask() );
+        
+        return transformMultiple(
+                MutableMap.<String,String>of("displayName", "url-escaping '"+arg), 
+                new Function<List<Object>, String>() {
+                    @Override
+                    @Nullable
+                    public String apply(@Nullable List<Object> input) {
+                        Object resolvedArg;
+                        if (arg instanceof TaskAdaptable || arg instanceof TaskFactory) resolvedArg = Iterables.getOnlyElement(input);
+                        else if (arg instanceof DeferredSupplier) resolvedArg = ((DeferredSupplier<?>) arg).get();
+                        else resolvedArg = arg;
+                        
+                        if (resolvedArg == null) return null;
+                        String resolvedString = resolvedArg.toString();
+                        return Urls.encode(resolvedString);
+                    }
+                },
+                taskArgs);
+    }
+
     protected static <T> Maybe<?> resolveImmediately(Object val) {
         if (val instanceof ImmediateSupplier<?>) {
             return ((ImmediateSupplier<?>)val).getImmediately();


[3/4] brooklyn-server git commit: AbstractYamlRebindTest: updates as per AbstractYamlTest

Posted by dr...@apache.org.
AbstractYamlRebindTest: updates as per AbstractYamlTest

Replaced the createAndStartApplication impl with that from
AbstractYamlTest. (Before this change, I saw a NoSuchElementException
because it failed to find the task for the start effector - I\u2019m guessing
there\u2019s a race for when that task is created).


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

Branch: refs/heads/master
Commit: 9275edb58c09081fe6ec9d9d5a7bbb241e3f5e8f
Parents: 316452e
Author: Aled Sage <al...@gmail.com>
Authored: Mon Feb 6 13:53:25 2017 +0000
Committer: Aled Sage <al...@gmail.com>
Committed: Mon Feb 6 14:20:19 2017 +0000

----------------------------------------------------------------------
 .../camp/brooklyn/AbstractYamlRebindTest.java   | 47 +++++++++++---------
 1 file changed, 26 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/9275edb5/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
index c9a57ce..9322866 100644
--- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
+++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlRebindTest.java
@@ -20,25 +20,33 @@ package org.apache.brooklyn.camp.brooklyn;
 
 import java.io.Reader;
 import java.io.StringReader;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.brooklyn.api.catalog.CatalogItem;
+import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatform;
 import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
+import org.apache.brooklyn.camp.brooklyn.spi.creation.CampTypePlanTransformer;
 import org.apache.brooklyn.camp.spi.Assembly;
 import org.apache.brooklyn.camp.spi.AssemblyTemplate;
 import org.apache.brooklyn.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.StartableApplication;
+import org.apache.brooklyn.core.entity.trait.Startable;
 import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
 import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
 import org.apache.brooklyn.core.mgmt.rebind.RebindOptions;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixture;
+import org.apache.brooklyn.core.typereg.RegisteredTypeLoadingContexts;
+import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.ResourceUtils;
 import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.stream.Streams;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterMethod;
@@ -129,34 +137,31 @@ public class AbstractYamlRebindTest extends RebindTestFixture<StartableApplicati
         return new StringReader(builder.toString());
     }
     
+    /**
+     * @deprecated since 0.11.0, use {@link #createAndStartApplication(String)} instead,
+     *             in the same way as {@link AbstractYamlTest}.
+     */
+    @Deprecated
+    protected Entity createAndStartApplication(Reader input) throws Exception {
+        return createAndStartApplication(Streams.readFully(input));
+    }
+
     protected Entity createAndStartApplication(String... multiLineYaml) throws Exception {
         return createAndStartApplication(joinLines(multiLineYaml));
     }
     
     protected Entity createAndStartApplication(String input) throws Exception {
-        return createAndStartApplication(new StringReader(input));
+        return createAndStartApplication(input, MutableMap.<String,String>of());
     }
-
-    protected Entity createAndStartApplication(Reader input) throws Exception {
-        AssemblyTemplate at = platform.pdp().registerDeploymentPlan(input);
-        Assembly assembly;
-        try {
-            assembly = at.getInstantiator().newInstance().instantiate(at, platform);
-        } catch (Exception e) {
-            getLogger().warn("Unable to instantiate " + at + " (rethrowing): " + e);
-            throw e;
-        }
-        getLogger().info("Test - created " + assembly);
-        final Entity app = mgmt().getEntityManager().getEntity(assembly.getId());
-        getLogger().info("App - " + app);
-        
-        // wait for app to have started
-        Set<Task<?>> tasks = mgmt().getExecutionManager().getTasksWithAllTags(ImmutableList.of(
-                BrooklynTaskTags.EFFECTOR_TAG, 
-                BrooklynTaskTags.tagForContextEntity(app), 
-                BrooklynTaskTags.tagForEffectorCall(app, "start", ConfigBag.newInstance(ImmutableMap.of("locations", ImmutableMap.of())))));
-        Iterables.getOnlyElement(tasks).get();
+    
+    protected Entity createAndStartApplication(String input, Map<String,?> startParameters) throws Exception {
+        EntitySpec<?> spec = 
+            mgmt().getTypeRegistry().createSpecFromPlan(CampTypePlanTransformer.FORMAT, input, RegisteredTypeLoadingContexts.spec(Application.class), EntitySpec.class);
+        final Entity app = mgmt().getEntityManager().createEntity(spec);
+        getLogger().info("Test created app, and will now start " + app);
         
+        // start the app (happens automatically if we use camp to instantiate, but not if we use crate spec approach)
+        app.invoke(Startable.START, startParameters).get();
         return app;
     }