http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/StringPredicates.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/StringPredicates.java b/utils/common/src/main/java/brooklyn/util/text/StringPredicates.java deleted file mode 100644 index f83b139..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/StringPredicates.java +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 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 brooklyn.util.text; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.List; -import java.util.Set; - -import javax.annotation.Nullable; - -import brooklyn.util.collections.MutableSet; - -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; - -public class StringPredicates { - - /** predicate form of {@link Strings#isBlank(CharSequence)} */ - public static <T extends CharSequence> Predicate<T> isBlank() { - return new IsBlank<T>(); - } - - private static final class IsBlank<T extends CharSequence> implements Predicate<T> { - @Override - public boolean apply(@Nullable CharSequence input) { - return Strings.isBlank(input); - } - - @Override - public String toString() { - return "isBlank()"; - } - } - - /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */ - @SuppressWarnings("unused") @Deprecated - private static Predicate<CharSequence> isBlankOld() { - return new Predicate<CharSequence>() { - @Override - public boolean apply(@Nullable CharSequence input) { - return Strings.isBlank(input); - } - @Override - public String toString() { - return "isBlank"; - } - }; - } - - - /** Tests if object is non-null and not a blank string. - * <p> - * Predicate form of {@link Strings#isNonBlank(CharSequence)} also accepting objects non-null, for convenience */ - public static <T> Predicate<T> isNonBlank() { - return new IsNonBlank<T>(); - } - - private static final class IsNonBlank<T> implements Predicate<T> { - @Override - public boolean apply(@Nullable Object input) { - if (input==null) return false; - if (!(input instanceof CharSequence)) return true; - return Strings.isNonBlank((CharSequence)input); - } - - @Override - public String toString() { - return "isNonBlank()"; - } - } - - // ----------------- - - public static <T extends CharSequence> Predicate<T> containsLiteralIgnoreCase(final String fragment) { - return new ContainsLiteralIgnoreCase<T>(fragment); - } - - private static final class ContainsLiteralIgnoreCase<T extends CharSequence> implements Predicate<T> { - private final String fragment; - - private ContainsLiteralIgnoreCase(String fragment) { - this.fragment = fragment; - } - - @Override - public boolean apply(@Nullable CharSequence input) { - return Strings.containsLiteralIgnoreCase(input, fragment); - } - - @Override - public String toString() { - return "containsLiteralCaseInsensitive("+fragment+")"; - } - } - - public static <T extends CharSequence> Predicate<T> containsLiteral(final String fragment) { - return new ContainsLiteral<T>(fragment); - } - - private static final class ContainsLiteral<T extends CharSequence> implements Predicate<T> { - private final String fragment; - - private ContainsLiteral(String fragment) { - this.fragment = fragment; - } - - @Override - public boolean apply(@Nullable CharSequence input) { - return Strings.containsLiteral(input, fragment); - } - - @Override - public String toString() { - return "containsLiteral("+fragment+")"; - } - } - - /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */ - @SuppressWarnings("unused") @Deprecated - private static Predicate<CharSequence> containsLiteralCaseInsensitiveOld(final String fragment) { - return new Predicate<CharSequence>() { - @Override - public boolean apply(@Nullable CharSequence input) { - return Strings.containsLiteralIgnoreCase(input, fragment); - } - @Override - public String toString() { - return "containsLiteralCaseInsensitive("+fragment+")"; - } - }; - } - - /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */ - @SuppressWarnings("unused") @Deprecated - private static Predicate<CharSequence> containsLiteralOld(final String fragment) { - return new Predicate<CharSequence>() { - @Override - public boolean apply(@Nullable CharSequence input) { - return Strings.containsLiteral(input, fragment); - } - @Override - public String toString() { - return "containsLiteral("+fragment+")"; - } - }; - } - - // ----------------- - - public static <T extends CharSequence> Predicate<T> containsAllLiterals(final String... fragments) { - List<Predicate<CharSequence>> fragmentPredicates = Lists.newArrayList(); - for (String fragment : fragments) { - fragmentPredicates.add(containsLiteral(fragment)); - } - return Predicates.and(fragmentPredicates); - } - - /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */ - @SuppressWarnings("unused") @Deprecated - private static Predicate<CharSequence> containsAllLiteralsOld(final String... fragments) { - return Predicates.and(Iterables.transform(Arrays.asList(fragments), new Function<String,Predicate<CharSequence>>() { - @Override - public Predicate<CharSequence> apply(String input) { - return containsLiteral(input); - } - })); - } - - // ----------------- - - public static Predicate<CharSequence> containsRegex(final String regex) { - // "Pattern" ... what a bad name :) - return Predicates.containsPattern(regex); - } - - // ----------------- - - public static <T extends CharSequence> Predicate<T> startsWith(final String prefix) { - return new StartsWith<T>(prefix); - } - - private static final class StartsWith<T extends CharSequence> implements Predicate<T> { - private final String prefix; - private StartsWith(String prefix) { - this.prefix = prefix; - } - @Override - public boolean apply(CharSequence input) { - return (input != null) && input.toString().startsWith(prefix); - } - @Override - public String toString() { - return "startsWith("+prefix+")"; - } - } - - /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */ - @SuppressWarnings("unused") @Deprecated - private static Predicate<CharSequence> startsWithOld(final String prefix) { - return new Predicate<CharSequence>() { - @Override - public boolean apply(CharSequence input) { - return (input != null) && input.toString().startsWith(prefix); - } - }; - } - - // ----------------- - - /** true if the object *is* a {@link CharSequence} starting with the given prefix */ - public static Predicate<Object> isStringStartingWith(final String prefix) { - return Predicates.<Object>and(Predicates.instanceOf(CharSequence.class), - Predicates.compose(startsWith(prefix), StringFunctions.toStringFunction())); - } - - /** @deprecated since 0.7.0 kept only to allow conversion of anonymous inner classes */ - @SuppressWarnings("unused") @Deprecated - private static Predicate<Object> isStringStartingWithOld(final String prefix) { - return new Predicate<Object>() { - @Override - public boolean apply(Object input) { - return (input instanceof CharSequence) && input.toString().startsWith(prefix); - } - }; - } - - // --------------- - - public static <T> Predicate<T> equalToAny(Iterable<T> vals) { - return new EqualToAny<T>(vals); - } - - private static class EqualToAny<T> implements Predicate<T>, Serializable { - private static final long serialVersionUID = 6209304291945204422L; - private final Set<T> vals; - - public EqualToAny(Iterable<? extends T> vals) { - this.vals = MutableSet.copyOf(vals); // so allows nulls - } - @Override - public boolean apply(T input) { - return vals.contains(input); - } - @Override - public String toString() { - return "equalToAny("+vals+")"; - } - } - - // ----------- - - public static <T extends CharSequence> Predicate<T> matchesRegex(final String regex) { - return new MatchesRegex<T>(regex); - } - - protected static class MatchesRegex<T extends CharSequence> implements Predicate<T> { - protected final String regex; - protected MatchesRegex(String regex) { - this.regex = regex; - } - @Override - public boolean apply(CharSequence input) { - return (input != null) && input.toString().matches(regex); - } - @Override - public String toString() { - return "matchesRegex("+regex+")"; - } - } - - public static <T extends CharSequence> Predicate<T> matchesGlob(final String glob) { - return new MatchesGlob<T>(glob); - } - - protected static class MatchesGlob<T extends CharSequence> implements Predicate<T> { - protected final String glob; - protected MatchesGlob(String glob) { - this.glob = glob; - } - @Override - public boolean apply(CharSequence input) { - return (input != null) && WildcardGlobs.isGlobMatched(glob, input.toString()); - } - @Override - public String toString() { - return "matchesGlob("+glob+")"; - } - } - -}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/StringShortener.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/StringShortener.java b/utils/common/src/main/java/brooklyn/util/text/StringShortener.java deleted file mode 100644 index 816007a..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/StringShortener.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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 brooklyn.util.text; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** utility which takes a bunch of segments and applies shortening rules to them */ -public class StringShortener { - - protected Map<String,String> wordsByIdInOrder = new LinkedHashMap<String,String>(); - protected String separator = null; - - protected interface ShorteningRule { - /** returns the new list, with the relevant items in the list replaced */ - public int apply(LinkedHashMap<String, String> words, int maxlen, int length); - } - - protected class TruncationRule implements ShorteningRule { - public TruncationRule(String id, int len) { - this.id = id; - this.len = len; - } - String id; - int len; - - public int apply(LinkedHashMap<String, String> words, int maxlen, int length) { - String v = words.get(id); - if (v!=null && v.length()>len) { - int charsToRemove = v.length() - len; - if (length-charsToRemove < maxlen) charsToRemove = length-maxlen; - words.put(id, v.substring(0, v.length() - charsToRemove)); - length -= charsToRemove; - if (charsToRemove==v.length() && separator!=null && length>0) - length -= separator.length(); - } - return length; - } - } - - protected class RemovalRule implements ShorteningRule { - public RemovalRule(String id) { - this.id = id; - } - String id; - - public int apply(LinkedHashMap<String, String> words, int maxlen, int length) { - String v = words.get(id); - if (v!=null) { - words.remove(id); - length -= v.length(); - if (separator!=null && length>0) - length -= separator.length(); - } - return length; - } - } - - private List<ShorteningRule> rules = new ArrayList<StringShortener.ShorteningRule>(); - - - public StringShortener separator(String separator) { - this.separator = separator; - return this; - } - - public StringShortener append(String id, String text) { - String old = wordsByIdInOrder.put(id, text); - if (old!=null) { - throw new IllegalStateException("Cannot append with id '"+id+"' when id already present"); - } - // TODO expose a replace or update - return this; - } - - public StringShortener truncate(String id, int len) { - String v = wordsByIdInOrder.get(id); - if (v!=null && v.length()>len) { - wordsByIdInOrder.put(id, v.substring(0, len)); - } - return this; - } - - public StringShortener canTruncate(String id, int len) { - rules.add(new TruncationRule(id, len)); - return this; - } - - public StringShortener canRemove(String id) { - rules.add(new RemovalRule(id)); - return this; - } - - public String getStringOfMaxLength(int maxlen) { - LinkedHashMap<String, String> words = new LinkedHashMap<String,String>(); - words.putAll(wordsByIdInOrder); - int length = 0; - for (String w: words.values()) { - if (!Strings.isBlank(w)) { - length += w.length(); - if (separator!=null) - length += separator.length(); - } - } - if (separator!=null && length>0) - // remove trailing separator if one had been added - length -= separator.length(); - - List<ShorteningRule> rulesLeft = new ArrayList<ShorteningRule>(); - rulesLeft.addAll(rules); - - while (length > maxlen && !rulesLeft.isEmpty()) { - ShorteningRule r = rulesLeft.remove(0); - length = r.apply(words, maxlen, length); - } - - StringBuilder sb = new StringBuilder(); - for (String w: words.values()) { - if (!Strings.isBlank(w)) { - if (separator!=null && sb.length()>0) - sb.append(separator); - sb.append(w); - } - } - - String result = sb.toString(); - if (result.length() > maxlen) result = result.substring(0, maxlen); - - return result; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/Strings.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/Strings.java b/utils/common/src/main/java/brooklyn/util/text/Strings.java deleted file mode 100644 index 5aa2089..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/Strings.java +++ /dev/null @@ -1,945 +0,0 @@ -/* - * 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 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 brooklyn.util.collections.MutableList; -import brooklyn.util.collections.MutableMap; -import brooklyn.util.guava.Maybe; -import 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 reabaility, 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/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/WildcardGlobs.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/WildcardGlobs.java b/utils/common/src/main/java/brooklyn/util/text/WildcardGlobs.java deleted file mode 100644 index e26848b..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/WildcardGlobs.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * 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 brooklyn.util.text; - -import java.util.ArrayList; -import java.util.List; - -import com.google.common.base.Throwables; - -public class WildcardGlobs { - - /** returns true iff the target matches the given pattern, - * under simplified bash rules -- viz permitting * and ? and comma delimited patterns inside curly braces - * @throws InvalidPatternException */ - public static boolean isGlobMatched(String globPattern, String targetText) throws InvalidPatternException { - List<String> patterns = getGlobsAfterBraceExpansion(globPattern); - for (String p : patterns) { - if (isNoBraceGlobMatched(p, targetText)) - return true; - } - return false; - } - - /** whether a glob-ish string without braces (e.g. containing just ? and * chars) matches; - * can be used directly, also used implicitly by isGlobMatched after glob expansion */ - public static boolean isNoBraceGlobMatched(String globPattern, String target) { - int pi=0, ti=0; - while (pi<globPattern.length() && ti<target.length()) { - char pc = globPattern.charAt(pi); - char tc = target.charAt(pi); - if (pc=='?') { - pi++; ti++; - continue; - } - if (pc!='*') { - if (pc!=tc) return false; - pi++; ti++; - continue; - } - //match 0 or more chars - String prest = globPattern.substring(pi+1); - while (ti<=target.length()) { - if (isNoBraceGlobMatched(prest, target.substring(ti))) - return true; - ti++; - } - return false; - } - while (pi<globPattern.length() && globPattern.charAt(pi)=='*') - pi++; - return (pi==globPattern.length() && ti==target.length()); - } - - /** returns a list with no curly braces in any entries, - * and guaranteeing order such that any {..,X,..,Y,..} will result in X being before Y in the resulting list; - * e.g. given a{,b,c} gives a ab and ac; no special treatment of numeric ranges, quotes, or parentheses - * (see SpecialistGlobExpander for that) */ - public static List<String> getGlobsAfterBraceExpansion(String pattern) throws InvalidPatternException { - return getGlobsAfterBraceExpansion(pattern, false, PhraseTreatment.NOT_A_SPECIAL_CHAR, PhraseTreatment.NOT_A_SPECIAL_CHAR); - } - - /** if a string contains a demarcated phrase, e.g. between open and close parentheses, or inside unescaped quotes - * this argument determines how that phrase is treated with regards to brace expansion */ - public enum PhraseTreatment { - /** the region is treated like any other region */ - NOT_A_SPECIAL_CHAR, - /** the interior will be expanded if there is a {x,y} expression _entirely_ inside the phrase, but otherwise commas inside it will be ignored; - * it will be an error if there is a { char inside the phrase, or if the phrase is not internally well-formed with regards to the phrase characters, - * (e.g. if quotes are interior expandable and parens are anything but not_a_special_char (e.g. interior expandable or interior not expandable) - * then any expression inside a quoted phrase must have matching parentheses) */ - INTERIOR_EXPANDABLE, - /** the interior will not be expanded at all, not if there's a comma inside, and not even if there is a {x,y} expression entirely inside; the braces will be left; - * interior of parenthetical phrases must have matching parentheses (to determine the right end parenthesis), - * apart from parentheses inside any quoted phrases when quotes are interior_not_expandable which will be ignored; - * quotes inside not_expandable paren phrases will be ignored */ - INTERIOR_NOT_EXPANDABLE - }; - - protected static class ExpressionToExpand { - String resultSoFar; - String todo; - String operatorStack; - public ExpressionToExpand(String resultSoFar, String todo, String operatorStack) { - super(); - this.resultSoFar = resultSoFar; - this.todo = todo; - this.operatorStack = operatorStack; - } - @Override - public String toString() { - return "ExpressionToExpand["+todo+":"+resultSoFar+"/"+operatorStack+"]"; - } - } - /** returns a list with no curly braces in any entries; e.g. given a{,b} gives a and ab; - * quotes and parentheses are kept, but their contents may be excluded from expansion or otherwise treated specially as per the flag. - * with allowNumericRanges, "{1-3}" is permitted for {1,2,3}. */ - public static List<String> getGlobsAfterBraceExpansion(String pattern, boolean allowNumericRanges, PhraseTreatment quoteTreatment, PhraseTreatment parenthesesTreatment) throws InvalidPatternException { - List<ExpressionToExpand> patterns = new ArrayList<ExpressionToExpand>(); - List<String> result = new ArrayList<String>(); - patterns.add(new ExpressionToExpand("", pattern, "")); - while (!patterns.isEmpty()) { - ExpressionToExpand cs = patterns.remove(0); - StringBuffer resultSoFar = new StringBuffer(cs.resultSoFar); - String operatorStack = cs.operatorStack; - boolean inQuote = operatorStack.contains("\""); - boolean expanded = false; - for (int i=0; i<cs.todo.length(); i++) { - assert !expanded; - char c = cs.todo.charAt(i); - boolean inParen = operatorStack.contains("(") && - (!inQuote || operatorStack.lastIndexOf('\"')<operatorStack.lastIndexOf('(')); - if (inQuote && !(inParen && parenthesesTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE))) { - if (c=='"') { - if (i>0 && cs.todo.charAt(i-1)=='\\') { - //this escaped quote, keep - resultSoFar.append(c); - continue; - } - //unquote - resultSoFar.append(c); - inQuote = false; - if (operatorStack.charAt(operatorStack.length()-1)!='\"') - throw new InvalidPatternException("Quoted string contents not valid, after parsing "+resultSoFar); - operatorStack = operatorStack.substring(0, operatorStack.length()-1); - continue; - } - if (quoteTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE)) { - resultSoFar.append(c); - continue; - } - //interior is expandable, continue parsing as usual below - } - if (inParen) { - if (c==')') { - //unparen - resultSoFar.append(c); - if (operatorStack.charAt(operatorStack.length()-1)!='(') - throw new InvalidPatternException("Parenthetical contents not valid, after parsing "+resultSoFar); - operatorStack = operatorStack.substring(0, operatorStack.length()-1); - continue; - } - if (parenthesesTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE)) { - resultSoFar.append(c); - if (c=='(') - operatorStack+="("; - continue; - } - //interior is expandable, continue parsing as usual below - } - - if (c=='"' && !quoteTreatment.equals(PhraseTreatment.NOT_A_SPECIAL_CHAR)) { - resultSoFar.append(c); - inQuote = true; - operatorStack += "\""; - continue; - } - if (c=='(' && !parenthesesTreatment.equals(PhraseTreatment.NOT_A_SPECIAL_CHAR)) { - resultSoFar.append(c); - operatorStack += "("; - continue; - } - - if (c!='{') { - resultSoFar.append(c); - continue; - } - - //brace.. we will need to expand - expanded = true; - String operatorStackBeforeExpansion = operatorStack; - int braceStartIndex = i; - int tokenStartIndex = i+1; - - //find matching close brace - List<String> tokens = new ArrayList<String>(); - operatorStack += "{"; - while (true) { - if (++i>=cs.todo.length()) { - throw new InvalidPatternException("Curly brace not closed, parsing '"+cs.todo.substring(braceStartIndex)+"' after "+resultSoFar); - } - c = cs.todo.charAt(i); - inParen = operatorStack.contains("(") && - (!inQuote || operatorStack.lastIndexOf('\"')<operatorStack.lastIndexOf('(')); - if (inQuote && !(inParen && parenthesesTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE))) { - if (c=='"') { - if (i>0 && cs.todo.charAt(i-1)=='\\') { - //this is escaped quote, doesn't affect status - continue; - } - //unquote - inQuote = false; - if (operatorStack.charAt(operatorStack.length()-1)!='\"') - throw new InvalidPatternException("Quoted string contents not valid, after parsing "+resultSoFar+cs.todo.substring(braceStartIndex, i)); - operatorStack = operatorStack.substring(0, operatorStack.length()-1); - continue; - } - if (quoteTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE)) { - continue; - } - //interior is expandable, continue parsing as usual below - } - if (inParen) { - if (c==')') { - //unparen - if (operatorStack.charAt(operatorStack.length()-1)!='(') - throw new InvalidPatternException("Parenthetical contents not valid, after parsing "+resultSoFar+cs.todo.substring(braceStartIndex, i)); - operatorStack = operatorStack.substring(0, operatorStack.length()-1); - continue; - } - if (parenthesesTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE)) { - if (c=='(') - operatorStack+="("; - continue; - } - //interior is expandable, continue parsing as usual below - } - - if (c=='"' && !quoteTreatment.equals(PhraseTreatment.NOT_A_SPECIAL_CHAR)) { - inQuote = true; - operatorStack += "\""; - continue; - } - if (c=='(' && !parenthesesTreatment.equals(PhraseTreatment.NOT_A_SPECIAL_CHAR)) { - operatorStack += "("; - continue; - } - - if (c=='}') { - if (operatorStack.charAt(operatorStack.length()-1)!='{') - throw new InvalidPatternException("Brace contents not valid, mismatched operators "+operatorStack+" after parsing "+resultSoFar+cs.todo.substring(braceStartIndex, i)); - operatorStack = operatorStack.substring(0, operatorStack.length()-1); - if (operatorStack.equals(operatorStackBeforeExpansion)) { - tokens.add(cs.todo.substring(tokenStartIndex, i)); - break; - } - continue; - } - - if (c==',') { - if (operatorStack.length()==operatorStackBeforeExpansion.length()+1) { - tokens.add(cs.todo.substring(tokenStartIndex, i)); - tokenStartIndex = i+1; - continue; - } - continue; - } - - if (c=='{') { - operatorStack += c; - continue; - } - - //any other char is irrelevant - continue; - } - - assert operatorStack.equals(operatorStackBeforeExpansion); - assert cs.todo.charAt(i)=='}'; - assert !tokens.isEmpty(); - - String suffix = cs.todo.substring(i+1); - - List<ExpressionToExpand> newPatterns = new ArrayList<ExpressionToExpand>(); - for (String token : tokens) { - //System.out.println("adding: "+pre+token+post); - if (allowNumericRanges && token.matches("\\s*[0-9]+\\s*-\\s*[0-9]+\\s*")) { - int dashIndex = token.indexOf('-'); - String startS = token.substring(0, dashIndex).trim(); - String endS = token.substring(dashIndex+1).trim(); - - int start = Integer.parseInt(startS); - int end = Integer.parseInt(endS); - - if (startS.startsWith("-")) startS=startS.substring(1).trim(); - if (endS.startsWith("-")) endS=endS.substring(1).trim(); - int minLen = Math.min(startS.length(), endS.length()); - - for (int ti=start; ti<=end; ti++) { - //partial support for negative numbers, but of course they cannot (yet) be specified in the regex above so it is moot - String tokenI = ""+Math.abs(ti); - while (tokenI.length()<minLen) tokenI = "0"+tokenI; - if (ti<0) tokenI = "-"+tokenI; - newPatterns.add(new ExpressionToExpand(resultSoFar.toString(), tokenI+suffix, operatorStackBeforeExpansion)); - } - } else { - newPatterns.add(new ExpressionToExpand(resultSoFar.toString(), token+suffix, operatorStackBeforeExpansion)); - } - } - // insert new patterns at the start, so we continue to expand them next - patterns.addAll(0, newPatterns); - - break; - } - if (!expanded) { - if (operatorStack.length()>0) { - throw new InvalidPatternException("Unclosed operators "+operatorStack+" parsing "+resultSoFar); - } - result.add(resultSoFar.toString()); - } - } - assert !result.isEmpty(); - return result; - } - - public static class InvalidPatternException extends RuntimeException { - private static final long serialVersionUID = -1969068264338310749L; - public InvalidPatternException(String msg) { - super(msg); - } - } - - - /** expands globs as per #getGlobsAfterBraceExpansion, - * but also handles numeric ranges, - * and optionally allows customized treatment of quoted regions and/or parentheses. - * <p> - * simple example: machine-{0-3}-{a,b} returns 8 values, - * machine-0-a machine-0-b machine-1-a ... machine-3-b; - * NB leading zeroes are meaningful, so {00-03} expands as 00, 01, 02, 03 - * <p> - * quote INTERIOR_NOT_EXPANDABLE example: a{b,"c,d"} return ab ac,d - * <p> - * for more detail on special treatment of quote and parentheses see PhraseTreatment and WildcardGlobsTest - */ - public static class SpecialistGlobExpander { - - private boolean expandNumericRanges; - private PhraseTreatment quoteTreatment; - private PhraseTreatment parenthesesTreatment; - - public SpecialistGlobExpander(boolean expandNumericRanges, PhraseTreatment quoteTreatment, PhraseTreatment parenthesesTreatment) { - this.expandNumericRanges = expandNumericRanges; - this.quoteTreatment = quoteTreatment; - this.parenthesesTreatment = parenthesesTreatment; - } - /** expands glob, including custom syntax for numeric part */ - public List<String> expand(String glob) throws InvalidPatternException { - return getGlobsAfterBraceExpansion(glob, expandNumericRanges, quoteTreatment, parenthesesTreatment); - } - - /** returns true iff the target matches the given pattern, - * under simplified bash rules -- viz permitting * and ? and comma delimited patterns inside curly braces, - * as well as things like {1,2,5-10} (and also {01,02,05-10} to keep leading 0) - * @throws InvalidPatternException */ - public boolean isGlobMatchedNumeric(String globPattern, String targetText) throws InvalidPatternException { - List<String> patterns = expand(globPattern); - for (String p : patterns) { - if (isNoBraceGlobMatched(p, targetText)) - return true; - } - return false; - } - - /** expands glob, including custom syntax for numeric part, but to an array, and re-throwing the checked exception as a runtime exception */ - public String[] expandToArrayUnchecked(String glob) { - try { - return expand(glob).toArray(new String[0]); - } catch (InvalidPatternException e) { - throw Throwables.propagate(e); - } - } - - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/time/CountdownTimer.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/time/CountdownTimer.java b/utils/common/src/main/java/brooklyn/util/time/CountdownTimer.java deleted file mode 100644 index 0a5aaec..0000000 --- a/utils/common/src/main/java/brooklyn/util/time/CountdownTimer.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 brooklyn.util.time; - -import java.util.concurrent.TimeUnit; - -import brooklyn.util.exceptions.Exceptions; - -import com.google.common.base.Stopwatch; - -public class CountdownTimer { - - Stopwatch stopwatch = Stopwatch.createUnstarted(); - Duration limit; - - private CountdownTimer(Duration limit) { - this.limit = limit; - } - - /** starts the timer, either initially or if {@link #pause()}d; no-op if already running */ - public synchronized CountdownTimer start() { - if (!stopwatch.isRunning()) stopwatch.start(); - return this; - } - - /** pauses the timer, if running; no-op if not running */ - public synchronized CountdownTimer pause() { - if (stopwatch.isRunning()) stopwatch.stop(); - return this; - } - - /** returns underlying stopwatch, which caller can inspect for more details or modify */ - public Stopwatch getStopwatch() { - return stopwatch; - } - - /** how much total time this timer should run for */ - public Duration getLimit() { - return limit; - } - - /** return how long the timer has been running (longer than limit if {@link #isExpired()}) */ - public Duration getDurationElapsed() { - return Duration.nanos(stopwatch.elapsed(TimeUnit.NANOSECONDS)); - } - - /** returns how much time is left (negative if {@link #isExpired()}) */ - public Duration getDurationRemaining() { - return Duration.millis(limit.toMilliseconds() - stopwatch.elapsed(TimeUnit.MILLISECONDS)); - } - - /** true iff the timer has been running for the duration specified at creation time */ - public boolean isExpired() { - return stopwatch.elapsed(TimeUnit.MILLISECONDS) > limit.toMilliseconds(); - } - - /** true iff timer is running (even if it is expired) */ - public boolean isRunning() { - return stopwatch.isRunning(); - } - - // --- constructor methods - - public static CountdownTimer newInstanceStarted(Duration duration) { - return new CountdownTimer(duration).start(); - } - - public static CountdownTimer newInstancePaused(Duration duration) { - return new CountdownTimer(duration).pause(); - } - - /** block (on this object) until completed - * @throws InterruptedException */ - public synchronized void waitForExpiry() throws InterruptedException { - while (waitOnForExpiry(this)) {}; - } - - /** as {@link #waitForExpiry()} but catches and wraps InterruptedException as unchecked RuntimeInterruptedExcedption */ - public synchronized void waitForExpiryUnchecked() { - waitOnForExpiryUnchecked(this); - } - - /** block on the given argument until the timer is completed or the object receives a notified; - * callers must be synchronized on the waitTarget - * @return true if the object is notified (or receives a spurious wake), false if the duration is expired - * @throws InterruptedException */ - public boolean waitOnForExpiry(Object waitTarget) throws InterruptedException { - Duration remainder = getDurationRemaining(); - if (remainder.toMilliseconds() <= 0) - return false; - waitTarget.wait(remainder.toMilliseconds()); - return true; - } - /** as {@link #waitOnForExpiry(Object)} but catches and wraps InterruptedException as unchecked RuntimeInterruptedExcedption */ - public boolean waitOnForExpiryUnchecked(Object waitTarget) { - try { - return waitOnForExpiry(waitTarget); - } catch (InterruptedException e) { - throw Exceptions.propagate(e); - } - } - -}
