Repository: incubator-brooklyn
Updated Branches:
  refs/heads/master e3b0389ff -> cd504e226


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/utils/common/src/main/java/org/apache/brooklyn/util/text/NaturalOrderComparator.java
----------------------------------------------------------------------
diff --cc 
brooklyn-server/utils/common/src/main/java/org/apache/brooklyn/util/text/NaturalOrderComparator.java
index 0000000,be53acc..d76244a
mode 000000,100644..100644
--- 
a/brooklyn-server/utils/common/src/main/java/org/apache/brooklyn/util/text/NaturalOrderComparator.java
+++ 
b/brooklyn-server/utils/common/src/main/java/org/apache/brooklyn/util/text/NaturalOrderComparator.java
@@@ -1,0 -1,165 +1,179 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing,
+  * software distributed under the License is distributed on an
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  * KIND, either express or implied.  See the License for the
+  * specific language governing permissions and limitations
+  * under the License.
+  * 
+ 
+ BROOKLYN NOTE: This is based on code from Pierre-Luc Paour,
+ adapted for the Brooklyn project in accordance with the original terms below.
+ Main changes are the package and edits for more recent Java compatibility.
+ 
+ --
+ 
+ NaturalOrderComparator.java -- Perform 'natural order' comparisons of strings 
in Java.
+ Copyright (C) 2003 by Pierre-Luc Paour <[email protected]>
+ 
+ Based on the C version by Martin Pool, of which this is more or less a 
straight conversion.
+ Copyright (C) 2000 by Martin Pool <[email protected]>
+ 
+ This software is provided 'as-is', without any express or implied
+ warranty.  In no event will the authors be held liable for any damages
+ arising from the use of this software.
+ 
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+ 
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ 
+  */
+ package org.apache.brooklyn.util.text;
+ 
+ import java.util.Comparator;
+ 
 -/** comparator which takes two strings and puts them in an order with special 
rules for numbers to be placed in numeric order;
++/** comparator which takes two strings and puts them in an order 
++ * with special rules for numbers (whole number) to be placed in numeric 
order;
+  * e.g. "10">"9", including when those numbers occur in the midst of equal 
text; e.g. "a10" > "a9";
+  * but not if the text differs; e.g. "a10" < "b9"
+  * <p>
+  * class is thread-safe. nulls not supported. (to support nulls, wrap in 
guava:
+  * <code>Ordering.from(NaturalOrderComparator.INSTANCE).nullsFirst()</code>)
++ * <p>
++ * NOTE: decimals are treated like a word-split, not a decimal point, i.e. 
1.9 < 1.10 
+  */
+ public class NaturalOrderComparator implements Comparator<String> {
+     
+     public static final NaturalOrderComparator INSTANCE = new 
NaturalOrderComparator();
+     
+     int compareRight(String a, String b)
+     {
+         int bias = 0;
+         int ia = 0;
+         int ib = 0;
+ 
+         // The longest run of digits wins.  That aside, the greatest
+         // value wins, but we can't know that it will until we've scanned
+         // both numbers to know that they have the same magnitude, so we
+         // remember it in BIAS.
+         for (;; ia++, ib++) {
+             char ca = charAt(a, ia);
+             char cb = charAt(b, ib);
+ 
+             if (!Character.isDigit(ca)
+                     && !Character.isDigit(cb)) {
+                 return bias;
+             } else if (!Character.isDigit(ca)) {
+                 return -1;
+             } else if (!Character.isDigit(cb)) {
+                 return +1;
+             } else if (ca < cb) {
+                 if (bias == 0) {
+                     bias = -1;
+                 }
+             } else if (ca > cb) {
+                 if (bias == 0)
+                     bias = +1;
+             } else if (ca == 0 && cb == 0) {
+                 return bias;
+             }
+         }
+     }
+ 
+     public int compare(String a, String b) {
+ 
+         int ia = 0, ib = 0;
+         int nza = 0, nzb = 0;
+         char ca, cb;
+         int result;
+ 
+         while (true) {
+             // only count the number of zeroes leading the last number 
compared
+             nza = nzb = 0;
+ 
+             ca = charAt(a, ia); cb = charAt(b, ib);
+ 
+             // skip over leading spaces or zeros
+             while (Character.isSpaceChar(ca) || ca == '0') {
+                 if (ca == '0') {
+                     nza++;
+                 } else {
+                     // only count consecutive zeroes
+                     nza = 0;
+                 }
+ 
+                 ca = charAt(a, ++ia);
+             }
+ 
+             while (Character.isSpaceChar(cb) || cb == '0') {
+                 if (cb == '0') {
+                     nzb++;
+                 } else {
+                     // only count consecutive zeroes
+                     nzb = 0;
+                 }
+ 
+                 cb = charAt(b, ++ib);
+             }
+ 
+             // process run of digits
+             if (Character.isDigit(ca) && Character.isDigit(cb)) {
+                 if ((result = compareRight(a.substring(ia), b.substring(ib))) 
!= 0) {
+                     return result;
+                 }
++            } else if ((Character.isDigit(ca) || nza>0) && 
(Character.isDigit(cb) || nzb>0)) {
++                // both sides are numbers, but at least one is a sequence of 
zeros
++                if (nza==0) {
++                    // b=0, a>0
++                    return 1;
++                }
++                if (nzb==0) {
++                    // inverse
++                    return -1;
++                }
++                // both sides were zero, continue to next check below
+             }
+ 
+             if (ca == 0 && cb == 0) {
+                 // The strings compare the same.  Perhaps the caller
+                 // will want to call strcmp to break the tie.
+                 return nza - nzb;
+             }
+ 
+             if (ca < cb) {
+                 return -1;
+             } else if (ca > cb) {
+                 return +1;
+             }
+ 
+             ++ia; ++ib;
+         }
+     }
+ 
+     static char charAt(String s, int i) {
+         if (i >= s.length()) {
+             return 0;
+         } else {
+             return s.charAt(i);
+         }
+     }
+ 
+ }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
----------------------------------------------------------------------
diff --cc 
brooklyn-server/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
index 0000000,626a312..d092abb
mode 000000,100644..100644
--- 
a/brooklyn-server/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
+++ 
b/brooklyn-server/utils/common/src/main/java/org/apache/brooklyn/util/text/Strings.java
@@@ -1,0 -1,945 +1,919 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing,
+  * software distributed under the License is distributed on an
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  * KIND, either express or implied.  See the License for the
+  * specific language governing permissions and limitations
+  * under the License.
+  */
+ package org.apache.brooklyn.util.text;
+ 
+ import java.text.DecimalFormat;
+ import java.text.DecimalFormatSymbols;
+ import java.text.NumberFormat;
+ import java.util.Arrays;
+ import java.util.Collections;
+ import java.util.Iterator;
+ import java.util.List;
+ import java.util.Locale;
+ import java.util.Map;
+ import java.util.StringTokenizer;
+ 
+ import javax.annotation.Nullable;
+ 
+ import org.apache.brooklyn.util.collections.MutableList;
+ import org.apache.brooklyn.util.collections.MutableMap;
+ import org.apache.brooklyn.util.guava.Maybe;
+ import org.apache.brooklyn.util.time.Time;
+ 
+ import com.google.common.base.CharMatcher;
+ import com.google.common.base.Functions;
+ import com.google.common.base.Joiner;
+ import com.google.common.base.Preconditions;
+ import com.google.common.base.Predicate;
+ import com.google.common.base.Supplier;
+ import com.google.common.base.Suppliers;
+ import com.google.common.collect.Ordering;
+ 
+ public class Strings {
+ 
+     /** The empty {@link String}. */
+     public static final String EMPTY = "";
+ 
+     /**
+      * Checks if the given string is null or is an empty string.
+      * Useful for pre-String.isEmpty.  And useful for StringBuilder etc.
+      *
+      * @param s the String to check
+      * @return true if empty or null, false otherwise.
+      *
+      * @see #isNonEmpty(CharSequence)
+      * @see #isBlank(CharSequence)
+      * @see #isNonBlank(CharSequence)
+      */
+     public static boolean isEmpty(CharSequence s) {
+         // Note guava has 
com.google.common.base.Strings.isNullOrEmpty(String),
+         // but that is just for String rather than CharSequence
+         return s == null || s.length()==0;
+     }
+ 
+     /**
+      * Checks if the given string is empty or only consists of whitespace.
+      *
+      * @param s the String to check
+      * @return true if blank, empty or null, false otherwise.
+      *
+      * @see #isEmpty(CharSequence)
+      * @see #isNonEmpty(CharSequence)
+      * @see #isNonBlank(CharSequence)
+      */
+     public static boolean isBlank(CharSequence s) {
+         return isEmpty(s) || CharMatcher.WHITESPACE.matchesAllOf(s);
+     }
+ 
+     /**
+      * The inverse of {@link #isEmpty(CharSequence)}.
+      *
+      * @param s the String to check
+      * @return true if non empty, false otherwise.
+      *
+      * @see #isEmpty(CharSequence)
+      * @see #isBlank(CharSequence)
+      * @see #isNonBlank(CharSequence)
+      */
+     public static boolean isNonEmpty(CharSequence s) {
+         return !isEmpty(s);
+     }
+ 
+     /**
+      * The inverse of {@link #isBlank(CharSequence)}.
+      *
+      * @param s the String to check
+      * @return true if non blank, false otherwise.
+      *
+      * @see #isEmpty(CharSequence)
+      * @see #isNonEmpty(CharSequence)
+      * @see #isBlank(CharSequence)
+      */
+     public static boolean isNonBlank(CharSequence s) {
+         return !isBlank(s);
+     }
+ 
+     /** @return a {@link Maybe} object which is absent if the argument {@link 
#isBlank(CharSequence)} */
+     public static <T extends CharSequence> Maybe<T> maybeNonBlank(T s) {
+         if (isNonBlank(s)) return Maybe.of(s);
+         return Maybe.absent();
+     }
+ 
+     /** throws IllegalArgument if string not empty; cf. guava 
Preconditions.checkXxxx */
+     public static void checkNonEmpty(CharSequence s) {
+         if (s==null) throw new IllegalArgumentException("String must not be 
null");
+         if (s.length()==0) throw new IllegalArgumentException("String must 
not be empty");
+     }
+     /** throws IllegalArgument if string not empty; cf. guava 
Preconditions.checkXxxx */
+     public static void checkNonEmpty(CharSequence s, String message) {
+         if (isEmpty(s)) throw new IllegalArgumentException(message);
+     }
+ 
+     /**
+      * Removes suffix from the end of the string. Returns string if it does 
not end with suffix.
+      */
+     public static String removeFromEnd(String string, String suffix) {
+         if (isEmpty(string)) {
+             return string;
+         } else if (!isEmpty(suffix) && string.endsWith(suffix)) {
+             return string.substring(0, string.length() - suffix.length());
+         } else {
+             return string;
+         }
+     }
+ 
 -    /** removes the first suffix in the list which is present at the end of 
string
 -     * and returns that string; ignores subsequent suffixes if a matching one 
is found;
 -     * returns the original string if no suffixes are at the end
 -     * @deprecated since 0.7.0 use {@link #removeFromEnd(String, String)} or 
{@link #removeAllFromEnd(String, String...)}
 -     */
 -    @Deprecated
 -    public static String removeFromEnd(String string, String ...suffixes) {
 -        if (isEmpty(string)) return string;
 -        for (String suffix : suffixes)
 -            if (suffix!=null && string.endsWith(suffix)) return 
string.substring(0, string.length() - suffix.length());
 -        return string;
 -    }
 -
+     /**
+      * As removeFromEnd, but repeats until all such suffixes are gone
+      */
+     public static String removeAllFromEnd(String string, String... suffixes) {
+         if (isEmpty(string)) return string;
+         int index = string.length();
+         boolean anotherLoopNeeded = true;
+         while (anotherLoopNeeded) {
+             if (isEmpty(string)) return string;
+             anotherLoopNeeded = false;
+             for (String suffix : suffixes)
+                 if (!isEmpty(suffix) && string.startsWith(suffix, index - 
suffix.length())) {
+                     index -= suffix.length();
+                     anotherLoopNeeded = true;
+                     break;
+                 }
+         }
+         return string.substring(0, index);
+     }
+ 
+     /**
+      * Removes prefix from the beginning of string. Returns string if it does 
not begin with prefix.
+      */
+     public static String removeFromStart(String string, String prefix) {
+         if (isEmpty(string)) {
+             return string;
+         } else if (!isEmpty(prefix) && string.startsWith(prefix)) {
+             return string.substring(prefix.length());
+         } else {
+             return string;
+         }
+     }
+ 
 -    /** removes the first prefix in the list which is present at the start of 
string
 -     * and returns that string; ignores subsequent prefixes if a matching one 
is found;
 -     * returns the original string if no prefixes match
 -     * @deprecated since 0.7.0 use {@link #removeFromStart(String, String)}
 -     */
 -    @Deprecated
 -    public static String removeFromStart(String string, String ...prefixes) {
 -        if (isEmpty(string)) return string;
 -        for (String prefix : prefixes)
 -            if (prefix!=null && string.startsWith(prefix)) return 
string.substring(prefix.length());
 -        return string;
 -    }
 -
+     /**
+      * As {@link #removeFromStart(String, String)}, repeating until all such 
prefixes are gone.
+      */
+     public static String removeAllFromStart(String string, String... 
prefixes) {
+         int index = 0;
+         boolean anotherLoopNeeded = true;
+         while (anotherLoopNeeded) {
+             if (isEmpty(string)) return string;
+             anotherLoopNeeded = false;
+             for (String prefix : prefixes) {
+                 if (!isEmpty(prefix) && string.startsWith(prefix, index)) {
+                     index += prefix.length();
+                     anotherLoopNeeded = true;
+                     break;
+                 }
+             }
+         }
+         return string.substring(index);
+     }
+ 
+     /** convenience for {@link com.google.common.base.Joiner} */
+     public static String join(Iterable<? extends Object> list, String 
separator) {
+         if (list==null) return null;
+         boolean app = false;
+         StringBuilder out = new StringBuilder();
+         for (Object s: list) {
+             if (app) out.append(separator);
+             out.append(s);
+             app = true;
+         }
+         return out.toString();
+     }
+     /** convenience for {@link com.google.common.base.Joiner} */
+     public static String join(Object[] list, String separator) {
+         boolean app = false;
+         StringBuilder out = new StringBuilder();
+         for (Object s: list) {
+             if (app) out.append(separator);
+             out.append(s);
+             app = true;
+         }
+         return out.toString();
+     }
+ 
+     /** convenience for joining lines together */
+     public static String lines(String ...lines) {
+         return Joiner.on("\n").join(Arrays.asList(lines));
+     }
+ 
+     /** NON-REGEX - replaces all key->value entries from the replacement map 
in source (non-regex) */
+     @SuppressWarnings("rawtypes")
+     public static String replaceAll(String source, Map replacements) {
+         for (Object rr: replacements.entrySet()) {
+             Map.Entry r = (Map.Entry)rr;
+             source = replaceAllNonRegex(source, ""+r.getKey(), 
""+r.getValue());
+         }
+         return source;
+     }
+ 
+     /** NON-REGEX replaceAll - see the better, explicitly named {@link 
#replaceAllNonRegex(String, String, String)}. */
+     public static String replaceAll(String source, String pattern, String 
replacement) {
+         return replaceAllNonRegex(source, pattern, replacement);
+     }
+ 
+     /** 
+      * Replaces all instances in source, of the given pattern, with the given 
replacement
+      * (not interpreting any arguments as regular expressions).
+      * <p>
+      * This is actually the same as the very ambiguous {@link 
String#replace(CharSequence, CharSequence)},
+      * which does replace all, but not using regex like the similarly 
ambiguous {@link String#replaceAll(String, String)} as.
+      * Alternatively see {@link #replaceAllRegex(String, String, String)}.
+      */
+     public static String replaceAllNonRegex(String source, String pattern, 
String replacement) {
+         if (source==null) return source;
+         StringBuilder result = new StringBuilder(source.length());
+         for (int i=0; i<source.length(); ) {
+             if (source.substring(i).startsWith(pattern)) {
+                 result.append(replacement);
+                 i += pattern.length();
+             } else {
+                 result.append(source.charAt(i));
+                 i++;
+             }
+         }
+         return result.toString();
+     }
+ 
+     /** REGEX replacement -- explicit method name for readability, doing same 
as {@link String#replaceAll(String, String)}. */
+     public static String replaceAllRegex(String source, String pattern, 
String replacement) {
+         return source.replaceAll(pattern, replacement);
+     }
+ 
+     /** Valid non alphanumeric characters for filenames. */
+     public static final String VALID_NON_ALPHANUM_FILE_CHARS = "-_.";
+ 
+     /**
+      * Returns a valid filename based on the input.
+      *
+      * A valid filename starts with the first alphanumeric character, then 
include
+      * all alphanumeric characters plus those in {@link 
#VALID_NON_ALPHANUM_FILE_CHARS},
+      * with any runs of invalid characters being replaced by {@literal _}.
+      *
+      * @throws NullPointerException if the input string is null.
+      * @throws IllegalArgumentException if the input string is blank.
+      */
+     public static String makeValidFilename(String s) {
+         Preconditions.checkNotNull(s, "Cannot make valid filename from null 
string");
+         Preconditions.checkArgument(isNonBlank(s), "Cannot make valid 
filename from blank string");
+         return 
CharMatcher.anyOf(VALID_NON_ALPHANUM_FILE_CHARS).or(CharMatcher.JAVA_LETTER_OR_DIGIT)
+                 .negate()
+                 .trimAndCollapseFrom(s, '_');
+     }
+ 
+     /**
+      * A {@link CharMatcher} that matches valid Java identifier characters.
+      *
+      * @see Character#isJavaIdentifierPart(char)
+      */
+     public static final CharMatcher IS_JAVA_IDENTIFIER_PART = 
CharMatcher.forPredicate(new Predicate<Character>() {
+         @Override
+         public boolean apply(@Nullable Character input) {
+             return input != null && Character.isJavaIdentifierPart(input);
+         }
+     });
+ 
+     /**
+      * Returns a valid Java identifier name based on the input.
+      *
+      * Removes certain characterss (like apostrophe), replaces one or more 
invalid
+      * characterss with {@literal _}, and prepends {@literal _} if the first 
character
+      * is only valid as an identifier part (not start).
+      * <p>
+      * The result is usually unique to s, though this isn't guaranteed, for 
example if
+      * all characters are invalid. For a unique identifier use {@link 
#makeValidUniqueJavaName(String)}.
+      *
+      * @see #makeValidUniqueJavaName(String)
+      */
+     public static String makeValidJavaName(String s) {
+         if (s==null) return "__null";
+         if (s.length()==0) return "__empty";
+         String name = 
IS_JAVA_IDENTIFIER_PART.negate().collapseFrom(CharMatcher.is('\'').removeFrom(s),
 '_');
+         if (!Character.isJavaIdentifierStart(s.charAt(0))) return "_" + name;
+         return name;
+     }
+ 
+     /**
+      * Returns a unique valid java identifier name based on the input.
+      *
+      * Translated as per {@link #makeValidJavaName(String)} but with {@link 
String#hashCode()}
+      * appended where necessary to guarantee uniqueness.
+      *
+      * @see #makeValidJavaName(String)
+      */
+     public static String makeValidUniqueJavaName(String s) {
+         String name = makeValidJavaName(s);
+         if (isEmpty(s) || IS_JAVA_IDENTIFIER_PART.matchesAllOf(s) || 
CharMatcher.is('\'').matchesNoneOf(s)) {
+             return name;
+         } else {
+             return name + "_" + s.hashCode();
+         }
+     }
+ 
+     /** @see {@link Identifiers#makeRandomId(int)} */
+     public static String makeRandomId(int l) {
+         return Identifiers.makeRandomId(l);
+     }
+ 
+     /** pads the string with 0's at the left up to len; no padding if i 
longer than len */
+     public static String makeZeroPaddedString(int i, int len) {
+         return makePaddedString(""+i, len, "0", "");
+     }
+ 
+     /** pads the string with "pad" at the left up to len; no padding if base 
longer than len */
+     public static String makePaddedString(String base, int len, String 
left_pad, String right_pad) {
+         String s = ""+(base==null ? "" : base);
+         while (s.length()<len) s=left_pad+s+right_pad;
+         return s;
+     }
+ 
+     public static void trimAll(String[] s) {
+         for (int i=0; i<s.length; i++)
+             s[i] = (s[i]==null ? "" : s[i].trim());
+     }
+ 
+     /** creates a string from a real number, with specified accuracy (more 
iff it comes for free, ie integer-part);
+      * switches to E notation if needed to fit within maxlen; can be padded 
left up too (not useful)
+      * @param x number to use
+      * @param maxlen maximum length for the numeric string, if possible (-1 
to suppress)
+      * @param prec number of digits accuracy desired (more kept for integers)
+      * @param leftPadLen will add spaces at left if necessary to make string 
this long (-1 to suppress) [probably not usef]
+      * @return such a string
+      */
+     public static String makeRealString(double x, int maxlen, int prec, int 
leftPadLen) {
+         return makeRealString(x, maxlen, prec, leftPadLen, 0.00000000001, 
true);
+     }
+     /** creates a string from a real number, with specified accuracy (more 
iff it comes for free, ie integer-part);
+      * switches to E notation if needed to fit within maxlen; can be padded 
left up too (not useful)
+      * @param x number to use
+      * @param maxlen maximum length for the numeric string, if possible (-1 
to suppress)
+      * @param prec number of digits accuracy desired (more kept for integers)
+      * @param leftPadLen will add spaces at left if necessary to make string 
this long (-1 to suppress) [probably not usef]
+      * @param skipDecimalThreshhold if positive it will not add a decimal 
part if the fractional part is less than this threshhold
+      *    (but for a value 3.00001 it would show zeroes, e.g. with 3 
precision and positive threshhold <= 0.00001 it would show 3.00);
+      *    if zero or negative then decimal digits are always shown
+      * @param useEForSmallNumbers whether to use E notation for numbers near 
zero (e.g. 0.001)
+      * @return such a string
+      */
+     public static String makeRealString(double x, int maxlen, int prec, int 
leftPadLen, double skipDecimalThreshhold, boolean useEForSmallNumbers) {
+         if (x<0) return "-"+makeRealString(-x, maxlen, prec, leftPadLen);
+         NumberFormat df = DecimalFormat.getInstance();
+         //df.setMaximumFractionDigits(maxlen);
+         df.setMinimumFractionDigits(0);
+         //df.setMaximumIntegerDigits(prec);
+         df.setMinimumIntegerDigits(1);
+         df.setGroupingUsed(false);
+         String s;
+         if (x==0) {
+             if (skipDecimalThreshhold>0 || prec<=1) s="0";
+             else {
+                 s="0.0";
+                 while (s.length()<prec+1) s+="0";
+             }
+         } else {
+ //            long bits= Double.doubleToLongBits(x);
+ //            int s = ((bits >> 63) == 0) ? 1 : -1;
+ //            int e = (int)((bits >> 52) & 0x7ffL);
+ //            long m = (e == 0) ?
+ //            (bits & 0xfffffffffffffL) << 1 :
+ //            (bits & 0xfffffffffffffL) | 0x10000000000000L;
+ //            //s*m*2^(e-1075);
+             int log = (int)Math.floor(Math.log10(x));
+             int numFractionDigits = (log>=prec ? 0 : prec-log-1);
+             if (numFractionDigits>0) { //need decimal digits
+                 if (skipDecimalThreshhold>0) {
+                     int checkFractionDigits = 0;
+                     double multiplier = 1;
+                     while (checkFractionDigits < numFractionDigits) {
+                         if (Math.abs(x - 
Math.rint(x*multiplier)/multiplier)<skipDecimalThreshhold)
+                             break;
+                         checkFractionDigits++;
+                         multiplier*=10;
+                     }
+                     numFractionDigits = checkFractionDigits;
+                 }
+                 df.setMinimumFractionDigits(numFractionDigits);
+                 df.setMaximumFractionDigits(numFractionDigits);
+             } else {
+                 //x = Math.rint(x);
+                 df.setMaximumFractionDigits(0);
+             }
+             s = df.format(x);
+             if (maxlen>0 && s.length()>maxlen) {
+                 //too long:
+                 double signif = x/Math.pow(10,log);
+                 if (s.indexOf(getDefaultDecimalSeparator())>=0) {
+                     //have a decimal point; either we are very small 0.000001
+                     //or prec is larger than maxlen
+                     if (Math.abs(x)<1 && useEForSmallNumbers) {
+                         //very small-- use alternate notation
+                         s = makeRealString(signif, -1, prec, -1) + "E"+log;
+                     } else {
+                         //leave it alone, user error or E not wanted
+                     }
+                 } else {
+                     //no decimal point, integer part is too large, use alt 
notation
+                     s = makeRealString(signif, -1, prec, -1) + "E"+log;
+                 }
+             }
+         }
+         if (leftPadLen>s.length())
+             return makePaddedString(s, leftPadLen, " ", "");
+         else
+             return s;
+     }
+ 
+     /** creates a string from a real number, with specified accuracy (more 
iff it comes for free, ie integer-part);
+      * switches to E notation if needed to fit within maxlen; can be padded 
left up too (not useful)
+      * @param x number to use
+      * @param maxlen maximum length for the numeric string, if possible (-1 
to suppress)
+      * @param prec number of digits accuracy desired (more kept for integers)
+      * @param leftPadLen will add spaces at left if necessary to make string 
this long (-1 to suppress) [probably not usef]
+      * @return such a string
+      */
+     public static String makeRealStringNearZero(double x, int maxlen, int 
prec, int leftPadLen) {
+         if (Math.abs(x)<0.0000000001) x=0;
+         NumberFormat df = DecimalFormat.getInstance();
+         //df.setMaximumFractionDigits(maxlen);
+         df.setMinimumFractionDigits(0);
+         //df.setMaximumIntegerDigits(prec);
+         df.setMinimumIntegerDigits(1);
+         df.setGroupingUsed(false);
+         String s;
+         if (x==0) {
+             if (prec<=1) s="0";
+             else {
+                 s="0.0";
+                 while (s.length()<prec+1) s+="0";
+             }
+         } else {
+ //            long bits= Double.doubleToLongBits(x);
+ //            int s = ((bits >> 63) == 0) ? 1 : -1;
+ //            int e = (int)((bits >> 52) & 0x7ffL);
+ //            long m = (e == 0) ?
+ //            (bits & 0xfffffffffffffL) << 1 :
+ //            (bits & 0xfffffffffffffL) | 0x10000000000000L;
+ //            //s*m*2^(e-1075);
+             int log = (int)Math.floor(Math.log10(x));
+             int scale = (log>=prec ? 0 : prec-log-1);
+             if (scale>0) { //need decimal digits
+                 double scale10 = Math.pow(10, scale);
+                 x = Math.rint(x*scale10)/scale10;
+                 df.setMinimumFractionDigits(scale);
+                 df.setMaximumFractionDigits(scale);
+             } else {
+                 //x = Math.rint(x);
+                 df.setMaximumFractionDigits(0);
+             }
+             s = df.format(x);
+             if (maxlen>0 && s.length()>maxlen) {
+                 //too long:
+                 double signif = x/Math.pow(10,log);
+                 if (s.indexOf('.')>=0) {
+                     //have a decimal point; either we are very small 0.000001
+                     //or prec is larger than maxlen
+                     if (Math.abs(x)<1) {
+                         //very small-- use alternate notation
+                         s = makeRealString(signif, -1, prec, -1) + "E"+log;
+                     } else {
+                         //leave it alone, user error
+                     }
+                 } else {
+                     //no decimal point, integer part is too large, use alt 
notation
+                     s = makeRealString(signif, -1, prec, -1) + "E"+log;
+                 }
+             }
+         }
+         if (leftPadLen>s.length())
+             return makePaddedString(s, leftPadLen, " ", "");
+         else
+             return s;
+     }
+ 
+     /** returns the first word (whitespace delimited text), or null if there 
is none (input null or all whitespace) */
+     public static String getFirstWord(String s) {
+         if (s==null) return null;
+         int start = 0;
+         while (start<s.length()) {
+             if (!Character.isWhitespace(s.charAt(start)))
+                 break;
+             start++;
+         }
+         int end = start;
+         if (end >= s.length())
+             return null;
+         while (end<s.length()) {
+             if (Character.isWhitespace(s.charAt(end)))
+                 break;
+             end++;
+         }
+         return s.substring(start, end);
+     }
+ 
+     /** returns the last word (whitespace delimited text), or null if there 
is none (input null or all whitespace) */
+     public static String getLastWord(String s) {
+         if (s==null) return null;
+         int end = s.length()-1;
+         while (end >= 0) {
+             if (!Character.isWhitespace(s.charAt(end)))
+                 break;
+             end--;
+         }
+         int start = end;
+         if (start < 0)
+             return null;
+         while (start >= 0) {
+             if (Character.isWhitespace(s.charAt(start)))
+                 break;
+             start--;
+         }
+         return s.substring(start+1, end+1);
+     }
+ 
+     /** returns the first word after the given phrase, or null if no such 
phrase;
+      * if the character immediately after the phrase is not whitespace, the 
non-whitespace
+      * sequence starting with that character will be returned */
+     public static String getFirstWordAfter(String context, String phrase) {
+         if (context==null || phrase==null) return null;
+         int index = context.indexOf(phrase);
+         if (index<0) return null;
+         return getFirstWord(context.substring(index + phrase.length()));
+     }
+ 
+    /**
+     * searches in context for the given phrase, and returns the 
<b>untrimmed</b> remainder of the first line
+     * on which the phrase is found
+     */
+     public static String getRemainderOfLineAfter(String context, String 
phrase) {
+         if (context == null || phrase == null) return null;
+         int index = context.indexOf(phrase);
+         if (index < 0) return null;
+         int lineEndIndex = context.indexOf("\n", index);
+         if (lineEndIndex <= 0) {
+             return context.substring(index + phrase.length());
+         } else {
+             return context.substring(index + phrase.length(), lineEndIndex);
+         }
+     }
+ 
+     /** @deprecated use {@link Time#makeTimeStringRounded(long)} */
+     @Deprecated
+     public static String makeTimeString(long utcMillis) {
+         return Time.makeTimeStringRounded(utcMillis);
+     }
+ 
+     /** returns e.g. { "prefix01", ..., "prefix96" };
+      * see more functional NumericRangeGlobExpander for "prefix{01-96}"
+      */
+     public static String[] makeArray(String prefix, int count) {
+         String[] result = new String[count];
+         int len = (""+count).length();
+         for (int i=1; i<=count; i++)
+             result[i-1] = prefix + makePaddedString("", len, "0", ""+i);
+         return result;
+     }
+ 
+     public static String[] combineArrays(String[] ...arrays) {
+         int totalLen = 0;
+         for (String[] array : arrays) {
+             if (array!=null) totalLen += array.length;
+         }
+         String[] result = new String[totalLen];
+         int i=0;
+         for (String[] array : arrays) {
+             if (array!=null) for (String s : array) {
+                 result[i++] = s;
+             }
+         }
+         return result;
+     }
+ 
+     public static String toInitialCapOnly(String value) {
+         if (value==null || value.length()==0) return value;
+         return value.substring(0, 1).toUpperCase(Locale.ENGLISH) + 
value.substring(1).toLowerCase(Locale.ENGLISH);
+     }
+ 
+     public static String reverse(String name) {
+         return new StringBuffer(name).reverse().toString();
+     }
+ 
+     public static boolean isLowerCase(String s) {
+         return s.toLowerCase().equals(s);
+     }
+ 
+     public static String makeRepeated(char c, int length) {
+         StringBuilder result = new StringBuilder(length);
+         for (int i = 0; i < length; i++) {
+             result.append(c);
+         }
+         return result.toString();
+     }
+ 
+     public static String trim(String s) {
+         if (s==null) return null;
+         return s.trim();
+     }
+ 
+     public static String trimEnd(String s) {
+         if (s==null) return null;
+         return ("a"+s).trim().substring(1);
+     }
+ 
+     /** returns up to maxlen characters from the start of s */
+     public static String maxlen(String s, int maxlen) {
+         return maxlenWithEllipsis(s, maxlen, "");
+     }
+ 
+     /** as {@link #maxlenWithEllipsis(String, int, String) with "..." as the 
ellipsis */
+     public static String maxlenWithEllipsis(String s, int maxlen) {
+         return maxlenWithEllipsis(s, maxlen, "...");
+     }
+     /** as {@link #maxlenWithEllipsis(String, int) but replacing the last few 
chars with the given ellipsis */
+     public static String maxlenWithEllipsis(String s, int maxlen, String 
ellipsis) {
+         if (s==null) return null;
+         if (ellipsis==null) ellipsis="";
+         if (s.length()<=maxlen) return s;
+         return s.substring(0, Math.max(maxlen-ellipsis.length(), 0))+ellipsis;
+     }
+ 
+     /** returns toString of the object if it is not null, otherwise null */
+     public static String toString(Object o) {
+         return toStringWithValueForNull(o, null);
+     }
+ 
+     /** returns toString of the object if it is not null, otherwise the given 
value */
+     public static String toStringWithValueForNull(Object o, String 
valueIfNull) {
+         if (o==null) return valueIfNull;
+         return o.toString();
+     }
+ 
+     public static boolean containsLiteralIgnoreCase(CharSequence input, 
CharSequence fragment) {
+         if (input==null) return false;
+         if (isEmpty(fragment)) return true;
+         int lastValidStartPos = input.length()-fragment.length();
+         char f0u = Character.toUpperCase(fragment.charAt(0));
+         char f0l = Character.toLowerCase(fragment.charAt(0));
+         i: for (int i=0; i<=lastValidStartPos; i++) {
+             char ii = input.charAt(i);
+             if (ii==f0l || ii==f0u) {
+                 for (int j=1; j<fragment.length(); j++) {
+                     if 
(Character.toLowerCase(input.charAt(i+j))!=Character.toLowerCase(fragment.charAt(j)))
+                         continue i;
+                 }
+                 return true;
+             }
+         }
+         return false;
+     }
+ 
+     public static boolean containsLiteral(CharSequence input, CharSequence 
fragment) {
+         if (input==null) return false;
+         if (isEmpty(fragment)) return true;
+         int lastValidStartPos = input.length()-fragment.length();
+         char f0 = fragment.charAt(0);
+         i: for (int i=0; i<=lastValidStartPos; i++) {
+             char ii = input.charAt(i);
+             if (ii==f0) {
+                 for (int j=1; j<fragment.length(); j++) {
+                     if (input.charAt(i+j)!=fragment.charAt(j))
+                         continue i;
+                 }
+                 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);
+     }
+ 
+     /** Returns a size string using ISO suffixes from {@link 
ByteSizeStrings#iso()}, e.g. 23.5MiB */
+     public static String makeISOSizeString(long sizeInBytes) {
+         return ByteSizeStrings.iso().makeSizeString(sizeInBytes);
+     }
+ 
+     /** Returns a size string using Java suffixes from {@link 
ByteSizeStrings#java()}, e.g. 23m */
+     public static String makeJavaSizeString(long sizeInBytes) {
+         return ByteSizeStrings.java().makeSizeString(sizeInBytes);
+     }
+ 
+     /** returns a configurable shortener */
+     public static StringShortener shortener() {
+         return new StringShortener();
+     }
+ 
+     public static Supplier<String> toStringSupplier(Object src) {
+         return Suppliers.compose(Functions.toStringFunction(), 
Suppliers.ofInstance(src));
+     }
+ 
+     /** wraps a call to {@link String#format(String, Object...)} in a 
toString, i.e. using %s syntax,
+      * useful for places where we want deferred evaluation
+      * (e.g. as message to {@link Preconditions} to skip concatenation when 
not needed) */
+     public static FormattedString format(String pattern, Object... args) {
+         return new FormattedString(pattern, args);
+     }
+ 
+     /** returns "s" if the argument is not 1, empty string otherwise; useful 
when constructing plurals */
+     public static String s(int count) {
+         return count==1 ? "" : "s";
+     }
+     /** as {@link #s(int)} based on size of argument */
+     public static String s(@Nullable Map<?,?> x) {
+         return s(x==null ? 0 : x.size());
+     }
+     /** as {@link #s(int)} based on size of argument */
+     public static String s(Iterable<?> x) {
+         if (x==null) return s(0);
+         return s(x.iterator());
+     }
+     /** as {@link #s(int)} based on size of argument */
+     public static String s(Iterator<?> x) {
+         int count = 0;
+         if (x==null || !x.hasNext()) {}
+         else {
+             x.next(); count++;
+             if (x.hasNext()) count++;
+         }
+         return s(count);
+     }
+ 
+     /** returns "ies" if the argument is not 1, "y" otherwise; useful when 
constructing plurals */
+     public static String ies(int count) {
+         return count==1 ? "y" : "ies";
+     }
+     /** as {@link #ies(int)} based on size of argument */
+     public static String ies(@Nullable Map<?,?> x) {
+         return ies(x==null ? 0 : x.size());
+     }
+     /** as {@link #ies(int)} based on size of argument */
+     public static String ies(Iterable<?> x) {
+         if (x==null) return ies(0);
+         return ies(x.iterator());
+     }
+     /** as {@link #ies(int)} based on size of argument */
+     public static String ies(Iterator<?> x) {
+         int count = 0;
+         if (x==null || !x.hasNext()) {}
+         else {
+             x.next(); count++;
+             if (x.hasNext()) count++;
+         }
+         return ies(count);
+     }
+ 
+     /** converts a map of any objects to a map of strings, using the 
tostring, and returning "null" for nulls 
+      * @deprecated since 0.7.0 use {@link #toStringMap(Map, String)} to 
remove ambiguity about how to handle null */
+     // NB previously the javadoc here was wrong, said it returned null not 
"null"
+     @Deprecated
+     public static Map<String, String> toStringMap(Map<?,?> map) {
+         return toStringMap(map, "null");
+     }
+     /** converts a map of any objects to a map of strings, using {@link 
Object#toString()},
+      * with the second argument used where a value (or key) is null */
+     public static Map<String, String> toStringMap(Map<?,?> map, String 
valueIfNull) {
+         if (map==null) return null;
+         Map<String,String> result = MutableMap.<String, String>of();
+         for (Map.Entry<?,?> e: map.entrySet()) {
+             result.put(toStringWithValueForNull(e.getKey(), valueIfNull), 
toStringWithValueForNull(e.getValue(), valueIfNull));
+         }
+         return result;
+     }
+     
+     /** converts a list of any objects to a list of strings, using {@link 
Object#toString()},
+      * with the second argument used where an entry is null */
+     public static List<String> toStringList(List<?> list, String valueIfNull) 
{
+         if (list==null) return null;
+         List<String> result = MutableList.of();
+         for (Object v: list) result.add(toStringWithValueForNull(v, 
valueIfNull));
+         return result;
+     }
+ 
+     /** returns base repeated count times */
+     public static String repeat(String base, int count) {
+         if (base==null) return null;
+         StringBuilder result = new StringBuilder();
+         for (int i=0; i<count; i++)
+             result.append(base);
+         return result.toString();
+     }
+ 
+     /** returns comparator which compares based on length, with shorter ones 
first (and null before that);
+      * in event of a tie, it uses the toString order */
+     public static Ordering<String> lengthComparator() {
+         return 
Ordering.<Integer>natural().onResultOf(StringFunctions.length()).compound(Ordering.<String>natural()).nullsFirst();
+     }
+ 
+     public static boolean isMultiLine(String s) {
+         if (s==null) return false;
+         if (s.indexOf('\n')>=0 || s.indexOf('\r')>=0) return true;
+         return false;
+     }
+     public static String getFirstLine(String s) {
+         int idx = s.indexOf('\n');
+         if (idx==-1) return s;
+         return s.substring(0, idx);
+     }
+ 
+     /** looks for first section of text in following the prefix and, if 
present, before the suffix;
+      * null if the prefix is not present in the string, and everything after 
the prefix if suffix is not present in the string;
+      * if either prefix or suffix is null, it is treated as the start/end of 
the string */
+     public static String getFragmentBetween(String input, String prefix, 
String suffix) {
+         if (input==null) return null;
+         int index;
+         if (prefix!=null) {
+             index = input.indexOf(prefix);
+             if (index==-1) return null;
+             input = input.substring(index + prefix.length());
+         }
+         if (suffix!=null) {
+             index = input.indexOf(suffix);
+             if (index>=0) input = input.substring(0, index);
+         }
+         return input;
+     }
+ 
+     public static int getWordCount(String phrase, boolean respectQuotes) {
+         if (phrase==null) return 0;
+         phrase = phrase.trim();
+         if (respectQuotes)
+             return new QuotedStringTokenizer(phrase).remainderAsList().size();
+         else
+             return Collections.list(new StringTokenizer(phrase)).size();
+     }
+ 
+     public static char getDecimalSeparator(Locale locale) {
+         DecimalFormatSymbols dfs = new DecimalFormatSymbols(locale);
+         return dfs.getDecimalSeparator();
+     }
+ 
+     public static char getDefaultDecimalSeparator() {
+         return getDecimalSeparator(Locale.getDefault());
+     }
+ 
+     /** replaces each sequence of whitespace in the first string with the 
replacement in the second string */
+     public static String collapseWhitespace(String x, String 
whitespaceReplacement) {
+         if (x==null) return null;
+         return replaceAllRegex(x, "\\s+", whitespaceReplacement);
+     }
+ 
+     public static String toLowerCase(String value) {
+         if (value==null || value.length()==0) return value;
+         return value.toLowerCase(Locale.ENGLISH);
+     }
+ 
+     /**
+      * @return null if var is null or empty string, otherwise return var
+      */
+     public static String emptyToNull(String var) {
+         if (isNonEmpty(var)) {
+             return var;
+         } else {
+             return null;
+         }
+     }
+     
+     /** Returns canonicalized string from the given object, made "unique" by:
+      * <li> putting sets into the toString order
+      * <li> appending a hash code if it's longer than the max (and the max is 
bigger than 0) */
+     public static String toUniqueString(Object x, int optionalMax) {
+         if (x instanceof Iterable && !(x instanceof List)) {
+             // unsorted collections should have a canonical order imposed
+             MutableList<String> result = MutableList.of();
+             for (Object xi: (Iterable<?>)x) {
+                 result.add(toUniqueString(xi, optionalMax));
+             }
+             Collections.sort(result);
+             x = result.toString();
+         }
+         if (x==null) return "{null}";
+         String xs = x.toString();
+         if (xs.length()<=optionalMax || optionalMax<=0) return xs;
+         return maxlenWithEllipsis(xs, 
optionalMax-8)+"/"+Integer.toHexString(xs.hashCode());
+     }
+ 
+ }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/collections/CollectionFunctionalsTest.java
----------------------------------------------------------------------
diff --cc 
brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/collections/CollectionFunctionalsTest.java
index 0000000,1d75297..1ce4015
mode 000000,100644..100644
--- 
a/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/collections/CollectionFunctionalsTest.java
+++ 
b/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/collections/CollectionFunctionalsTest.java
@@@ -1,0 -1,58 +1,82 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing,
+  * software distributed under the License is distributed on an
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  * KIND, either express or implied.  See the License for the
+  * specific language governing permissions and limitations
+  * under the License.
+  */
+ package org.apache.brooklyn.util.collections;
+ 
+ import org.apache.brooklyn.util.collections.CollectionFunctionals;
+ import org.testng.Assert;
+ import org.testng.annotations.Test;
+ 
++import com.google.common.base.Predicates;
+ import com.google.common.collect.ImmutableList;
+ import com.google.common.collect.ImmutableMap;
+ 
+ public class CollectionFunctionalsTest {
+ 
+     @Test
+     public void testListSize() {
+         
Assert.assertTrue(CollectionFunctionals.sizeEquals(2).apply(ImmutableList.of("x",
 "y")));
+         Assert.assertFalse(CollectionFunctionals.sizeEquals(2).apply(null));
+         
Assert.assertTrue(CollectionFunctionals.sizeEquals(0).apply(ImmutableList.of()));
+         Assert.assertFalse(CollectionFunctionals.sizeEquals(0).apply(null));
+     }
+ 
+     @Test
+     public void testMapSize() {
+         
Assert.assertTrue(CollectionFunctionals.<String>mapSizeEquals(2).apply(ImmutableMap.of("x",
 "1", "y", "2")));
+         
Assert.assertFalse(CollectionFunctionals.<String>mapSizeEquals(2).apply(null));
+         
Assert.assertTrue(CollectionFunctionals.mapSizeEquals(0).apply(ImmutableMap.of()));
+         
Assert.assertFalse(CollectionFunctionals.mapSizeEquals(0).apply(null));
+     }
+ 
+     @Test
+     public void testMapSizeOfNull() {
+         Assert.assertEquals(CollectionFunctionals.mapSize().apply(null), 
null);
+         Assert.assertEquals(CollectionFunctionals.mapSize(-1).apply(null), 
(Integer)(-1));
+     }
+ 
+     @Test
+     public void testFirstElement() {
+         Assert.assertEquals(CollectionFunctionals.firstElement().apply(null), 
null);
+         
Assert.assertEquals(CollectionFunctionals.firstElement().apply(ImmutableList.of("a")),
 "a");
+         
Assert.assertEquals(CollectionFunctionals.firstElement().apply(ImmutableList.of("a",
 "b", "c")), "a");
+     }
++
++    @Test
++    public void testAllAndAny() {
++        
Assert.assertEquals(CollectionFunctionals.all(Predicates.equalTo(1)).apply(
++            MutableList.of(1, 1, 1)), true);
++        
Assert.assertEquals(CollectionFunctionals.all(Predicates.equalTo(1)).apply(
++            MutableList.<Integer>of()), true);
++        
Assert.assertEquals(CollectionFunctionals.all(Predicates.equalTo(1)).apply(
++            MutableList.of(1, 0, 1)), false);
++        
Assert.assertEquals(CollectionFunctionals.all(Predicates.equalTo(1)).apply(
++            MutableList.of(0, 0, 0)), false);
++        
++        
Assert.assertEquals(CollectionFunctionals.any(Predicates.equalTo(1)).apply(
++            MutableList.of(1, 1, 1)), true);
++        
Assert.assertEquals(CollectionFunctionals.any(Predicates.equalTo(1)).apply(
++            MutableList.<Integer>of()), false);
++        
Assert.assertEquals(CollectionFunctionals.any(Predicates.equalTo(1)).apply(
++            MutableList.of(1, 0, 1)), true);
++        
Assert.assertEquals(CollectionFunctionals.any(Predicates.equalTo(1)).apply(
++            MutableList.of(0, 0, 0)), false);
++        
++    }
++    
+ }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/ComparableVersionTest.java
----------------------------------------------------------------------
diff --cc 
brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/ComparableVersionTest.java
index 0000000,16b07b8..a730ade
mode 000000,100644..100644
--- 
a/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/ComparableVersionTest.java
+++ 
b/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/ComparableVersionTest.java
@@@ -1,0 -1,54 +1,63 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing,
+  * software distributed under the License is distributed on an
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  * KIND, either express or implied.  See the License for the
+  * specific language governing permissions and limitations
+  * under the License.
+  */
+ package org.apache.brooklyn.util.text;
+ 
 -import org.apache.brooklyn.util.text.NaturalOrderComparator;
+ import org.testng.Assert;
+ import org.testng.annotations.Test;
+ 
+ public class ComparableVersionTest {
+ 
 -    public static final NaturalOrderComparator noc = new 
NaturalOrderComparator();
 -    
++    ComparableVersion v = new ComparableVersion("10.5.8");
++    ComparableVersion v_rc2 = new ComparableVersion("10.5.8-rc2");
++
+     @Test
+     public void testBasicOnes() {
 -        Assert.assertEquals(0, noc.compare("a", "a"));
 -        Assert.assertTrue(noc.compare("a", "b") < 0);
 -        Assert.assertTrue(noc.compare("b", "a") > 0);
++        Assert.assertTrue(v.isGreaterThanAndNotEqualTo("10.5"));
++        Assert.assertTrue(v.isGreaterThanOrEqualTo("10.5.8"));
++        Assert.assertFalse(v.isGreaterThanAndNotEqualTo("10.5.8"));
++
++        Assert.assertTrue(v.isLessThanAndNotEqualTo("10.6"));
++        Assert.assertTrue(v.isLessThanOrEqualTo("10.5.8"));
++        Assert.assertFalse(v.isLessThanAndNotEqualTo("10.5.8"));
++        
++        Assert.assertTrue(v.isLessThanAndNotEqualTo("10.5.8.1"));
+         
 -        Assert.assertTrue(noc.compare("9", "10") < 0);
 -        Assert.assertTrue(noc.compare("10", "9") > 0);
++        Assert.assertTrue(v_rc2.isLessThanAndNotEqualTo("10.5.8-rc3")) ;
++        Assert.assertTrue(v_rc2.isGreaterThanAndNotEqualTo("10.5.8-rc1"));
+         
 -        Assert.assertTrue(noc.compare("b10", "a9") > 0);
 -        Assert.assertTrue(noc.compare("b9", "a10") > 0);
++        
Assert.assertTrue(v_rc2.isGreaterThanAndNotEqualTo("10.5.8-beta1")==v_rc2.isGreaterThanAndNotEqualTo("10.5.8-beta3"));
+         
 -        Assert.assertTrue(noc.compare(" 9", "10") < 0);
 -        Assert.assertTrue(noc.compare("10", " 9") > 0);
++        Assert.assertTrue(v.isInRange("[10.5,10.6)"));
++        Assert.assertFalse(v.isInRange("[10.5,10.5.8)"));
++        Assert.assertTrue(v.isInRange("[10.5,)"));
++        Assert.assertTrue(v.isInRange("[9,)"));
++        Assert.assertFalse(v.isInRange("(10.5.8,)"));
++        Assert.assertFalse(v.isInRange("[10.6,)"));
++        Assert.assertTrue(v.isInRange("[,11)"));
++        Assert.assertTrue(v.isInRange("[,]"));
+     }
+ 
 -    @Test
 -    public void testVersionNumbers() {
 -        Assert.assertEquals(0, noc.compare("10.5.8", "10.5.8"));
 -        Assert.assertTrue(noc.compare("10.5", "9.9") > 0);
 -        Assert.assertTrue(noc.compare("10.5.1", "10.5") > 0);
 -        Assert.assertTrue(noc.compare("10.5.1", "10.6") < 0);
 -        Assert.assertTrue(noc.compare("10.5.1-1", "10.5.1-0") > 0);
 -    }
++    @Test(expectedExceptions={IllegalArgumentException.class})
++    public void testError1() { v.isInRange("10.5"); }
++    @Test(expectedExceptions={IllegalArgumentException.class})
++    public void testError2() { v.isInRange("[10.5"); }
++    @Test(expectedExceptions={IllegalArgumentException.class})
++    public void testError3() { v.isInRange("[10.5]"); }
+ 
+ }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/NaturalOrderComparatorTest.java
----------------------------------------------------------------------
diff --cc 
brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/NaturalOrderComparatorTest.java
index 0000000,3e99e58..3113c8e
mode 000000,100644..100644
--- 
a/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/NaturalOrderComparatorTest.java
+++ 
b/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/NaturalOrderComparatorTest.java
@@@ -1,0 -1,81 +1,90 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing,
+  * software distributed under the License is distributed on an
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  * KIND, either express or implied.  See the License for the
+  * specific language governing permissions and limitations
+  * under the License.
+  */
+ package org.apache.brooklyn.util.text;
+ 
+ import org.apache.brooklyn.util.text.ComparableVersion;
+ import org.apache.brooklyn.util.text.NaturalOrderComparator;
+ import org.testng.Assert;
+ import org.testng.annotations.Test;
+ 
+ public class NaturalOrderComparatorTest {
+ 
+     public static final NaturalOrderComparator noc = new 
NaturalOrderComparator();
+     
+     ComparableVersion v = new ComparableVersion("10.5.8");
+     ComparableVersion v_rc2 = new ComparableVersion("10.5.8-rc2");
+     
+     @Test
 -    public void testBasicOnes() {
 -        Assert.assertTrue(v.isGreaterThanAndNotEqualTo("10.5"));
 -        Assert.assertTrue(v.isGreaterThanOrEqualTo("10.5.8"));
 -        Assert.assertFalse(v.isGreaterThanAndNotEqualTo("10.5.8"));
 -
 -        Assert.assertTrue(v.isLessThanAndNotEqualTo("10.6"));
 -        Assert.assertTrue(v.isLessThanOrEqualTo("10.5.8"));
 -        Assert.assertFalse(v.isLessThanAndNotEqualTo("10.5.8"));
++    public void testNoc() {
++        Assert.assertEquals(noc.compare("0a", "1"), -1);
++        
++        Assert.assertEquals(noc.compare("0", "1"), -1);
++        Assert.assertEquals(noc.compare("1", "10"), -1);
++        Assert.assertEquals(noc.compare("9", "10"), -1);
++        Assert.assertEquals(noc.compare("a", "b"), -1);
++        Assert.assertEquals(noc.compare("a9", "a10"), -1);
+         
 -        Assert.assertTrue(v.isLessThanAndNotEqualTo("10.5.8.1"));
++        Assert.assertEquals(noc.compare("0.9", "0.91"), -1);
++        Assert.assertEquals(noc.compare("0.90", "0.91"), -1);
++        Assert.assertEquals(noc.compare("1.2.x", "1.09.x"), -1);
++        
++        Assert.assertEquals(noc.compare("0", "1a"), -1);
++        Assert.assertEquals(noc.compare("0a", "1"), -1);
++    }
++    
++    @Test
++    public void testBasicOnes() {
++        Assert.assertEquals(0, noc.compare("a", "a"));
++        Assert.assertTrue(noc.compare("a", "b") < 0);
++        Assert.assertTrue(noc.compare("b", "a") > 0);
+         
 -        Assert.assertTrue(v_rc2.isLessThanAndNotEqualTo("10.5.8-rc3")) ;
 -        Assert.assertTrue(v_rc2.isGreaterThanAndNotEqualTo("10.5.8-rc1"));
++        Assert.assertTrue(noc.compare("9", "10") < 0);
++        Assert.assertTrue(noc.compare("10", "9") > 0);
+         
 -        
Assert.assertTrue(v_rc2.isGreaterThanAndNotEqualTo("10.5.8-beta1")==v_rc2.isGreaterThanAndNotEqualTo("10.5.8-beta3"));
++        Assert.assertTrue(noc.compare("b10", "a9") > 0);
++        Assert.assertTrue(noc.compare("b9", "a10") > 0);
+         
 -        Assert.assertTrue(v.isInRange("[10.5,10.6)"));
 -        Assert.assertFalse(v.isInRange("[10.5,10.5.8)"));
 -        Assert.assertTrue(v.isInRange("[10.5,)"));
 -        Assert.assertTrue(v.isInRange("[9,)"));
 -        Assert.assertFalse(v.isInRange("(10.5.8,)"));
 -        Assert.assertFalse(v.isInRange("[10.6,)"));
 -        Assert.assertTrue(v.isInRange("[,11)"));
 -        Assert.assertTrue(v.isInRange("[,]"));
++        Assert.assertTrue(noc.compare(" 9", "10") < 0);
++        Assert.assertTrue(noc.compare("10", " 9") > 0);
+     }
+ 
 -    @Test(expectedExceptions={IllegalArgumentException.class})
 -    public void testError1() { v.isInRange("10.5"); }
 -    @Test(expectedExceptions={IllegalArgumentException.class})
 -    public void testError2() { v.isInRange("[10.5"); }
 -    @Test(expectedExceptions={IllegalArgumentException.class})
 -    public void testError3() { v.isInRange("[10.5]"); }
++    @Test
++    public void testVersionNumbers() {
++        Assert.assertEquals(0, noc.compare("10.5.8", "10.5.8"));
++        Assert.assertTrue(noc.compare("10.5", "9.9") > 0);
++        Assert.assertTrue(noc.compare("10.5.1", "10.5") > 0);
++        Assert.assertTrue(noc.compare("10.5.1", "10.6") < 0);
++        Assert.assertTrue(noc.compare("10.5.1-1", "10.5.1-0") > 0);
++    }
+ 
+     @Test(groups="WIP", enabled=false)
+     public void testUnderscoreDoesNotChangeMeaningOfNumberInNoc() {
+         // why??
+         Assert.assertTrue(noc.compare("0.0.0_SNAPSHOT", 
"0.0.1-SNAPSHOT-20141111114709760") < 0);
+ 
+         Assert.assertTrue(v.isGreaterThanAndNotEqualTo(v_rc2.version));
+         Assert.assertTrue(v_rc2.isLessThanAndNotEqualTo(v.version));
+     }
+     
+     @Test(groups="WIP", enabled=false)
+     public void testUnderscoreDoesNotChangeMeaningOfNumberInOurWorld() {
+         Assert.assertTrue(new 
ComparableVersion("0.0.0_SNAPSHOT").isLessThanAndNotEqualTo("0.0.1-SNAPSHOT-20141111114709760"));
+     }
+ 
+ }

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/StringsTest.java
----------------------------------------------------------------------
diff --cc 
brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/StringsTest.java
index 0000000,85ba659..a861a10
mode 000000,100644..100644
--- 
a/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/StringsTest.java
+++ 
b/brooklyn-server/utils/common/src/test/java/org/apache/brooklyn/util/text/StringsTest.java
@@@ -1,0 -1,366 +1,362 @@@
+ /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing,
+  * software distributed under the License is distributed on an
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  * KIND, either express or implied.  See the License for the
+  * specific language governing permissions and limitations
+  * under the License.
+  */
+ package org.apache.brooklyn.util.text;
+ 
+ import static org.testng.Assert.assertEquals;
+ import static org.testng.Assert.assertFalse;
+ import static org.testng.Assert.assertTrue;
+ 
+ import java.util.Arrays;
+ 
+ import org.apache.brooklyn.test.FixedLocaleTest;
+ import org.apache.brooklyn.util.collections.MutableMap;
+ import org.apache.brooklyn.util.text.FormattedString;
+ import org.apache.brooklyn.util.text.StringFunctions;
+ import org.apache.brooklyn.util.text.Strings;
+ import org.testng.Assert;
+ import org.testng.annotations.Test;
+ 
+ @Test
+ public class StringsTest extends FixedLocaleTest {
+ 
+     public void isBlankOrEmpty() {
+         assertTrue(Strings.isEmpty(null));
+         assertTrue(Strings.isEmpty(""));
+         assertFalse(Strings.isEmpty("   \t   "));
+         assertFalse(Strings.isEmpty("abc"));
+         assertFalse(Strings.isEmpty("   abc   "));
+ 
+         assertFalse(Strings.isNonEmpty(null));
+         assertFalse(Strings.isNonEmpty(""));
+         assertTrue(Strings.isNonEmpty("   \t   "));
+         assertTrue(Strings.isNonEmpty("abc"));
+         assertTrue(Strings.isNonEmpty("   abc   "));
+ 
+         assertTrue(Strings.isBlank(null));
+         assertTrue(Strings.isBlank(""));
+         assertTrue(Strings.isBlank("   \t   "));
+         assertFalse(Strings.isBlank("abc"));
+         assertFalse(Strings.isBlank("   abc   "));
+ 
+         assertFalse(Strings.isNonBlank(null));
+         assertFalse(Strings.isNonBlank(""));
+         assertFalse(Strings.isNonBlank("   \t   "));
+         assertTrue(Strings.isNonBlank("abc"));
+         assertTrue(Strings.isNonBlank("   abc   "));
+     }
+ 
+     public void testMakeValidFilename() {
+         assertEquals("abcdef", Strings.makeValidFilename("abcdef"));
+         assertEquals("abc_def", Strings.makeValidFilename("abc$$$def"));
+         assertEquals("abc_def", Strings.makeValidFilename("$$$abc$$$def$$$"));
+         assertEquals("a_b_c", Strings.makeValidFilename("a b c"));
+         assertEquals("a.b.c", Strings.makeValidFilename("a.b.c"));
+     }
+     @Test(expectedExceptions = { NullPointerException.class })
+     public void testMakeValidFilenameNull() {
+         Strings.makeValidFilename(null);
+     }
+     @Test(expectedExceptions = { IllegalArgumentException.class })
+     public void testMakeValidFilenameEmpty() {
+         Strings.makeValidFilename("");
+     }
+     @Test(expectedExceptions = { IllegalArgumentException.class })
+     public void testMakeValidFilenameBlank() {
+         Strings.makeValidFilename("    \t    ");
+     }
+ 
+     public void makeValidJavaName() {
+         assertEquals(Strings.makeValidJavaName(null), "__null");
+         assertEquals(Strings.makeValidJavaName(""), "__empty");
+         assertEquals(Strings.makeValidJavaName("abcdef"), "abcdef");
+         assertEquals(Strings.makeValidJavaName("a'b'c'd'e'f"), "abcdef");
+         assertEquals(Strings.makeValidJavaName("12345"), "_12345");
+     }
+ 
+     public void makeValidUniqueJavaName() {
+         assertEquals(Strings.makeValidUniqueJavaName(null), "__null");
+         assertEquals(Strings.makeValidUniqueJavaName(""), "__empty");
+         assertEquals(Strings.makeValidUniqueJavaName("abcdef"), "abcdef");
+         assertEquals(Strings.makeValidUniqueJavaName("12345"), "_12345");
+     }
+ 
+     public void testRemoveFromEnd() {
+         assertEquals(Strings.removeFromEnd("", "bar"), "");
+         assertEquals(Strings.removeFromEnd(null, "bar"), null);
+ 
+         assertEquals(Strings.removeFromEnd("foobar", "bar"), "foo");
+         assertEquals(Strings.removeFromEnd("foo", "bar"), "foo");
 -        assertEquals(Strings.removeFromEnd("foobar", "foo", "bar"), "foo");
+         // test they are applied in order
 -        assertEquals(Strings.removeFromEnd("foobar", "ar", "bar", "b"), 
"foob");
+     }
+ 
+     public void testRemoveAllFromEnd() {
+         assertEquals(Strings.removeAllFromEnd("", "bar"), "");
+         assertEquals(Strings.removeAllFromEnd(null, "bar"), null);
+         assertEquals(Strings.removeAllFromEnd("foo", ""), "foo");
+ 
+         assertEquals(Strings.removeAllFromEnd("foobar", "foo", "bar"), "");
+         assertEquals(Strings.removeAllFromEnd("foobar", "ar", "car", "b", 
"o"), "f");
+         // test they are applied in order
+         assertEquals(Strings.removeAllFromEnd("foobar", "ar", "car", "b", 
"ob"), "foo");
+         assertEquals(Strings.removeAllFromEnd("foobar", "zz", "x"), "foobar");
+         assertEquals(Strings.removeAllFromEnd("foobarbaz", "bar", "baz"), 
"foo");
+         assertEquals(Strings.removeAllFromEnd("foobarbaz", "baz", "", "foo", 
"bar", "baz"), "");
+     }
+ 
+     public void testRemoveFromStart() {
+         assertEquals(Strings.removeFromStart("", "foo"), "");
+         assertEquals(Strings.removeFromStart(null, "foo"), null);
+ 
+         assertEquals(Strings.removeFromStart("foobar", "foo"), "bar");
+         assertEquals(Strings.removeFromStart("foo", "bar"), "foo");
 -        assertEquals(Strings.removeFromStart("foobar", "foo", "bar"), "bar");
 -        assertEquals(Strings.removeFromStart("foobar", "ob", "fo", "foo", 
"o"), "obar");
+     }
+ 
+     public void testRemoveAllFromStart() {
+         assertEquals(Strings.removeAllFromStart("", "foo"), "");
+         assertEquals(Strings.removeAllFromStart(null, "foo"), null);
+         assertEquals(Strings.removeAllFromStart("foo", ""), "foo");
+ 
+         assertEquals(Strings.removeAllFromStart("foobar", "foo"), "bar");
+         assertEquals(Strings.removeAllFromStart("foo", "bar"), "foo");
+         assertEquals(Strings.removeAllFromStart("foobar", "foo", "bar"), "");
+ 
+         assertEquals(Strings.removeAllFromStart("foobar", "fo", "ob", "o"), 
"ar");
+         assertEquals(Strings.removeAllFromStart("foobar", "ob", "fo", "o"), 
"ar");
+         // test they are applied in order, "ob" doesn't match because "o" 
eats the o
+         assertEquals(Strings.removeAllFromStart("foobar", "o", "fo", "ob"), 
"bar");
+         assertEquals(Strings.removeAllFromStart("foobarbaz", "bar", "foo"), 
"baz");
+         assertEquals(Strings.removeAllFromStart("foobarbaz", "baz", "bar", 
"foo"), "");
+     }
+ 
+     public void testRemoveFromStart2() {
+         assertEquals(Strings.removeFromStart("xyz", "x"), "yz");
+         assertEquals(Strings.removeFromStart("xyz", "."), "xyz");
+         assertEquals(Strings.removeFromStart("http://foo.com";, "http://";), 
"foo.com");
+     }
+ 
+     public void testRemoveFromEnd2() {
+         assertEquals(Strings.removeFromEnd("xyz", "z"), "xy");
+         assertEquals(Strings.removeFromEnd("xyz", "."), "xyz");
+         assertEquals(Strings.removeFromEnd("http://foo.com/";, "/"), 
"http://foo.com";);
+     }
+ 
+     public void testReplaceAll() {
+         assertEquals(Strings.replaceAll("xyz", "x", ""), "yz");
+         assertEquals(Strings.replaceAll("xyz", ".", ""), "xyz");
+         assertEquals(Strings.replaceAll("http://foo.com/";, "/", ""), 
"http:foo.com");
+         assertEquals(Strings.replaceAll("http://foo.com/";, "http:", 
"https:"), "https://foo.com/";);
+     }
+ 
+     public void testReplaceAllNonRegex() {
+         assertEquals(Strings.replaceAllNonRegex("xyz", "x", ""), "yz");
+         assertEquals(Strings.replaceAllNonRegex("xyz", ".", ""), "xyz");
+         assertEquals(Strings.replaceAllNonRegex("http://foo.com/";, "/", ""), 
"http:foo.com");
+         assertEquals(Strings.replaceAllNonRegex("http://foo.com/";, "http:", 
"https:"), "https://foo.com/";);
+     }
+ 
+     public void testReplaceAllRegex() {
+         assertEquals(Strings.replaceAllRegex("xyz", "x", ""), "yz");
+         assertEquals(Strings.replaceAllRegex("xyz", ".", ""), "");
+         assertEquals(Strings.replaceAllRegex("http://foo.com/";, "/", ""), 
"http:foo.com");
+         assertEquals(Strings.replaceAllRegex("http://foo.com/";, "http:", 
"https:"), "https://foo.com/";);
+     }
+ 
+     public void testReplaceMap() {
+         assertEquals(Strings.replaceAll("xyz", 
MutableMap.builder().put("x","a").put("y","").build()), "az");
+     }
+ 
+     public void testContainsLiteral() {
+         assertTrue(Strings.containsLiteral("hello", "ell"));
+         assertTrue(Strings.containsLiteral("hello", "h"));
+         assertFalse(Strings.containsLiteral("hello", "H"));
+         assertFalse(Strings.containsLiteral("hello", "O"));
+         assertFalse(Strings.containsLiteral("hello", "x"));
+         assertFalse(Strings.containsLiteral("hello", "ELL"));
+         assertTrue(Strings.containsLiteral("hello", "hello"));
+         assertTrue(Strings.containsLiteral("hELlo", "ELl"));
+         assertFalse(Strings.containsLiteral("hello", "!"));
+     }
+ 
+     public void testContainsLiteralIgnoreCase() {
+         assertTrue(Strings.containsLiteralIgnoreCase("hello", "ell"));
+         assertTrue(Strings.containsLiteralIgnoreCase("hello", "H"));
+         assertTrue(Strings.containsLiteralIgnoreCase("hello", "O"));
+         assertFalse(Strings.containsLiteralIgnoreCase("hello", "X"));
+         assertTrue(Strings.containsLiteralIgnoreCase("hello", "ELL"));
+         assertTrue(Strings.containsLiteralIgnoreCase("hello", "hello"));
+         assertTrue(Strings.containsLiteralIgnoreCase("hELlo", "Hello"));
+         assertFalse(Strings.containsLiteralIgnoreCase("hello", "!"));
+     }
+ 
+     @Test
+     public void testDeferredFormat() {
+         ToStringCounter c = new ToStringCounter();
+         FormattedString x = Strings.format("hello %s", c);
+         Assert.assertEquals(c.count, 0);
+         Assert.assertEquals(x.toString(), "hello world");
+         Assert.assertEquals(c.count, 1);
+     }
+ 
+     @Test
+     public void testToStringSupplier() {
+         ToStringCounter c = new ToStringCounter(true);
+         Assert.assertEquals(Strings.toStringSupplier(c).get(), "world1");
+         FormattedString x = Strings.format("hello %s", c);
+         Assert.assertEquals(x.toString(), "hello world2");
+         Assert.assertEquals(x.toString(), "hello world3");
+     }
+ 
+     private static class ToStringCounter {
+         private int count = 0;
+         private boolean appendCount = false;
+         private ToStringCounter() {}
+         private ToStringCounter(boolean append) { this.appendCount = append; }
+         @Override
+         public String toString() {
+             count++;
+             return "world"+(appendCount?""+count:"");
+         }
+     }
+ 
+     @Test
+     public void testFormatter() {
+         Assert.assertEquals(StringFunctions.formatter("hello 
%s").apply("world"), "hello world");
+         Assert.assertEquals(StringFunctions.formatterForArray("%s 
%s").apply(new String[] { "hello", "world" }), "hello world");
+     }
+ 
+     @Test
+     public void testJoiner() {
+         Assert.assertEquals(StringFunctions.joiner(" 
").apply(Arrays.asList("hello", "world")), "hello world");
+         Assert.assertEquals(StringFunctions.joinerForArray(" ").apply(new 
String[] { "hello", "world" }), "hello world");
+     }
+ 
+     @Test
+     public void testSurround() {
+         Assert.assertEquals(StringFunctions.surround("hello ", " 
world").apply("new"), "hello new world");
+     }
+ 
+     @Test
+     public void testFirstWord() {
+         Assert.assertEquals(Strings.getFirstWord("hello world"), "hello");
+         Assert.assertEquals(Strings.getFirstWord("   hello world"), "hello");
+         Assert.assertEquals(Strings.getFirstWord("   hello   "), "hello");
+         Assert.assertEquals(Strings.getFirstWord("hello"), "hello");
+         Assert.assertEquals(Strings.getFirstWord("  "), null);
+         Assert.assertEquals(Strings.getFirstWord(""), null);
+         Assert.assertEquals(Strings.getFirstWord(null), null);
+     }
+ 
+     @Test
+     public void testLastWord() {
+         Assert.assertEquals(Strings.getLastWord("hello world"), "world");
+         Assert.assertEquals(Strings.getLastWord("   hello world  "), "world");
+         Assert.assertEquals(Strings.getLastWord("   hello   "), "hello");
+         Assert.assertEquals(Strings.getLastWord("hello"), "hello");
+         Assert.assertEquals(Strings.getLastWord("  "), null);
+         Assert.assertEquals(Strings.getLastWord(""), null);
+         Assert.assertEquals(Strings.getLastWord(null), null);
+     }
+ 
+     @Test
+     public void testFirstWordAfter() {
+         Assert.assertEquals(Strings.getFirstWordAfter("hello world", 
"hello"), "world");
+         Assert.assertEquals(Strings.getFirstWordAfter("   hello world", 
"hello"), "world");
+         Assert.assertEquals(Strings.getFirstWordAfter("   hello world: is not 
enough", "world:"), "is");
+         Assert.assertEquals(Strings.getFirstWordAfter("   hello world: is not 
enough", "world"), ":");
+         Assert.assertEquals(Strings.getFirstWordAfter("   hello   ", 
"hello"), null);
+         Assert.assertEquals(Strings.getFirstWordAfter("hello", "hello"), 
null);
+         Assert.assertEquals(Strings.getFirstWordAfter("  ", "x"), null);
+         Assert.assertEquals(Strings.getFirstWordAfter("", "x"), null);
+         Assert.assertEquals(Strings.getFirstWordAfter(null, "x"), null);
+     }
+ 
+     @Test
+     public void testFragmentBetween() {
+         Assert.assertEquals("ooba", Strings.getFragmentBetween("foobar", "f", 
"r"));
+         Assert.assertEquals("oobar", Strings.getFragmentBetween("foobar", 
"f", "z"));
+         Assert.assertEquals("oobar", Strings.getFragmentBetween("foobar", 
"f", null));
+         Assert.assertEquals("oba", Strings.getFragmentBetween("foobar", "o", 
"r"));
+         Assert.assertEquals("\nba", Strings.getFragmentBetween("foo\nbar", 
"foo", "r"));
+         Assert.assertEquals("fooba", Strings.getFragmentBetween("foobar", 
null, "r"));
+         Assert.assertEquals(null, Strings.getFragmentBetween("foobar", "z", 
"r"));
+     }
+ 
+     @Test
+     public void testWordCount() {
+         Assert.assertEquals(Strings.getWordCount("hello", true), 1);
+         Assert.assertEquals(Strings.getWordCount("hello world", true), 2);
+         Assert.assertEquals(Strings.getWordCount("hello\nworld", true), 2);
+         Assert.assertEquals(Strings.getWordCount("hello world \nit is me!\n", 
true), 5);
+         Assert.assertEquals(Strings.getWordCount("", true), 0);
+         Assert.assertEquals(Strings.getWordCount(null, true), 0);
+         Assert.assertEquals(Strings.getWordCount("\"hello world\" ", true), 
1);
+         Assert.assertEquals(Strings.getWordCount("\"hello world\" ", false), 
2);
+         Assert.assertEquals(Strings.getWordCount("hello world \nit's me!\n", 
true), 3);
+         Assert.assertEquals(Strings.getWordCount("hello world \nit's me!\n", 
false), 4);
+     }
+ 
+     @Test
+     public void testMakeRealString() {
+         // less precision = less length
+         Assert.assertEquals(Strings.makeRealString(1.23456d, 4, 2, 0), "1.2");
+         // precision trumps length, and rounds
+         Assert.assertEquals(Strings.makeRealString(1.23456d, 4, 5, 0), 
"1.2346");
+         // uses E notation when needed
+         Assert.assertEquals(Strings.makeRealString(123456, 2, 2, 0), "1.2E5");
+         // and works with negatives
+         Assert.assertEquals(Strings.makeRealString(-123456, 2, 2, 0), 
"-1.2E5");
+         // and very small negatives
+         Assert.assertEquals(Strings.makeRealString(-0.000000000123456, 2, 2, 
0), "-1.2E-10");
+         // and 0
+         Assert.assertEquals(Strings.makeRealString(0.0d, 4, 2, 0), "0");
+         // skips E notation and gives extra precision when it's free
+         Assert.assertEquals(Strings.makeRealString(123456, 8, 2, 0), 
"123456");
+     }
+ 
+     @Test
+     public void testCollapseWhitespace() {
+         Assert.assertEquals(Strings.collapseWhitespace(" x\n y\n", ""), "xy");
+         Assert.assertEquals(Strings.collapseWhitespace(" x\n y\n", " "), " x 
y ");
+         Assert.assertEquals(Strings.collapseWhitespace(" x\n y\n", 
"\n").trim(), "x\ny");
+     }
+     
+     @Test
+     public void testMaxlen() {
+         Assert.assertEquals(Strings.maxlen("hello world", 5), "hello");
+         Assert.assertEquals(Strings.maxlenWithEllipsis("hello world", 9), 
"hello ...");
+         Assert.assertEquals(Strings.maxlenWithEllipsis("hello world", 7, 
"--"), "hello--");
+     }
+ 
+     @Test
+     public void testGetRemainderOfLineAfter() {
+         // Basic test (also tests start is trimmed)
+         Assert.assertEquals(Strings.getRemainderOfLineAfter("the message is 
hello", "is"), " hello");
+         Assert.assertEquals(Strings.getRemainderOfLineAfter("the message is 
is hello", "is"), " is hello");
+         // Trim spaces from end
+         Assert.assertEquals(Strings.getRemainderOfLineAfter("the message is 
is hello    ", "is"), " is hello    ");
+         // Trim non-matching lines from start
+         
Assert.assertEquals(Strings.getRemainderOfLineAfter("one\ntwo\nthree\nthe 
message is is hello    ", "is"), " is hello    ");
+         // Trim lines from end
+         
Assert.assertEquals(Strings.getRemainderOfLineAfter("one\ntwo\nthree\nthe 
message is is hello    \nfour\nfive\nsix\nis not seven", "is"), " is hello    
");
+         // Play nicely with null / non-match
+         Assert.assertEquals(Strings.getRemainderOfLineAfter(null, "is"), 
null);
+         Assert.assertEquals(Strings.getRemainderOfLineAfter("the message is 
hello", null), null);
+         Assert.assertEquals(Strings.getRemainderOfLineAfter("the message is 
hello", "foo"), null);
+     }
+ }

Reply via email to