/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004-2008], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program is distributed * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.util; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.text.CharacterIterator; import java.text.NumberFormat; import java.text.StringCharacterIterator; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; public class StringUtil { /** * @param source The source string to perform replacements on. * @param find The substring to find in source. * @param replace The string to replace 'find' within source * @return The source string, with all occurrences of 'find' replaced with 'replace' */ public static String replace(String source, String find, String replace) { if (source == null || find == null || replace == null) { return source; } int sourceLen = source.length(); int findLen = find.length(); if (sourceLen == 0 || findLen == 0) { return source; } StringBuffer buffer = new StringBuffer(); int idx, fromIndex; for (fromIndex = 0; (idx = source.indexOf(find, fromIndex)) != -1; fromIndex = idx + findLen) { buffer.append(source.substring(fromIndex, idx)); buffer.append(replace); } if (fromIndex == 0) { return source; } buffer.append(source.substring(fromIndex)); return buffer.toString(); } /** * @param source The source string to perform replacements on. * @param find The substring to find in source. * @return The source string, with all occurrences of 'find' removed */ public static String remove(String source, String find) { if (source == null || find == null) { return source; } String retVal = null; int sourceLen = source.length(); int findLen = find.length(); StringBuffer remove = new StringBuffer(source); try { if (source != null && sourceLen > 0 && find != null && findLen > 0) { int fromIndex, idx; for (fromIndex = 0, idx=0; (fromIndex = source.indexOf(find, idx)) != -1; idx = fromIndex + findLen) { remove.delete(fromIndex, findLen + fromIndex); } retVal = remove.toString(); } } catch (Exception e) { // XXX This should never happen. // O'RLY? e.printStackTrace(); retVal = null; } return retVal; } /** * Print out everything in an Iterator in a user-friendly string format. * * @param i An iterator to print out. * @param delim The delimiter to use between elements. * @return The Iterator's elements in a user-friendly string format. */ public static String iteratorToString(Iterator i, String delim) { return iteratorToString(i, delim, ""); } /** * Print out everything in an Iterator in a user-friendly string format. * * @param i An iterator to print out. * @param delim The delimiter to use between elements. * @param quoteChar The character to quote each element with. * @return The Iterator's elements in a user-friendly string format. */ public static String iteratorToString(Iterator i, String delim, String quoteChar) { Object elt = null; StringBuffer rstr = new StringBuffer(); String s; while (i.hasNext()) { if (rstr.length() > 0) { rstr.append(delim); } elt = i.next(); if (elt == null) { rstr.append("NULL"); } else { s = elt.toString(); if (quoteChar != null) { rstr.append(quoteChar).append(s).append(quoteChar); } else { rstr.append(s); } } } return rstr.toString(); } /** * Print out a List in a user-friendly string format. * * @param list A List to print out. * @param delim The delimiter to use between elements. * @return The List in a user-friendly string format. */ public static String listToString(List list, String delim) { if (list == null) { return "NULL"; } Iterator i = list.iterator(); return iteratorToString(i, delim, null); } /** * Print out a List in a user-friendly string format. * * @param list A List to print out. * @return The List in a user-friendly string format. */ public static String listToString(List list) { return listToString(list, ","); } /** * Print out an array as a String */ public static String arrayToString(Object[] array) { return arrayToString(array, ','); } /** * Print out an array as a String. * * XXX: Isn't this the same as ArrayUtil.toString()? */ public static String arrayToString(boolean[] array) { if (array == null) { return "null"; } String rstr = ""; char delim = ','; for (int i=0; i<array.length; i++) { if (i > 0) { rstr += delim; } rstr += array[i]; } return rstr; } /** * Print out an array as a String * @param array The array to print out * @param delim The delimiter to use between elements. */ public static String arrayToString(Object[] array, char delim) { if (array == null) { return "null"; } String rstr = ""; for (int i=0; i<array.length; i++) { if (i>0) { rstr += delim; } rstr += array[i]; } return rstr; } /** * Print out an array as a String */ public static String arrayToString(int[] array) { if (array == null) { return "null"; } String rstr = ""; for (int i=0; i<array.length; i++) { if (i > 0) { rstr += ","; } rstr += array[i]; } return rstr; } /** * Create a string formulated by inserting a delimiter in between * consecutive array elements. * * @param objs List of objects to implode (elements may not be null) * @param delim String to place inbetween elements * @return A string with objects in the list seperated by delim */ public static String implode(List objs, String delim) { StringBuffer buf = new StringBuffer(); int size = objs.size(); for (int i=0; i<size - 1; i++) { buf.append(objs.get(i).toString() + delim); } if (size != 0) { buf.append(objs.get(size - 1).toString()); } return buf.toString(); } /** * Split a string on delimiter boundaries, and place each element * into an array. * * @param s String to split up * @param delim Delimiting token, ala StringTokenizer * @return an ArrayList comprised of elements split by the tokenizing */ public static List<String> explode(String s, String delim) { ArrayList<String> res = new ArrayList<String>(); if (s != null) { StringTokenizer tok = new StringTokenizer(s, delim); while(tok.hasMoreTokens()) { res.add(tok.nextToken()); } } return res; } /* the following code..explodeQuoted is based on code from bash-4.0/subst.c * XXX can be optimized if needed, but functionality first. */ private static final char QUOTE = '\''; private static final char DOUBLEQUOTE = '"'; private static final char BACKSLASH = '\\'; private static boolean spctabnl(char c) { return (c == ' ') || (c == '\t') || (c == '\n'); } private static int skipSingleQuoted(String str, int slen, int sind) { int i = sind; while ((i < slen) && str.charAt(i) != QUOTE) { i++; } if (i < slen) { i++; } return i; } private static int skipDoubleQuoted(String str, int slen, int sind) { int i = sind; int pass_next = 0; while (i < slen) { char c = str.charAt(i); if (pass_next != 0) { pass_next = 0; i++; } else if (c == BACKSLASH) { pass_next++; i++; } else if (c != DOUBLEQUOTE) { i++; } else { break; } } if (i < slen) { i++; } return i; } private static String extractDoubleQuoted(String str) { int slen = str.length(); int i=0; int pass_next=0; int dquote=0; StringBuffer temp = new StringBuffer(slen); while (i < slen) { char c = str.charAt(i); if (pass_next != 0) { if (dquote == 0) { temp.append('\\'); } pass_next = 0; temp.append(c); } else if (c == BACKSLASH) { pass_next++; } else if (c != DOUBLEQUOTE) { temp.append(c); } else { dquote ^= 1; } i++; } if (dquote != 0) { throw new IllegalArgumentException("Unbalanced quotation marks"); } return temp.toString(); } private static String extractSingleQuoted(String str) { char first = str.charAt(0); char last = str.charAt(str.length()-1); if (first == QUOTE) { if (last == QUOTE) { return str.substring(1, str.length()-1); } else { throw new IllegalArgumentException("Unbalanced quotation marks"); } } else { return str; } } public static String extractQuoted(String str) { if (str.length() == 0) { return str; } if (str.charAt(0) == QUOTE) { str = extractSingleQuoted(str); } else if (str.charAt(0) == DOUBLEQUOTE) { str = extractDoubleQuoted(str); } return str; } private static String[] splitCommandLine(String str, boolean extract) { List list = new ArrayList(); int slen; char c; int i=0; int tokstart=0; if ((str == null) || ((str = str.trim()).length() == 0)) { return new String[0]; } slen = str.length(); while (true) { if (i < slen) { c = str.charAt(i); } else { c = '\0'; } if (c == BACKSLASH) { i++; if (i < slen) { i++; } } else if (c == QUOTE) { i = skipSingleQuoted(str, slen, ++i); } else if (c == DOUBLEQUOTE) { i = skipDoubleQuoted(str, slen, ++i); } else if ((c == '\0') || spctabnl(c)) { String token = str.substring(tokstart, i); if (extract) { token = extractQuoted(token); } list.add(token); while ((i < slen) && spctabnl(str.charAt(i))) { i++; } if (i < slen) { tokstart = i; } else { break; } } else { i++; } } return (String[])list.toArray(new String[list.size()]); } /** * Split a string up by whitespace, taking into account quoted * subcomponents. If there is an uneven number of quotes, a * parse error will be thrown. * * @param arg String to parse * @return an array of elements, the argument was split into * @throws IllegalArgumentException indicating there was a quoting error */ public static String[] explodeQuoted(String arg) { return splitCommandLine(arg, true); } /** * Remove a prefix from a string. If value starts with prefix, it will be * removed, the resultant string is trimmed and returned. * @return If value starts with prefix, then this method returns value with * the prefix removed, and the resultant string trimmed. If value does not * start with prefix, value is returned as-is. */ public static String removePrefix(String value, String prefix) { if (!value.startsWith(prefix)) { return value; } return value.substring(prefix.length()).trim(); } /** * @return the plural of word. This is done by applying a few * rules. These cover most (but not all) cases: * 1. If the word ends in s, ss, x, o, or ch, append es * 2. If the word ends in a consonant followed by y, drop the y * and add ies * 3. Append an s and call it a day. * The ultimate references is at http://en.wikipedia.org/wiki/English_plural */ public static String pluralize (String word) { if (word.endsWith("s") || word.endsWith("x") || word.endsWith("o") || word.endsWith("ch")) { if(word.endsWith("Metrics")){ return word; } return word + "es"; } if (word.endsWith("y")) { // Odd case to avoid StringIndexOutOfBounds later if (word.length() == 1) { return word; } // Check next-to-last letter char next2last = word.charAt(word.length()-2); if (next2last != 'a' && next2last != 'e' && next2last != 'i' && next2last != 'o' && next2last != 'u' && next2last != 'y') { return word.substring(0, word.length()-1) + "ies"; } } return word + "s"; } /** * @return The stack trace for the given Throwable as a String. */ public static String getStackTrace(Throwable t) { if (t == null) { return "THROWABLE-WAS-NULL (at " + getStackTrace(new Exception()) + ")"; } try { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); Throwable cause = t.getCause(); if (cause != null) { return sw.toString() + getStackTrace(cause); } return sw.toString(); } catch(Exception e) { return "\n\nStringUtil.getStackTrace " + "GENERATED EXCEPTION: '" + e.toString() + "' \n\n"; } } /** * @param s A string that might contain unix-style path separators. * @return The correct path for this platform (i.e, if win32, replace / with \). */ public static String normalizePath(String s) { return StringUtil.replace(s, "/", File.separator); } public static String formatDuration(long duration) { return formatDuration(duration, 0, false); } public static String formatDuration(long duration, int scale, boolean minDigits) { long hours, mins; int digits; double millis; hours = duration / 3600000; duration -= hours * 3600000; mins = duration / 60000; duration -= mins * 60000; millis = (double)duration / 1000; StringBuffer buf = new StringBuffer(); if (hours > 0 || minDigits == false) { buf.append(hours < 10 && minDigits == false ? "0" + hours : String.valueOf(hours)).append(':'); minDigits = false; } if (mins > 0 || minDigits == false) { buf.append(mins < 10 && minDigits == false ? "0" + mins : String.valueOf(mins)).append(':'); minDigits = false; } // Format seconds and milliseconds NumberFormat fmt = NumberFormat.getInstance(); digits = (minDigits == false || (scale == 0 && millis >= 9.5) ? 2 : 1); fmt.setMinimumIntegerDigits(digits); fmt.setMaximumIntegerDigits(2); // Max of 2 fmt.setMinimumFractionDigits(0); // Don't need any fmt.setMaximumFractionDigits(scale); buf.append(fmt.format(millis)); return buf.toString(); } public static String repeatChars(char c, int nTimes) { char[] arr = new char[nTimes]; for (int i=0; i<nTimes; i++) { arr[i] = c; } return new String(arr); } /** Capitalizes the first letter of str. * * @param str The string to capitalize. * @return A new string that is <code>str</code> capitalized. * Returns <code>null</code> if str is null. */ public static String capitalize(String str) { if (str == null) { return null; } else if (str.trim().equals("")) { return str; } String result = str.substring(0,1).toUpperCase() + str.substring(1, str.length()); return result; } /** * Return a variant of 'str' which contains the beginning and end of * the string, but places '...' in the middle to limit the maximum * length of the string. * * @param str String to shorten * @param maxLen Maximum length of the returned string */ public static String dotProximate(String str, int maxLen) { int strLen = str.length(); int toChop; if (strLen <= maxLen) return str; if (maxLen <= 3) return "..."; toChop = strLen - maxLen + 3; return str.substring(0, strLen / 2 - toChop / 2 - 1) + "..." + str.substring(strLen / 2 + toChop / 2); } /** * Do a case-insensitive search for a substring */ public static boolean stringDoesNotExist(String source, String sub) { return (sub != null) && (sub.length() > 0) && (source.toLowerCase().indexOf(sub.toLowerCase()) < 0); } /** * Escapes a minimal set of metacharacters with their * regular expression escape codes. */ public static String escapeForRegex(String source, boolean wildcard) { if (source == null) { return null; } StringBuilder result = new StringBuilder(); StringCharacterIterator iterator = new StringCharacterIterator(source); char character = iterator.current(); while (character != CharacterIterator.DONE) { // All literals need to have backslashes doubled. if (character == '.') { result.append("\\."); } else if (character == '\\') { result.append("\\\\"); } else if (character == '?') { result.append("\\?"); } else if (character == '+') { result.append("\\+"); } else if (character == '{') { result.append("\\{"); } else if (character == '}') { result.append("\\}"); } else if (character == '[') { result.append("\\["); } else if (character == ']') { result.append("\\]"); } else if (character == '(') { result.append("\\("); } else if (character == ')') { result.append("\\)"); } else if (character == '^') { result.append("\\^"); } else if (character == '$') { result.append("\\$"); } else if (character == '|') { result.append("\\|"); } else if (character == '*') { if (wildcard) { result.append(".*"); } else { result.append("\\*"); } } else { //the char is not a special one //add it to the result as is result.append(character); } character = iterator.next(); } return result.toString(); } public static boolean isNullOrEmpty(String str) { return str == null || str.trim().length() == 0; } }