You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2017/10/28 10:03:35 UTC

[1/4] brooklyn-server git commit: add more javadoc about use of snapshots/qualifiers, and tests

Repository: brooklyn-server
Updated Branches:
  refs/heads/master 8d7444aea -> b5508747f


add more javadoc about use of snapshots/qualifiers, and tests


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

Branch: refs/heads/master
Commit: 3cd8f0b61750a66729f51d20178a927b10da8708
Parents: d5b4b57
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Oct 27 11:54:33 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Oct 27 11:57:28 2017 +0100

----------------------------------------------------------------------
 .../core/typereg/BundleUpgradeParser.java       | 41 ++++++++++++++------
 .../core/typereg/BundleUpgradeParserTest.java   | 11 +++++-
 2 files changed, 38 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3cd8f0b6/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
index 72603e2..e797137 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
@@ -54,17 +54,20 @@ public class BundleUpgradeParser {
      * given legacy catalog items. Here "legacy" means those in the `/catalog` persisted state, 
      * rather than items added in bundles.
      * 
-     * The format for the value is one of:
+     * The format for the value is one of the following:
      * <ul>
-     *   <li>Quoted {@code name:versionRange}, where version range follows the OSGi conventions 
-     *       (except that a single version number means exactly that version rather than greater 
-     *       than or equal to that verison). For example, {@code "my-tomcat:[0,1)"}
-     *   <li>Comma-separated list of quoted {@code name:versionRange}. For example,
-     *       {@code "my-tomcat:[0,1)","my-nginx:[0,1)"}
+     *   <li>Quoted {@code name:versionRange}, eg {@code "my-tomcat:[0,1)"};
+     *       see {@link #MANIFEST_HEADER_FORCE_REMOVE_BUNDLES} for more information
+     *   <li>Comma-separated list of quoted {@code name:versionRange}, eg {@code "my-tomcat:[0,1)","my-nginx:[0,1)"};
+     *       see {@link #MANIFEST_HEADER_FORCE_REMOVE_BUNDLES} for more information
      *   <li>{@code "*"} means all legacy items for things defined in this bundle, with version
-     *       numbers older than the version of the bundle. For example, if the bundle is 
+     *       numbers lower than the version of the bundle. For example, if the bundle is 
      *       version 1.0.0 and its catalog.bom contains items "foo" and "bar", then it is equivalent
-     *       to writing {@code "foo:[0,1.0.0)","bar:[0,1.0.0)"}
+     *       to writing {@code "foo:[0,1.0.0)","bar:[0,1.0.0)"}.
+     *       As per the comments on {@link #MANIFEST_HEADER_FORCE_REMOVE_BUNDLES},
+     *       the version of the bundle and items being added here to replace legacy catalog items
+     *       should typically be larger in major/minor/point value 
+     *       as a qualifier bump can be quite complex due to ordering differences.  
      * </ul>
      */
     @Beta
@@ -72,17 +75,31 @@ public class BundleUpgradeParser {
 
     /**
      * A header in a bundle's manifest, indicating that this bundle will force the removal of matching 
-     * bundle(s) that are in the `/bundles` persisted state.
+     * bundle(s) previously added and the types they contain.
      * 
      * The format for the value is one of:
      * <ul>
      *   <li>Quoted {@code name:versionRange}, where version range follows the OSGi conventions 
      *       (except that a single version number means exactly that version rather than greater 
-     *       than or equal to that verison). For example, {@code "org.example.mybundle:[0,1)"}
+     *       than or equal to that version). For example, {@code "org.example.mybundle:[0,1)"}.
+     *       Note in particular this uses OSGi ordering semantics not Brooklyn ordering semantics,
+     *       so qualifiers come <i>after</i> unqualified versions here, snapshot is not special-cased,
+     *       and qualifiers (last/fourth segment) are compared alphabetically
+     *       (thus "1.0" < "1.0.0.GA" < "1.0.0.SNAPSHOT" < "1.0.0.v10" < "1.0.0.v2" --
+     *       but they are the same with respect to major/minor/point numbers so if in doubt stick with those!).
+     *       Thus if using a range it is generally recommended to use a "[" square bracket start and ")" round bracket end
+     *       so that the start is inclusive and end exclusive, and any edge cases explicitly referenced.
+     *       If you want to replace a SNAPSHOT or RC version with a GA version you will need to call this out specially,
+     *       as described in the "comma-separated list" format below.
+     *       This is good anyway because there are different conventions for release names
+     *       (e.g. "1.0.0" or "1.0.0.GA" or "1.0.0.2017-12") and any automation here is likely to cause surprises.
      *   <li>Comma-separated list of quoted {@code name:versionRange}. For example,
      *       {@code "org.example.mybundle:[0,1)","org.example.myotherbundle:[0,1)"} (useful for
-     *       when this bundle merges the contents of two previous bundles).
-     *   <li>{@code "*"} means all older versions of this bundle. For example, if the bundle is 
+     *       when this bundle merges the contents of two previous bundles), or
+     *       {@code "*","org.example.mybundle:1.0.0.SNAPSHOT","org.example.mybundle:1.0.0.rc1"}
+     *       when releasing {@code org.example.mybundle:1.0.0.GA} 
+     *       (to replace versions pre 1.0.0 as well as a snapshot and RC1)
+     *   <li>{@code "*"} means all lower versions of this bundle. For example, if the bundle is 
      *       {@code org.example.mybundle:1.0.0}, then it is equivalent to writing 
      *       {@code "org.example.mybundle:[0,1.0.0)"}
      * </ul>

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/3cd8f0b6/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java b/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
index 6e638d0..26bd27a 100644
--- a/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
@@ -149,7 +149,7 @@ public class BundleUpgradeParserTest {
     @Test
     public void testParseBundleManifest() throws Exception {
         Bundle bundle = newMockBundle(ImmutableMap.of(
-                BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS, "\"foo:[0,1.0.0)\",\"bar:[0,1.0.0)\"",
+                BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS, "\"foo:[0,1.0.0)\",\"foo:1.0.0.SNAPSHOT\",\"bar:[0,1.0.0)\"",
                 BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, "\"org.example.brooklyn.mybundle:[0,1.0.0)\""));
         checkParse(bundle);
     }
@@ -157,7 +157,7 @@ public class BundleUpgradeParserTest {
     @Test
     public void testParseBundleManifestWithSpaces() throws Exception {
         Bundle bundle = newMockBundle(ImmutableMap.of(
-                BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS, "\"foo:[0,1.0.0)\", \"bar:[0,1.0.0)\"",
+                BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS, "\"foo:[0,1.0.0)\", \"foo:1.0.0.SNAPSHOT\", \"bar:[0,1.0.0)\"",
                 BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, " \"org.example.brooklyn.mybundle:[0,1.0.0)\""));
         checkParse(bundle);
     }
@@ -171,9 +171,16 @@ public class BundleUpgradeParserTest {
         assertFalse(upgrades.isBundleRemoved(new VersionedName("org.example.brooklyn.mybundle", "1.0.0")));
         
         assertTrue(upgrades.isLegacyItemRemoved(newMockCatalogItem("foo", "0.1.0")));
+        assertTrue(upgrades.isLegacyItemRemoved(newMockCatalogItem("foo", "0.1.0-SNAPSHOT")));
+        assertTrue(upgrades.isLegacyItemRemoved(newMockCatalogItem("foo", "0.0.0-SNAPSHOT")));
         assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("foo", "1.0.0")));
+        assertTrue(upgrades.isLegacyItemRemoved(newMockCatalogItem("foo", "1.0.0.SNAPSHOT")));
+        assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("foo", "1.0.0.GA")));
+        
         assertTrue(upgrades.isLegacyItemRemoved(newMockCatalogItem("bar", "0.1.0")));
         assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("bar", "1.0.0")));
+        assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("bar", "1.0.0.SNAPSHOT")));
+        
         assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("different", "0.1.0")));
     }
     


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

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


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

Branch: refs/heads/master
Commit: b5508747fbe64e166dffcbf42b7bd3471ee057eb
Parents: 8d7444a 3cd8f0b
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Sat Oct 28 11:03:20 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Sat Oct 28 11:03:20 2017 +0100

----------------------------------------------------------------------
 .../catalog/internal/CatalogInitialization.java | 16 +++---
 .../core/typereg/BundleUpgradeParser.java       | 52 +++++++++++++++-----
 .../core/typereg/BundleUpgradeParserTest.java   | 43 +++++++++++++++-
 .../org/apache/brooklyn/util/text/Strings.java  |  7 +++
 4 files changed, 95 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b5508747/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
----------------------------------------------------------------------


[2/4] brooklyn-server git commit: change RTypeSupplier to take filter

Posted by he...@apache.org.
change RTypeSupplier to take filter

makes it more general. also stores mgmt not TR as mgmt has smarts around persistence whereas TR doesnt
(just in case this is ever persisted, it shouldn't be but passing mgmt is the standard way;
alternative would be to pass TR in constructor and make it a TR filtered view;
passing mgmt then converting to TR seems weird middle ground)


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

Branch: refs/heads/master
Commit: d5b4b576fd546c8b7573678fc7a9775d8bfb5b3d
Parents: b05b819
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Oct 27 11:14:03 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Oct 27 11:57:28 2017 +0100

----------------------------------------------------------------------
 .../catalog/internal/CatalogInitialization.java     | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d5b4b576/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
index 225e3fd..f2a1f47 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogInitialization.java
@@ -39,7 +39,6 @@ import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
 import org.apache.brooklyn.api.mgmt.rebind.RebindExceptionHandler;
 import org.apache.brooklyn.api.objs.BrooklynObjectType;
-import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry;
 import org.apache.brooklyn.api.typereg.BrooklynTypeRegistry.RegisteredTypeKind;
 import org.apache.brooklyn.api.typereg.ManagedBundle;
 import org.apache.brooklyn.api.typereg.RegisteredType;
@@ -75,6 +74,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.Beta;
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Predicate;
 import com.google.common.base.Stopwatch;
 import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
@@ -580,7 +580,7 @@ public class CatalogInitialization implements ManagementContextInjectable {
             if (bundle.isPresent()) {
                 CatalogUpgrades catalogUpgrades = BundleUpgradeParser.parseBundleManifestForCatalogUpgrades(
                         bundle.get(),
-                        new RegisteredTypesSupplier(managementContext, managedBundle));
+                        new RegisteredTypesSupplier(managementContext, RegisteredTypePredicates.containingBundle(managedBundle)));
                 catalogUpgradesBuilder.addAll(catalogUpgrades);
             } else {
                 rebindLogger.info("Managed bundle "+managedBundle.getId()+" not found by OSGi Manager; "
@@ -591,16 +591,16 @@ public class CatalogInitialization implements ManagementContextInjectable {
     }
 
     private static class RegisteredTypesSupplier implements Supplier<Iterable<RegisteredType>> {
-        private final BrooklynTypeRegistry typeRegistry;
-        private final ManagedBundle bundle;
+        private final ManagementContext mgmt;
+        private final Predicate<? super RegisteredType> filter;
         
-        RegisteredTypesSupplier(ManagementContext mgmt, ManagedBundle bundle) {
-            this.typeRegistry = mgmt.getTypeRegistry();
-            this.bundle = bundle;
+        RegisteredTypesSupplier(ManagementContext mgmt, Predicate<? super RegisteredType> predicate) {
+            this.mgmt = mgmt;
+            this.filter = predicate;
         }
         @Override
         public Iterable<RegisteredType> get() {
-            return typeRegistry.getMatching(RegisteredTypePredicates.containingBundle(bundle));
+            return mgmt.getTypeRegistry().getMatching(filter);
         }
     }
 


[3/4] brooklyn-server git commit: forgive spaces and give better error if not quoted, in manifest headers

Posted by he...@apache.org.
forgive spaces and give better error if not quoted, in manifest headers


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

Branch: refs/heads/master
Commit: b05b8195eed5882d0ef80de268493a1f2b075f75
Parents: 9045005
Author: Alex Heneveld <al...@cloudsoftcorp.com>
Authored: Fri Oct 27 11:01:10 2017 +0100
Committer: Alex Heneveld <al...@cloudsoftcorp.com>
Committed: Fri Oct 27 11:57:28 2017 +0100

----------------------------------------------------------------------
 .../core/typereg/BundleUpgradeParser.java       | 11 ++++++-
 .../core/typereg/BundleUpgradeParserTest.java   | 34 +++++++++++++++++++-
 .../org/apache/brooklyn/util/text/Strings.java  |  7 ++++
 3 files changed, 50 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b05b8195/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
index 69bd583..72603e2 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BundleUpgradeParser.java
@@ -29,6 +29,7 @@ import java.util.Set;
 
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.osgi.VersionedName;
 import org.apache.brooklyn.util.text.BrooklynVersionSyntax;
 import org.apache.brooklyn.util.text.QuotedStringTokenizer;
@@ -297,7 +298,15 @@ public class BundleUpgradeParser {
         
         List<VersionRangedName> versionedItems = new ArrayList<>();
         for (String val : vals) {
-            versionedItems.add(VersionRangedName.fromString(val, singleVersionIsOsgiRange));
+            try {
+                versionedItems.add(VersionRangedName.fromString(val.trim(), singleVersionIsOsgiRange));
+            } catch (Exception e) {
+                if (Strings.containsAny(val, "(", ")", "[", "]") &&
+                        !Strings.containsAny(val, "'", "\"")) {
+                    throw Exceptions.propagateAnnotated("Entry cannot be parsed. If defining a range on an entry you must quote the entry.", e);
+                }
+                throw Exceptions.propagate(e);
+            }
         }
         return versionedItems;
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b05b8195/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java b/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
index 341cccb..6e638d0 100644
--- a/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/typereg/BundleUpgradeParserTest.java
@@ -151,6 +151,18 @@ public class BundleUpgradeParserTest {
         Bundle bundle = newMockBundle(ImmutableMap.of(
                 BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS, "\"foo:[0,1.0.0)\",\"bar:[0,1.0.0)\"",
                 BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, "\"org.example.brooklyn.mybundle:[0,1.0.0)\""));
+        checkParse(bundle);
+    }
+
+    @Test
+    public void testParseBundleManifestWithSpaces() throws Exception {
+        Bundle bundle = newMockBundle(ImmutableMap.of(
+                BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS, "\"foo:[0,1.0.0)\", \"bar:[0,1.0.0)\"",
+                BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_BUNDLES, " \"org.example.brooklyn.mybundle:[0,1.0.0)\""));
+        checkParse(bundle);
+    }
+
+    protected void checkParse(Bundle bundle) {
         Supplier<Iterable<RegisteredType>> typeSupplier = Suppliers.ofInstance(ImmutableList.of());
         
         CatalogUpgrades upgrades = BundleUpgradeParser.parseBundleManifestForCatalogUpgrades(bundle, typeSupplier);
@@ -164,6 +176,20 @@ public class BundleUpgradeParserTest {
         assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("bar", "1.0.0")));
         assertFalse(upgrades.isLegacyItemRemoved(newMockCatalogItem("different", "0.1.0")));
     }
+    
+    @Test
+    public void testForgetQuotesGivesNiceError() throws Exception {
+        Bundle bundle = newMockBundle(ImmutableMap.of(
+                BundleUpgradeParser.MANIFEST_HEADER_FORCE_REMOVE_LEGACY_ITEMS, "foo:[0,1.0.0),bar:[0,1.0.0)"));
+        Supplier<Iterable<RegisteredType>> typeSupplier = Suppliers.ofInstance(ImmutableList.of());
+        
+        try {
+            BundleUpgradeParser.parseBundleManifestForCatalogUpgrades(bundle, typeSupplier);
+            Asserts.shouldHaveFailedPreviously();
+        } catch (Exception e) {
+            Asserts.expectedFailureContainsIgnoreCase(e, "quote");
+        }
+    }
 
     @Test
     public void testStripQuotes() throws Exception {
@@ -183,7 +209,13 @@ public class BundleUpgradeParserTest {
     
     private Bundle newMockBundle(VersionedName name, Map<String, String> rawHeaders) {
         Dictionary<String, String> headers = new Hashtable<>(rawHeaders);
-        Bundle result = Mockito.mock(Bundle.class);
+        Bundle result;
+        try {
+            result = Mockito.mock(Bundle.class);
+        } catch (Exception e) {
+            throw new IllegalStateException("Java too old.  There is a bug in really early java 1.8.0 "
+                + "that causes mocks to fail, and has probably caused this.", e);
+        }
         Mockito.when(result.getHeaders()).thenReturn(headers);
         Mockito.when(result.getSymbolicName()).thenReturn(name.getSymbolicName());
         Mockito.when(result.getVersion()).thenReturn(Version.valueOf(name.getOsgiVersionString()));

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/b05b8195/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
----------------------------------------------------------------------
diff --git a/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java b/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
index dc134bc..d7ffd4b 100644
--- a/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
+++ b/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
@@ -722,6 +722,13 @@ public class Strings {
         return false;
     }
 
+    public static boolean containsAny(CharSequence input, CharSequence ...candidates) {
+        for (CharSequence candidate: candidates) {
+            if (containsLiteral(input, candidate)) return true;
+        }
+        return false;
+    }
+
     /** Returns a size string using metric suffixes from {@link ByteSizeStrings#metric()}, e.g. 23.5MB */
     public static String makeSizeString(long sizeInBytes) {
         return ByteSizeStrings.metric().makeSizeString(sizeInBytes);