http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/ByteSizeStrings.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/ByteSizeStrings.java b/utils/common/src/main/java/brooklyn/util/text/ByteSizeStrings.java deleted file mode 100644 index ac38e61..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/ByteSizeStrings.java +++ /dev/null @@ -1,416 +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.Formattable; -import java.util.FormattableFlags; -import java.util.Formatter; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.annotation.Nullable; - -import com.google.common.base.Function; - -/** - * A formatter to pretty-print numeric values representing sizes in byes. - * <p> - * The {@link ByteSizeStrings#builder()} presents a fluent interface to create - * various configurations of formatting. The defaults produce metric units in - * multiples of 1000 bytes at a precision of three significant figures. This is - * the way disk space is normally measured, for example {@literal 128.1GB}. - * <p> - * Alternatively the {@link ByteSizeStrings#iso()} convenience method produces - * ISO standard units in multiples of 1024 bytes, with the same precision as the - * metric output. This is how RAM is normally measured, for example {@literal 12.4MiB} - * or {@literal 1.04GiB}. - * <p> - * Finally, the {@link ByteSizeStrings#java()} convenience method will produce - * strings suitable for use with a Java command line, as part of the {@code -Xms} - * or {@code -Xmx} options. These output integer values only, so values up to - * 10GB will be reported in MB to preserve accuracy. For size values over 1000GB, - * the output will still be formatted as GB but rounded to a mutiple of 1000. - * <p> - * The class is immutable and thread safe once built and a single instance of - * the three pre-defined configurations is created and returned buy the methods - * described above. - * - * @see Strings#makeSizeString(long) - * @see Strings#makeISOSizeString(long) - * @see Strings#makeJavaSizeString(long) - */ -public class ByteSizeStrings implements Function<Long, String> { - - /** - * Configures and builds a {@link ByteSizeStrings} formatter. - */ - public static class Builder { - - private String suffixBytes = "B"; - private String suffixKilo = "kB"; - private String suffixMega = "MB"; - private String suffixGiga = "GB"; - private String suffixTera = "TB"; - private boolean addSpace = true; - private int bytesPerMetricUnit = 1000; - private int maxLen = 4; - private int precision = 3; - private int lowerLimit = 1; - - /** - * The suffix to use when printing bytes. - */ - public Builder suffixBytes(String suffixBytes) { this.suffixBytes = suffixBytes; return this; } - - /** - * The suffix to use when printing Kilobytes. - */ - public Builder suffixKilo(String suffixKilo) { this.suffixKilo = suffixKilo; return this; } - - /** - * The suffix to use when printing Megabytes. - */ - public Builder suffixMega(String suffixMega) { this.suffixMega = suffixMega; return this; } - - /** - * The suffix to use when printing Gigabytes. - */ - public Builder suffixGiga(String suffixGiga) { this.suffixGiga = suffixGiga; return this; } - - /** - * The suffix to use when printing Terabytes. - */ - public Builder suffixTera(String suffixTera) { this.suffixTera = suffixTera; return this; } - - /** - * Whether to add a space between the value and the unit suffix. - * <p> - * Defaults is {@literal true} for '5 MiB' output. - */ - public Builder addSpace(boolean addSpace) { this.addSpace = addSpace; return this; } - public Builder addSpace() { this.addSpace = true; return this; } - public Builder noSpace() { this.addSpace = false; return this; } - - /** - * The number of bytes per metric usnit, usually either 1000 or 1024. - * <p> - * Used to determine when to use the next suffix string. - */ - public Builder bytesPerMetricUnit(int bytesPerMetricUnit) { this.bytesPerMetricUnit = bytesPerMetricUnit; return this; } - - /** - * The maximum length of the printed number. - * - * @see Strings#makeRealString(double, int, int, int, double, boolean) - */ - public Builder maxLen(int maxLen) { this.maxLen = maxLen; return this; } - - /** - * The number of digits accuracy desired in the printed number. - * - * @see Strings#makeRealString(double, int, int, int, double, boolean) - */ - public Builder precision(int precision) { this.precision = precision; return this; } - - /** - * Prints using a lower suffix until the size is greater than this limit multiplied - * by bytes per metric unit, when the next highest suffix will be used.§ - * <p> - * If this has the value 5 then sizes up to 5000 will be printed as bytes, and over 5000 - * as Kilobytes. - */ - public Builder lowerLimit(int lowerLimit) { this.lowerLimit = lowerLimit; return this; } - - /** - * Returns an immutable {@link ByteSizeStrings} formatter using the builder configuration. - */ - public ByteSizeStrings build() { - String space = addSpace ? " " : ""; - return new ByteSizeStrings(space + suffixBytes, space + suffixKilo, space + suffixMega, space + suffixGiga, - space + suffixTera, bytesPerMetricUnit, maxLen, precision, lowerLimit); - } - - } - - /** - * Returns a builder for a {@link ByteSizeStrings} formatter. - */ - public static Builder builder() { return new Builder(); } - - /** - * Format byte sizes suitable for Java {@code -Xms} arguments. - */ - public static final ByteSizeStrings java() { return JAVA; } - - private static final ByteSizeStrings JAVA = ByteSizeStrings.builder() - .suffixBytes("") - .suffixKilo("k") - .suffixMega("m") - .suffixGiga("g") - .suffixTera("000g") // Java has no Tera suffix - .noSpace() - .bytesPerMetricUnit(1024) - .maxLen(6) - .precision(0) - .lowerLimit(10) - .build(); - - /** - * Formats byte sizes using ISO standard suffixes and binary multiples of 1024 - */ - public static ByteSizeStrings iso() { return ISO; } - - private static ByteSizeStrings ISO = ByteSizeStrings.builder() - .suffixBytes("B") - .suffixKilo("KiB") - .suffixMega("MiB") - .suffixGiga("GiB") - .suffixTera("TiB") - .bytesPerMetricUnit(1024) - .build(); - - /** - * Default byte size formatter using metric multiples of 1000. - */ - public static ByteSizeStrings metric() { return METRIC; } - - private static ByteSizeStrings METRIC = ByteSizeStrings.builder().build(); - - private String suffixBytes; - private String suffixKilo; - private String suffixMega; - private String suffixGiga; - private String suffixTera; - private int bytesPerMetricUnit; - private int maxLen; - private int precision; - private int lowerLimit; - - /** - * For use by the {@link Builder} only. - */ - private ByteSizeStrings(String suffixBytes, String suffixKilo, String suffixMega, String suffixGiga, - String suffixTera, int bytesPerMetricUnit, int maxLen, int precision, int lowerLimit) { - this.suffixBytes = suffixBytes; - this.suffixKilo = suffixKilo; - this.suffixMega = suffixMega; - this.suffixGiga = suffixGiga; - this.suffixTera = suffixTera; - this.bytesPerMetricUnit = bytesPerMetricUnit; - this.maxLen = maxLen; - this.precision = precision; - this.lowerLimit = lowerLimit; - } - - /** @deprecated Use {@link ByteSizeStrings#builder()} */ - @Deprecated - public ByteSizeStrings() { } - - /** @deprecated Use {@link ByteSizeStrings.Builder#suffixBytes(String)} */ - @Deprecated - public void setSuffixBytes(String suffixBytes) { - this.suffixBytes = suffixBytes; - } - - /** @deprecated Use {@link ByteSizeStrings.Builder#suffixKilo(String)} */ - @Deprecated - public void setSuffixKilo(String suffixKilo) { - this.suffixKilo = suffixKilo; - } - - /** @deprecated Use {@link ByteSizeStrings.Builder#suffixMega(String)} */ - @Deprecated - public void setSuffixMega(String suffixMega) { - this.suffixMega = suffixMega; - } - - /** @deprecated Use {@link ByteSizeStrings.Builder#suffixGiga(String)} */ - @Deprecated - public void setSuffixGiga(String suffixGiga) { - this.suffixGiga = suffixGiga; - } - - /** @deprecated Use {@link ByteSizeStrings.Builder#suffixTera(String)} */ - @Deprecated - public void setSuffixTera(String suffixTera) { - this.suffixTera = suffixTera; - } - - /** @deprecated Use {@link ByteSizeStrings.Builder#bytesPerMetricUnit(int)} */ - @Deprecated - public void setBytesPerMetricUnit(int bytesPerMetricUnit) { - this.bytesPerMetricUnit = bytesPerMetricUnit; - } - - /** @deprecated Use {@link ByteSizeStrings.Builder#maxLen(int)} */ - @Deprecated - public void setMaxLen(int maxLen) { - this.maxLen = maxLen; - } - - /** @deprecated Use {@link ByteSizeStrings.Builder#precision(int)} */ - @Deprecated - public void setPrecision(int precision) { - this.precision = precision; - } - - /** @deprecated Use {@link ByteSizeStrings.Builder#lowerLimit(int)} */ - @Deprecated - public void setLowerLimit(int lowerLimit) { - this.lowerLimit = lowerLimit; - } - - /** - * Format the {@literal size} bytes as a String. - */ - public String makeSizeString(long size) { - return makeSizeString(size, precision); - } - - /** - * Format the {@literal size} bytes as a String with the given precision. - */ - public String makeSizeString(long size, int precision) { - long t = size; - if (t==0) return "0"+suffixBytes; - if (t<0) return "-"+makeSizeString(-t); - long b = t%bytesPerMetricUnit; - t = t/bytesPerMetricUnit; - long kb = t%bytesPerMetricUnit; - t = t/bytesPerMetricUnit; - long mb = t%bytesPerMetricUnit; - t = t/bytesPerMetricUnit; - long gb = t%bytesPerMetricUnit; - t = t/bytesPerMetricUnit; - long tb = t; - - if (tb>lowerLimit) - return Strings.makeRealString(tb + (1.0*gb/bytesPerMetricUnit), -1, precision, 0) + suffixTera; - if (gb>lowerLimit) - return Strings.makeRealString((tb*bytesPerMetricUnit) + gb + (1.0*mb/bytesPerMetricUnit), maxLen, precision, 0) + suffixGiga; - if (mb>lowerLimit) - return Strings.makeRealString((gb*bytesPerMetricUnit) + mb + (1.0*kb/bytesPerMetricUnit), maxLen, precision, 0) + suffixMega; - if (kb>lowerLimit) - return Strings.makeRealString((mb*bytesPerMetricUnit) + kb + (1.0*b/bytesPerMetricUnit), maxLen, precision, 0) + suffixKilo; - return (kb*bytesPerMetricUnit) + b + suffixBytes; - } - - /** - * Returns a {@link Formattable} object that can be used with {@link String#format(String, Object...)}. - * <p> - * When used as the argument for a {@literal %s} format string element, the {@literal bytes} value - * will be formatted using the current {@link ByteSizeStrings} values, or if the alternative - * flag is set (using the {@literal %#s} format string) it will use the {@link ByteSizeStrings#metric()} - * formatter. Finally, the precision of the formatted value can be adjusted using format string - * argumenbts like {@literal %.6s}. - * - * @see http://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax - */ - public Formattable formatted(final long bytes) { - return new Formattable() { - @Override - public void formatTo(Formatter formatter, int flags, int width, int precision) { - boolean alternate = (flags & FormattableFlags.ALTERNATE) == FormattableFlags.ALTERNATE; - ByteSizeStrings strings = alternate ? ByteSizeStrings.metric() : ByteSizeStrings.this; - if (precision != -1) { - formatter.format("%s", strings.makeSizeString(bytes, precision)); - } else { - formatter.format("%s", strings.makeSizeString(bytes)); - } - } - }; - } - - /** - * A {@link Function} implementation that formats its input using the current {@link ByteSizeStrings} values. - */ - @Override - @Nullable - public String apply(@Nullable Long input) { - if (input == null) return null; - return makeSizeString(input); - } - - public static long parse(String sizeString) { - return parse(sizeString, null); - } - public static long parse(String sizeString, String defaultUnits) { - return parse(sizeString, defaultUnits, null); - } - /** parses the given string as a byte size string, e.g. "4gb" - * @param sizeString string to parse - * @param defaultUnit optional units to append if a number (no units) are supplied - * @param bytesMode optional evaluation mode to force 1024 or 1000 as the interpretation of the unit prefix; - * if omitted, it will depend on the units supplied, - * 1000 for {@link #metric()} (e.g. "1kB"), and - * 1024 for {@link #java()} (e.g. "1k") and {@link #iso()} (e.g. "1KiB") - * @return number of bytes represented by this string - */ - public static long parse(String sizeStringOriginal, String defaultUnit, ByteSizeStrings bytesMode) { - String sizeString = sizeStringOriginal.trim(); - String units; - Matcher matcher = Pattern.compile("[A-Za-z]+").matcher(sizeString); - if (!matcher.find()) { - if (defaultUnit==null) { - throw new IllegalArgumentException("Cannot parse '"+sizeStringOriginal+"' as a size string"); - } - units = defaultUnit; - } else { - units = matcher.group(); - int unitsIndex = sizeString.indexOf(units); - if (sizeString.length() > unitsIndex+units.length()) { - throw new IllegalArgumentException("Cannot parse '"+sizeStringOriginal+"' as a size string"); - } - sizeString = sizeString.substring(0, unitsIndex).trim(); - } - - int exponent = -1; - ByteSizeStrings matchedMode = null; - for (ByteSizeStrings mode: new ByteSizeStrings[] { ISO, JAVA, METRIC } ) { - matchedMode = mode; - if (units.equalsIgnoreCase(mode.suffixBytes.trim())) { exponent = 0; break; } - if (units.equalsIgnoreCase(mode.suffixKilo.trim())) { exponent = 1; break; } - if (units.equalsIgnoreCase(mode.suffixMega.trim())) { exponent = 2; break; } - if (units.equalsIgnoreCase(mode.suffixGiga.trim())) { exponent = 3; break; } - if (units.equalsIgnoreCase(mode.suffixTera.trim())) { exponent = 4; break; } - } - - if (exponent==-1) { - // did not match; try other standard ones - if (units.equalsIgnoreCase("t")) { - exponent = 4; - matchedMode = java(); - } else { - throw new IllegalArgumentException("Cannot parse '"+sizeStringOriginal+"' as a size string (as '"+sizeString+"' "+units+")"); - } - } - - double base = Double.parseDouble(sizeString.trim()); - - if (bytesMode==null) bytesMode=matchedMode; - - while (exponent>0) { - base *= bytesMode.bytesPerMetricUnit; - exponent--; - } - - return (long)base; - } - -}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/ComparableVersion.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/ComparableVersion.java b/utils/common/src/main/java/brooklyn/util/text/ComparableVersion.java deleted file mode 100644 index 30bec96..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/ComparableVersion.java +++ /dev/null @@ -1,89 +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; - - -/** takes a version string, and compares to other versions, using {@link NaturalOrderComparator} */ -public class ComparableVersion implements Comparable<String> { - - public final String version; - - public ComparableVersion(String version) { - this.version = version; - } - - public int compareTo(String target) { - return new NaturalOrderComparator().compare(version, target); - } - - public boolean isGreaterThanOrEqualTo(String target) { - return compareTo(target) >= 0; - } - public boolean isGreaterThanAndNotEqualTo(String target) { - return compareTo(target) > 0; - } - public boolean isLessThanOrEqualTo(String target) { - return compareTo(target) <= 0; - } - public boolean isLessThanAndNotEqualTo(String target) { - return compareTo(target) < 0; - } - - /** inclusive at endpoints */ - public boolean isInRange(String lowerBound, String upperBound) { - return isGreaterThanAndNotEqualTo(lowerBound) && isLessThanAndNotEqualTo(upperBound); - } - - /** parses a string expressed with common mathematical sematics, - * as either square brackets (inclusive), round brackets (exclusive), or one of each, - * surrounding a pair of version strings separated by a comma, where a version string - * consists of any non-whitespace non-bracket characters - * (ie numbers, letters, dots, hyphens, underscores) or is empty (to indicate no bound); - * e.g. "[10.6,10.7)" to mean >= 10.6 and < 10.7; - * "[10.6,)" to mean >= 10.6. - */ - public boolean isInRange(String range) { - String r = range.trim(); - boolean strictLeft, strictRight; - - if (r.startsWith("(")) strictLeft = true; - else if (r.startsWith("[")) strictLeft = false; - else throw new IllegalArgumentException("Range must start with ( or ["); - if (r.endsWith(")")) strictRight = true; - else if (r.endsWith("]")) strictRight = false; - else throw new IllegalArgumentException("Range must end with ) or ]"); - - int i = r.indexOf(","); - if (i==-1) throw new IllegalArgumentException("Range must contain , following the open bracket and version"); - String left = r.substring(1, i).trim(); - String right = r.substring(i+1, r.length()-1).trim(); - - if (left.length()>0) { - if (strictLeft && compareTo(left)<=0) return false; - if (!strictLeft && compareTo(left)<0) return false; - } - if (right.length()>0) { - if (strictRight && compareTo(right)>=0) return false; - if (!strictRight && compareTo(right)>0) return false; - } - - return true; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/FormattedString.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/FormattedString.java b/utils/common/src/main/java/brooklyn/util/text/FormattedString.java deleted file mode 100644 index 949ab3f..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/FormattedString.java +++ /dev/null @@ -1,47 +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 com.google.common.base.Preconditions; -import com.google.common.base.Supplier; - -/** 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 class FormattedString { - private final String pattern; - private final Object[] args; - public FormattedString(String pattern, Object[] args) { - this.pattern = pattern; - this.args = args; - } - @Override - public String toString() { - return String.format(pattern, args); - } - public String getPattern() { - return pattern; - } - public Object[] getArgs() { - return args; - } - public Supplier<String> supplier() { - return Strings.toStringSupplier(this); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/Identifiers.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/Identifiers.java b/utils/common/src/main/java/brooklyn/util/text/Identifiers.java deleted file mode 100644 index 1b8377d..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/Identifiers.java +++ /dev/null @@ -1,210 +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.Random; - -public class Identifiers { - - private static Random random = new Random(); - - public static final String JAVA_GOOD_START_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_"; - public static final String JAVA_GOOD_NONSTART_CHARS = JAVA_GOOD_START_CHARS+"1234567890"; - - public static final String JAVA_GENERATED_IDENTIFIER_START_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - public static final String JAVA_GENERATED_IDENTIFIERNONSTART_CHARS = JAVA_GENERATED_IDENTIFIER_START_CHARS+"1234567890"; - - public static final String BASE64_VALID_CHARS = JAVA_GENERATED_IDENTIFIERNONSTART_CHARS+"+="; - - public static final String ID_VALID_START_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - public static final String ID_VALID_NONSTART_CHARS = ID_VALID_START_CHARS+"1234567890"; - - /** makes a random id string (letters and numbers) of the given length; - * starts with letter (upper or lower) so can be used as java-id; - * tests ensure random distribution, so random ID of length 5 - * is about 2^29 possibilities - * <p> - * With ID of length 4 it is not unlikely (15% chance) to get - * duplicates in the first 2000 attempts. - * With ID of length 8 there is 1% chance to get duplicates - * in the first 1M attempts and 50% for the first 16M. - * <p> - * implementation is efficient, uses char array, and - * makes one call to random per 5 chars; makeRandomId(5) - * takes about 4 times as long as a simple Math.random call, - * or about 50 times more than a simple x++ instruction; - * in other words, it's appropriate for contexts where random id's are needed, - * but use efficiently (ie cache it per object), and - * prefer to use a counter where feasible - * <p> - * in general this is preferable to base64 as is more portable, - * can be used throughout javascript (as ID's which don't allow +) - * or as java identifiers (which don't allow numbers in the first char) - **/ - public static String makeRandomId(int l) { - //this version is 30-50% faster than the old double-based one, - //which computed a random every 3 turns -- - //takes about 600 ns to do id of len 10, compared to 10000 ns for old version [on 1.6ghz machine] - if (l<=0) return ""; - char[] id = new char[l]; - int d = random.nextInt( (26+26) * (26+26+10) * (26+26+10) * (26+26+10) * (26+26+10)); - int i = 0; - id[i] = ID_VALID_START_CHARS.charAt(d % (26+26)); - d /= (26+26); - if (++i<l) do { - id[i] = ID_VALID_NONSTART_CHARS.charAt(d%(26+26+10)); - if (++i>=l) break; - if (i%5==0) { - d = random.nextInt( (26+26+10) * (26+26+10) * (26+26+10) * (26+26+10) * (26+26+10)); - } else { - d /= (26+26+10); - } - } while (true); - //Message.message("random id is " + id); - return new String(id); - } - - /** creates a short identifier comfortable in java and OS's, given an input hash code - * <p> - * result is always at least of length 1, shorter if the hash is smaller */ - public static String makeIdFromHash(long d) { - StringBuffer result = new StringBuffer(); - if (d<0) d=-d; - // correction for Long.MIN_VALUE - if (d<0) d=-(d+1000); - - result.append(ID_VALID_START_CHARS.charAt((int)(d % (26+26)))); - d /= (26+26); - while (d!=0) { - result.append(ID_VALID_NONSTART_CHARS.charAt((int)(d%(26+26+10)))); - d /= (26+26+10); - } - return result.toString(); - } - - /** makes a random id string (letters and numbers) of the given length; - * starts with letter (upper or lower) so can be used as java-id; - * tests ensure random distribution, so random ID of length 5 - * is about 2^29 possibilities - * <p> - * implementation is efficient, uses char array, and - * makes one call to random per 5 chars; makeRandomId(5) - * takes about 4 times as long as a simple Math.random call, - * or about 50 times more than a simple x++ instruction; - * in other words, it's appropriate for contexts where random id's are needed, - * but use efficiently (ie cache it per object), and - * prefer to use a counter where feasible - **/ - public static String makeRandomJavaId(int l) { - // copied from Monterey util's com.cloudsoftcorp.util.StringUtils. - // TODO should share code with makeRandomId, just supplying different char sets (though the char sets in fact are the same..) - - //this version is 30-50% faster than the old double-based one, - //which computed a random every 3 turns -- - //takes about 600 ns to do id of len 10, compared to 10000 ns for old version [on 1.6ghz machine] - if (l<=0) return ""; - char[] id = new char[l]; - int d = random.nextInt( (26+26) * (26+26+10) * (26+26+10) * (26+26+10) * (26+26+10)); - int i = 0; - id[i] = JAVA_GENERATED_IDENTIFIER_START_CHARS.charAt(d % (26+26)); - d /= (26+26); - if (++i<l) do { - id[i] = JAVA_GENERATED_IDENTIFIERNONSTART_CHARS.charAt(d%(26+26+10)); - if (++i>=l) break; - if (i%5==0) { - d = random.nextInt( (26+26+10) * (26+26+10) * (26+26+10) * (26+26+10) * (26+26+10)); - } else { - d /= (26+26+10); - } - } while (true); - //Message.message("random id is " + id); - return new String(id); - } - - public static double randomDouble() { - return random.nextDouble(); - } - public static long randomLong() { - return random.nextLong(); - } - public static boolean randomBoolean() { - return random.nextBoolean(); - } - public static int randomInt() { - return random.nextInt(); - } - /** returns in [0,upbound) */ - public static int randomInt(int upbound) { - return random.nextInt(upbound); - } - /** returns the array passed in */ - public static byte[] randomBytes(byte[] buf) { - random.nextBytes(buf); - return buf; - } - public static byte[] randomBytes(int length) { - byte[] buf = new byte[length]; - return randomBytes(buf); - } - - public static String makeRandomBase64Id(int length) { - StringBuilder s = new StringBuilder(); - while (length>0) { - appendBase64IdFromValueOfLength(randomLong(), length>10 ? 10 : length, s); - length -= 10; - } - return s.toString(); - } - public static String getBase64IdFromValue(long value) { - return getBase64IdFromValue(value, 10); - } - public static String getBase64IdFromValue(long value, int length) { - StringBuilder s = new StringBuilder(); - appendBase64IdFromValueOfLength(value, length, s); - return s.toString(); - } - public static void appendBase64IdFromValueOfLength(long value, int length, StringBuffer sb) { - if (length>11) - throw new IllegalArgumentException("can't get a Base64 string longer than 11 chars from a long"); - long idx = value; - for (int i=0; i<length; i++) { - byte x = (byte)(idx & 63); - sb.append(BASE64_VALID_CHARS.charAt(x)); - idx = idx >> 6; - } - } - public static void appendBase64IdFromValueOfLength(long value, int length, StringBuilder sb) { - if (length>11) - throw new IllegalArgumentException("can't get a Base64 string longer than 11 chars from a long"); - long idx = value; - for (int i=0; i<length; i++) { - byte x = (byte)(idx & 63); - sb.append(BASE64_VALID_CHARS.charAt(x)); - idx = idx >> 6; - } - } - - public static boolean isValidToken(String token, String validStartChars, String validSubsequentChars) { - if (token==null || token.length()==0) return false; - if (validStartChars.indexOf(token.charAt(0))==-1) return false; - for (int i=1; i<token.length(); i++) - if (validSubsequentChars.indexOf(token.charAt(i))==-1) return false; - return true; - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/KeyValueParser.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/KeyValueParser.java b/utils/common/src/main/java/brooklyn/util/text/KeyValueParser.java deleted file mode 100644 index 76a4532..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/KeyValueParser.java +++ /dev/null @@ -1,124 +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.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import com.google.common.base.Splitter; - - -/** - * Parses a String that consists of multiple arguments, which are either single or key-value pairs. - * The value may be in quotes. - * - * For example: - * a=x, b="x x", c, "d d" - * - * Would return the ordered map: - * "a" = "x" - * "b" = "x x" - * "c" = null - * "d d" = null - * - * Consider instead using {@link Splitter#withKeyValueSeparator(char)}, but that doesn't give the - * same behaviour for values, see {@link QuotedStringTokenizer}. For example: - * <pre> - * {@code - * String val = "a=x,b=y"; - * Map<String,String> map = Splitter.on(",").withKeyValueSeparator("=").split(val); - * } - * </pre> - * - * @author aled - **/ -public class KeyValueParser { - - public static String toLine(Map<String, String> parts) { - QuotedStringTokenizer tokenizer = new QuotedStringTokenizer("", true); - - StringBuilder result = new StringBuilder(); - for (Map.Entry<String, String> entry : parts.entrySet()) { - if (result.length()>0) result.append(", "); - result.append(tokenizer.quoteToken(entry.getKey())); - if (entry.getValue() != null) result.append("="+tokenizer.quoteToken(entry.getValue())); - } - return result.toString(); - } - - public static String toLine(Collection<String> parts) { - QuotedStringTokenizer tokenizer = new QuotedStringTokenizer("", false); - - StringBuilder result = new StringBuilder(); - for (String part : parts) { - result.append(tokenizer.quoteToken(part)+", "); - } - if (result.length() > 0) result.deleteCharAt(result.length()-1); - return result.toString(); - } - - public static List<String> parseList(String line) { - List<String> result = new ArrayList<String>(); - QuotedStringTokenizer tokenizer = new QuotedStringTokenizer(line, null, true, ",", false); - - while (tokenizer.hasMoreTokens()) { - result.add(tokenizer.unquoteToken(tokenizer.nextToken().trim())); - } - return result; - } - - @Deprecated // use parseMap - public static Map<String,String> parse(String line) { - return parseMap(line); - } - - /** takes a string of the form "key=value,key2=value2" and returns a map; - * values can be quoted (but not keys) */ - public static Map<String,String> parseMap(String line) { - Map<String,String> result = new LinkedHashMap<String,String>(); - - QuotedStringTokenizer tokenizer = new QuotedStringTokenizer(line, null, true, ",", false); - - while (tokenizer.hasMoreTokens()) { - //String token = tokenizer.unquoteToken(tokenizer.nextToken().trim()); - String token = tokenizer.nextToken().trim(); - - int index = token.indexOf("="); - - if (index < 0) { - String unquotedKey = tokenizer.unquoteToken(token); - result.put(unquotedKey, null); - - } else if (index < (token.length()-1)) { - String unquotedKey = tokenizer.unquoteToken(token.substring(0, index).trim()); - String unquotedVal = tokenizer.unquoteToken(token.substring(index+1).trim()); - result.put(unquotedKey, unquotedVal); - - } else { // ends with = - assert index == token.length() -1; - String unquotedKey = tokenizer.unquoteToken(token.substring(0, index).trim()); - result.put(unquotedKey, ""); - } - } - return result; - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/NaturalOrderComparator.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/NaturalOrderComparator.java b/utils/common/src/main/java/brooklyn/util/text/NaturalOrderComparator.java deleted file mode 100644 index 84ea567..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/NaturalOrderComparator.java +++ /dev/null @@ -1,165 +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. - * - -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 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; - * 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>) - */ -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; - } - } - - 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); - } - } - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/QuotedStringTokenizer.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/QuotedStringTokenizer.java b/utils/common/src/main/java/brooklyn/util/text/QuotedStringTokenizer.java deleted file mode 100644 index 1946235..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/QuotedStringTokenizer.java +++ /dev/null @@ -1,196 +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 java.util.NoSuchElementException; -import java.util.StringTokenizer; - -/** As 'StringTokenizer' but items in quotes (single or double) are treated as single tokens - * (cf mortbay's QuotedStringTokenizer) - */ -public class QuotedStringTokenizer { - - final StringTokenizer delegate; - final String quoteChars; - final boolean includeQuotes; - final String delimiters; - final boolean includeDelimiters; - - public static String DEFAULT_QUOTE_CHARS = "\"\'"; - - - protected String DEFAULT_QUOTE_CHARS() { - return DEFAULT_QUOTE_CHARS; - } - - public final static String DEFAULT_DELIMITERS = " \t\n\r\f"; - - /** default quoted tokenizer, using single and double quotes as quote chars and returning quoted results - * (use unquoteToken to unquote), and using whitespace chars as delimeters (not included as tokens); - * string may be null if the nothing will be tokenized and the class is used only for - * quoteToken(String) and unquote(String). - */ - public QuotedStringTokenizer(String stringToTokenize) { - this(stringToTokenize, true); - } - public QuotedStringTokenizer(String stringToTokenize, boolean includeQuotes) { - this(stringToTokenize, null, includeQuotes); - } - public QuotedStringTokenizer(String stringToTokenize, String quoteChars, boolean includeQuotes) { - this(stringToTokenize, quoteChars, includeQuotes, null, false); - } - - public QuotedStringTokenizer(String stringToTokenize, String quoteChars, boolean includeQuotes, String delimiters, boolean includeDelimiters) { - delegate = new StringTokenizer(stringToTokenize==null ? "" : stringToTokenize, (delimiters==null ? DEFAULT_DELIMITERS : delimiters), true); - this.quoteChars = quoteChars==null ? DEFAULT_QUOTE_CHARS() : quoteChars; - this.includeQuotes = includeQuotes; - this.delimiters = delimiters==null ? DEFAULT_DELIMITERS : delimiters; - this.includeDelimiters = includeDelimiters; - updateNextToken(); - } - - public static class Builder { - private String quoteChars = DEFAULT_QUOTE_CHARS; - private boolean includeQuotes=true; - private String delimiterChars=DEFAULT_DELIMITERS; - private boolean includeDelimiters=false; - - public QuotedStringTokenizer build(String stringToTokenize) { - return new QuotedStringTokenizer(stringToTokenize, quoteChars, includeQuotes, delimiterChars, includeDelimiters); - } - public List<String> buildList(String stringToTokenize) { - return new QuotedStringTokenizer(stringToTokenize, quoteChars, includeQuotes, delimiterChars, includeDelimiters).remainderAsList(); - } - - public Builder quoteChars(String quoteChars) { this.quoteChars = quoteChars; return this; } - public Builder addQuoteChars(String quoteChars) { this.quoteChars = this.quoteChars + quoteChars; return this; } - public Builder includeQuotes(boolean includeQuotes) { this.includeQuotes = includeQuotes; return this; } - public Builder delimiterChars(String delimiterChars) { this.delimiterChars = delimiterChars; return this; } - public Builder addDelimiterChars(String delimiterChars) { this.delimiterChars = this.delimiterChars + delimiterChars; return this; } - public Builder includeDelimiters(boolean includeDelimiters) { this.includeDelimiters = includeDelimiters; return this; } - } - public static Builder builder() { - return new Builder(); - } - - String peekedNextToken = null; - - public synchronized boolean hasMoreTokens() { - return peekedNextToken!=null; - } - - public synchronized String nextToken() { - if (peekedNextToken==null) throw new NoSuchElementException(); - String lastToken = peekedNextToken; - updateNextToken(); - return includeQuotes ? lastToken : unquoteToken(lastToken); - } - - /** this method removes all unescaped quote chars, i.e. quote chars preceded by no backslashes (or a larger even number of them); - * it also unescapes '\\' as '\'. it does no other unescaping. */ - public String unquoteToken(String word) { - // ( (\\A|[^\\\\]) (\\\\\\\\)* ) [ Pattern.quote(quoteChars) ] $1 - word = word.replaceAll( - "((\\A|[^\\\\])(\\\\\\\\)*)["+ - //Pattern.quote( - quoteChars - //) - +"]+", - "$1"); - //above pattern removes any quote preceded by even number of backslashes - //now it is safe to replace any \c by c - word = word.replaceAll("\\\\"+"([\\\\"+ - //Pattern.quote( - quoteChars - //) - +"])", "$1"); - - return word; - } - - /** returns the input text escaped for use with unquoteTokens, and wrapped in the quoteChar[0] (usu a double quote) */ - public String quoteToken(String unescapedText) { - String result = unescapedText; - //replace every backslash by two backslashes - result = result.replaceAll("\\\\", "\\\\\\\\"); - //now replace every quote char by backslash quote char - result = result.replaceAll("(["+quoteChars+"])", "\\\\$1"); - //then wrap in quote - result = quoteChars.charAt(0) + result + quoteChars.charAt(0); - return result; - } - - protected synchronized void updateNextToken() { - peekedNextToken = null; - String token; - do { - if (!delegate.hasMoreTokens()) return; - token = delegate.nextToken(); - //skip delimeters - } while (!includeDelimiters && token.matches("["+delimiters+"]+")); - - StringBuffer nextToken = new StringBuffer(token); - pullUntilValid(nextToken); - peekedNextToken = nextToken.toString(); - } - - private void pullUntilValid(StringBuffer nextToken) { - while (hasOpenQuote(nextToken.toString(), quoteChars) && delegate.hasMoreTokens()) { - //keep appending until the quote is ended or there are no more quotes - nextToken.append(delegate.nextToken()); - } - } - - public static boolean hasOpenQuote(String stringToCheck) { - return hasOpenQuote(stringToCheck, DEFAULT_QUOTE_CHARS); - } - - public static boolean hasOpenQuote(String stringToCheck, String quoteChars) { - String x = stringToCheck; - if (x==null) return false; - - StringBuffer xi = new StringBuffer(); - for (int i=0; i<x.length(); i++) { - char c = x.charAt(i); - if (c=='\\') i++; - else if (quoteChars.indexOf(c)>=0) { - xi.append(c); - } - } - x = xi.toString(); - - while (x.length()>0) { - char c = x.charAt(0); - int match = x.indexOf(c, 1); - if (match==-1) return true; - x = x.substring(match+1); - } - return false; - } - - public List<String> remainderAsList() { - List<String> l = new ArrayList<String>(); - while (hasMoreTokens()) - l.add(nextToken()); - return l; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/StringEscapes.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/StringEscapes.java b/utils/common/src/main/java/brooklyn/util/text/StringEscapes.java deleted file mode 100644 index b5b4976..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/StringEscapes.java +++ /dev/null @@ -1,413 +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.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nonnull; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import brooklyn.util.collections.MutableList; -import brooklyn.util.exceptions.Exceptions; -import brooklyn.util.net.URLParamEncoder; - -public class StringEscapes { - - private static final Logger log = LoggerFactory.getLogger(StringEscapes.class); - - /** if s is wrapped in double quotes containing no unescaped double quotes */ - public static boolean isWrappedInDoubleQuotes(String s) { - if (Strings.isEmpty(s)) return false; - if (!s.startsWith("\"") || !s.endsWith("\"")) return false; - return (s.substring(1, s.length()-1).replace("\\\\", "").replace("\\\"", "").indexOf("\"")==-1); - } - - /** if s is wrapped in single quotes containing no unescaped single quotes */ - public static boolean isWrappedInSingleQuotes(String s) { - if (Strings.isEmpty(s)) return false; - if (!s.startsWith("\'") || !s.endsWith("\'")) return false; - return (s.substring(1, s.length()-1).replace("\\\\", "").replace("\\\'", "").indexOf("\'")==-1); - } - - /** if s is wrapped in single or double quotes containing no unescaped quotes of that type */ - public static boolean isWrappedInMatchingQuotes(String s) { - return isWrappedInDoubleQuotes(s) || isWrappedInSingleQuotes(s); - } - - /** - * Encodes a string suitable for use as a parameter in a URL. - */ - public static String escapeUrlParam(String input) { - return URLParamEncoder.encode(input); - } - - /** - * Encodes a string suitable for use as a URL in an HTML form: space to +, and high-numbered chars assuming UTF-8. - * However, it will also convert the first "http://" to "http%3A%2F%2F" so is not suitable for converting an - * entire URL. - * - * Also note that parameter-conversion doesn't work in way you'd expect when trying to create a "normal" url. - * See http://stackoverflow.com/questions/724043/http-url-address-encoding-in-java - * - * @see escapeUrlParam(String), and consider using that instead. - */ - public static String escapeHtmlFormUrl(String url) { - try { - return URLEncoder.encode(url, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw Exceptions.propagate(e); - } - } - - /** encodes a string to SQL, that is ' becomes '' */ - public static String escapeSql(String x) { - //identical to apache commons StringEscapeUtils.escapeSql - if (x==null) return null; - return x.replaceAll("'", "''"); - } - - - - public static class BashStringEscapes { - // single quotes don't permit escapes! e.g. echo 'hello \' world' doesn't work; - // you must do 'hello '\'' world' (to get "hello ' world") - - /** wraps plain text in double quotes escaped for use in bash double-quoting */ - public static String wrapBash(String value) { - StringBuilder out = new StringBuilder(); - try { - wrapBash(value, out); - } catch (IOException e) { - //shouldn't happen for string buffer - throw Exceptions.propagate(e); - } - return out.toString(); - } - - /** @see #wrapBash(String) */ - public static void wrapBash(String value, Appendable out) throws IOException { - out.append('"'); - escapeLiteralForDoubleQuotedBash(value, out); - out.append('"'); - } - - private static void escapeLiteralForDoubleQuotedBash(String value, Appendable out) throws IOException { - for (int i=0; i<value.length(); i++) { - char c = value.charAt(i); - if (c=='\\' || c=='\"' || c=='$' || c=='`') { - appendEscaped(out, c); - } else if (c == '!') { - out.append("\"'!'\""); - } else { - out.append(c); - } - } - } - - /** performs replacements on a string so that it can be legally inserted into a double-quoted bash context - * (without the surrounding double quotes; see also {@link #wrapBash(String)}) */ - public static String escapeLiteralForDoubleQuotedBash(String unquotedInputToBeEscaped) { - StringBuilder out = new StringBuilder(); - try { - escapeLiteralForDoubleQuotedBash(unquotedInputToBeEscaped, out); - } catch (IOException e) { - // shouldn't happen for StringBuilder - throw Exceptions.propagate(e); - } - return out.toString(); - } - - /** transforms e.g. [ "-Dname=Bob Johnson", "-Dnet.worth=$100" ] to - * a java string "\"-Dname=Bob Johnson\" \"-Dnet.worth=\$100\"" -- - * which can be inserted into a bash command where it will be picked up as 2 params - */ - public static String doubleQuoteLiteralsForBash(String... args) { - StringBuilder result = new StringBuilder(); - for (String arg: args) { - if (!Strings.isEmpty(result)) result.append(" "); - result.append("\""); - result.append(escapeLiteralForDoubleQuotedBash(arg)); - result.append("\""); - } - return result.toString(); - } - - //between java and regex parsing, this gives a single backslash and double quote - private static final String BACKSLASH = "\\\\"; - private static final String DOUBLE_QUOTE = "\\\""; - - public static boolean isValidForDoubleQuotingInBash(String x) { - return (checkValidForDoubleQuotingInBash(x)==null); - } - - public static void assertValidForDoubleQuotingInBash(String x) { - String problem = checkValidForDoubleQuotingInBash(x); - if (problem==null) return; - throw new IllegalArgumentException("String \""+x+"\" not acceptable for bash argument (including double quotes): "+problem); - } - - private static String checkValidForDoubleQuotingInBash(String x) { - //double quotes must be preceded by a backslash (preceded by 0 or more bash-escaped backslashes) - if (x.matches( "[^"+BACKSLASH+DOUBLE_QUOTE+"]*"+ - "("+BACKSLASH+BACKSLASH+")*"+ - DOUBLE_QUOTE+".*")) return "unescaped double quote"; - return null; - } - - /** given a string in bash notation, e.g. with quoted portions needing unescaped, returns the unescaped and unquoted version */ - public static String unwrapBashQuotesAndEscapes(String s) { - return applyUnquoteAndUnescape(s, "Bash", true); - } - } - - - public static class JavaStringEscapes { - /** converts normal string to java escaped for double-quotes (but not wrapped in double quotes) */ - public static String escapeJavaString(String value) { - StringBuilder out = new StringBuilder(); - try { - escapeJavaString(value, out); - } catch (IOException e) { - //shouldn't happen for string builder - throw Exceptions.propagate(e); - } - return out.toString(); - } - - /** converts normal string to java escaped for double-quotes and wrapped in those double quotes */ - public static String wrapJavaString(String value) { - StringBuilder out = new StringBuilder(); - try { - wrapJavaString(value, out); - } catch (IOException e) { - //shouldn't happen for string builder - throw Exceptions.propagate(e); - } - return out.toString(); - } - public static List<String> wrapJavaStrings(Iterable<String> values) { - if (values==null) return null; - List<String> result = MutableList.of(); - for (String v: values) result.add(wrapJavaString(v)); - return result; - } - - /** as {@link #unwrapJavaString(String)} if the given string is wrapped in double quotes; - * otherwise just returns the given string */ - public static String unwrapJavaStringIfWrapped(String s) { - if (!StringEscapes.isWrappedInDoubleQuotes(s)) return s; - return unwrapJavaString(s); - } - - /** converts normal string to java escaped for double-quotes and wrapped in those double quotes */ - public static void wrapJavaString(String value, Appendable out) throws IOException { - if (value==null) { - out.append("null"); - } else { - out.append('"'); - escapeJavaString(value, out); - out.append('"'); - } - } - - /** converts normal string to java escaped for double-quotes (but not wrapped in double quotes) */ - public static void escapeJavaString(@Nonnull String value, Appendable out) throws IOException { - for (int i=0; i<value.length(); i++) { - char c = value.charAt(i); - if (c=='\\' || c=='"') { - // NB do NOT escape single quotes; while valid for java, it is not in JSON (breaks jQuery.parseJSON) - appendEscaped(out, c); - } else if (c=='\n') { - appendEscaped(out, 'n'); - } else if (c=='\t') { - appendEscaped(out, 't'); - } else if (c=='\r') { - appendEscaped(out, 'r'); - } else { - out.append(c); - } - } - } - - /** given a string in java syntax, e.g. wrapped in quotes and with backslash escapes, returns the literal value, - * without the surrounding quotes and unescaped; throws IllegalArgumentException if not a valid java string */ - public static String unwrapJavaString(String s) { - return applyUnquoteAndUnescape(s, "Java", false); - } - - /** - * Unwraps a sequence of quoted java strings, that are each separated by the given separator. - * @param trimmedArg - * @return - */ - public static List<String> unwrapQuotedJavaStringList(String s, String separator) { - List<String> result = new ArrayList<String>(); - String remaining = s.trim(); - while (remaining.length() > 0) { - int endIndex = findNextClosingQuoteOf(remaining); - result.add(unwrapJavaString(remaining.substring(0, endIndex+1))); - remaining = remaining.substring(endIndex+1).trim(); - if (remaining.startsWith(separator)) { - remaining = remaining.substring(separator.length()).trim(); - } else if (remaining.length() > 0) { - throw new IllegalArgumentException("String '"+s+"' has invalid separators, should be '"+separator+"'"); - } - } - return result; - } - private static int findNextClosingQuoteOf(String s) { - boolean escaped = false; - boolean quoted = false; - for (int i=0; i<s.length(); i++) { - char c = s.charAt(i); - if (!quoted) { - assert (i==0); - assert !escaped; - if (c=='"') quoted = true; - else throw new IllegalArgumentException("String '"+s+"' is not a valid Java string (must start with double quote)"); - } else { - if (escaped) { - escaped = false; - } else { - if (c=='\\') escaped = true; - else if (c=='\"') { - quoted = false; - return i; - } - } - } - } - - assert quoted; - throw new IllegalArgumentException("String '"+s+"' is not a valid Java string (unterminated string)"); - } - - /** converts a comma separated list in a single string to a list of strings, - * doing what would be expected if given java or json style string as input, - * and falling back to returning the input. - * <p> - * this method does <b>not</b> throw exceptions on invalid input, - * but just returns that input - * <p> - * specifically, uses the following rules (executed once in sequence: - * <li> 1) if of form <code>[ X ]</code> (in brackets after trim), - * then removes brackets and applies following rules to X (for any X including quoted or with commas) - * <li> 2) if of form <code>"X"</code> - * (in double quotes after trim, - * where X contains no internal double quotes unless escaped with backslash) - * then returns list containing X unescaped (\x replaced by x) - * <li> 3) if of form <code>X</code> or <code>X, Y, ...</code> - * (where X, Y, ... each satisfy the constraint given in 2, or have no double quotes or commas in them) - * then returns the concatenation of rule 2 applied to non-empty X, Y, ... - * (if you want an empty string in a list, you must double quote it) - * <li> 4) for any other form X returns [ X ], including empty list for empty string - * <p> - * @see #unwrapOptionallyQuotedJavaStringList(String) - **/ - public static List<String> unwrapJsonishListIfPossible(String input) { - try { - return unwrapOptionallyQuotedJavaStringList(input); - } catch (Exception e) { - Exceptions.propagateIfFatal(e); - if (e instanceof IllegalArgumentException) { - if (log.isDebugEnabled()) - log.debug("Unable to parse JSON list '"+input+"' ("+e+"); treating as single-element string list"); - } else { - log.warn("Unable to parse JSON list '"+input+"' ("+e+"); treating as single-element string list", e); - } - return MutableList.of(input); - } - } - - /** as {@link #unwrapJsonishListIfPossible(String)} but throwing errors - * if something which looks like a string or set of brackets is not well-formed - * (this does the work for that method) - * @throws IllegalArgumentException if looks to have quoted list or surrounding brackets but they are not syntactically valid */ - public static List<String> unwrapOptionallyQuotedJavaStringList(String input) { - if (input==null) return null; - MutableList<String> result = MutableList.of(); - String i1 = input.trim(); - - boolean inBrackets = (i1.startsWith("[") && i1.endsWith("]")); - if (inBrackets) i1 = i1.substring(1, i1.length()-2).trim(); - - QuotedStringTokenizer qst = new QuotedStringTokenizer(i1, "\"", true, ",", false); - while (qst.hasMoreTokens()) { - String t = qst.nextToken().trim(); - if (isWrappedInDoubleQuotes(t)) - result.add(unwrapJavaString(t)); - else { - if (inBrackets && (t.indexOf('[')>=0 || t.indexOf(']')>=0)) - throw new IllegalArgumentException("Literal square brackets must be quoted, in element '"+t+"'"); - result.add(t.trim()); - } - } - - return result; - } - } - - private static void appendEscaped(Appendable out, char c) throws IOException { - out.append('\\'); - out.append(c); - } - private static String applyUnquoteAndUnescape(String s, String mode, boolean allowMultipleQuotes) { - StringBuilder result = new StringBuilder(); - boolean escaped = false; - boolean quoted = false; - for (int i=0; i<s.length(); i++) { - char c = s.charAt(i); - if (!quoted) { - assert (i==0 || allowMultipleQuotes); - assert !escaped; - if (c=='"') quoted = true; - else if (!allowMultipleQuotes) - throw new IllegalArgumentException("String '"+s+"' is not a valid "+mode+" string (must start with double quote)"); - else result.append(c); - } else { - if (escaped) { - if (c=='\\' || c=='"' || c=='\'') result.append(c); - else if (c=='n') result.append('\n'); - else if (c=='t') result.append('\t'); - else if (c=='r') result.append('\r'); - else throw new IllegalArgumentException("String '"+s+"' is not a valid "+mode+" string (unsupported escape char '"+c+"' at position "+i+")"); - escaped = false; - } else { - if (c=='\\') escaped = true; - else if (c=='\"') { - quoted = false; - if (!allowMultipleQuotes && i<s.length()-1) - throw new IllegalArgumentException("String '"+s+"' is not a valid "+mode+" string (unescaped interior double quote at position "+i+")"); - } else result.append(c); - } - } - } - if (quoted) - throw new IllegalArgumentException("String '"+s+"' is not a valid "+mode+" string (unterminated string)"); - assert !escaped; - return result.toString(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/cf2f7a93/utils/common/src/main/java/brooklyn/util/text/StringFunctions.java ---------------------------------------------------------------------- diff --git a/utils/common/src/main/java/brooklyn/util/text/StringFunctions.java b/utils/common/src/main/java/brooklyn/util/text/StringFunctions.java deleted file mode 100644 index 69cf4ae..0000000 --- a/utils/common/src/main/java/brooklyn/util/text/StringFunctions.java +++ /dev/null @@ -1,157 +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 javax.annotation.Nullable; - -import com.google.common.base.CaseFormat; -import com.google.common.base.CharMatcher; -import com.google.common.base.Function; -import com.google.common.base.Functions; -import com.google.common.base.Preconditions; - -public class StringFunctions { - - public static Function<String,String> append(final String suffix) { - return new Function<String, String>() { - @Override - @Nullable - public String apply(@Nullable String input) { - if (input==null) return null; - return input + suffix; - } - }; - } - - public static Function<String,String> prepend(final String prefix) { - return new Function<String, String>() { - @Override - @Nullable - public String apply(@Nullable String input) { - if (input==null) return null; - return prefix + input; - } - }; - } - - /** given e.g. "hello %s" returns a function which will insert a string into that pattern */ - public static Function<Object, String> formatter(final String pattern) { - return new Function<Object, String>() { - public String apply(@Nullable Object input) { - return String.format(pattern, input); - } - }; - } - - /** given e.g. "hello %s %s" returns a function which will insert an array of two strings into that pattern */ - public static Function<Object[], String> formatterForArray(final String pattern) { - return new Function<Object[], String>() { - public String apply(@Nullable Object[] input) { - return String.format(pattern, input); - } - }; - } - - /** joins the given objects in a collection as a toString with the given separator */ - public static Function<Iterable<?>, String> joiner(final String separator) { - return new Function<Iterable<?>, String>() { - public String apply(@Nullable Iterable<?> input) { - return Strings.join(input, separator); - } - }; - } - - /** joins the given objects as a toString with the given separator, but expecting an array of objects, not a collection */ - public static Function<Object[], String> joinerForArray(final String separator) { - return new Function<Object[], String>() { - public String apply(@Nullable Object[] input) { - if (input == null) return Strings.EMPTY; - return Strings.join(input, separator); - } - }; - } - - /** provided here as a convenience; prefer {@link Functions#toStringFunction()} */ - public static Function<Object,String> toStringFunction() { - return Functions.toStringFunction(); - } - - /** returns function which gives length of input, with -1 for nulls */ - public static Function<String,Integer> length() { - return new Function<String,Integer>() { - @Override - public Integer apply(@Nullable String input) { - if (input == null) return -1; - return input.length(); - } - }; - } - - /** Surrounds an input string with the given prefix and suffix */ - public static Function<String,String> surround(final String prefix, final String suffix) { - Preconditions.checkNotNull(prefix); - Preconditions.checkNotNull(suffix); - return new Function<String,String>() { - @Override - public String apply(@Nullable String input) { - if (input == null) return null; - return prefix+input+suffix; - } - }; - } - - public static Function<String, String> trim() { - return new Function<String, String>() { - @Override - public String apply(@Nullable String input) { - if (input == null) return null; - if (Strings.isBlank(input)) return Strings.EMPTY; - return CharMatcher.BREAKING_WHITESPACE.trimFrom(input); - } - }; - } - - public static Function<String, String> toLowerCase() { - return new Function<String, String>() { - @Override - public String apply(String input) { - return input.toLowerCase(); - } - }; - } - - public static Function<String, String> toUpperCase() { - return new Function<String, String>() { - @Override - public String apply(String input) { - return input.toUpperCase(); - } - }; - } - - public static Function<String, String> convertCase(final CaseFormat src, final CaseFormat target) { - return new Function<String, String>() { - @Override - public String apply(String input) { - return src.to(target, input); - } - }; - } - -}
