[120] | 1 | /** |
---|
| 2 | * Licensed to the Apache Software Foundation (ASF) under one |
---|
| 3 | * or more contributor license agreements. See the NOTICE file |
---|
| 4 | * distributed with this work for additional information |
---|
| 5 | * regarding copyright ownership. The ASF licenses this file |
---|
| 6 | * to you under the Apache License, Version 2.0 (the |
---|
| 7 | * "License"); you may not use this file except in compliance |
---|
| 8 | * with the License. You may obtain a copy of the License at |
---|
| 9 | * |
---|
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
---|
| 11 | * |
---|
| 12 | * Unless required by applicable law or agreed to in writing, software |
---|
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
---|
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
| 15 | * See the License for the specific language governing permissions and |
---|
| 16 | * limitations under the License. |
---|
| 17 | */ |
---|
| 18 | |
---|
| 19 | package org.apache.hadoop.util; |
---|
| 20 | |
---|
| 21 | import java.io.PrintWriter; |
---|
| 22 | import java.io.StringWriter; |
---|
| 23 | import java.net.InetAddress; |
---|
| 24 | import java.net.URI; |
---|
| 25 | import java.net.URISyntaxException; |
---|
| 26 | import java.net.UnknownHostException; |
---|
| 27 | import java.text.DateFormat; |
---|
| 28 | import java.text.DecimalFormat; |
---|
| 29 | import java.text.NumberFormat; |
---|
| 30 | import java.util.Locale; |
---|
| 31 | import java.util.ArrayList; |
---|
| 32 | import java.util.Arrays; |
---|
| 33 | import java.util.Date; |
---|
| 34 | import java.util.List; |
---|
| 35 | import java.util.StringTokenizer; |
---|
| 36 | import java.util.Collection; |
---|
| 37 | |
---|
| 38 | import org.apache.hadoop.fs.*; |
---|
| 39 | |
---|
| 40 | /** |
---|
| 41 | * General string utils |
---|
| 42 | */ |
---|
| 43 | public class StringUtils { |
---|
| 44 | |
---|
| 45 | private static final DecimalFormat decimalFormat; |
---|
| 46 | static { |
---|
| 47 | NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.ENGLISH); |
---|
| 48 | decimalFormat = (DecimalFormat) numberFormat; |
---|
| 49 | decimalFormat.applyPattern("#.##"); |
---|
| 50 | } |
---|
| 51 | |
---|
| 52 | /** |
---|
| 53 | * Make a string representation of the exception. |
---|
| 54 | * @param e The exception to stringify |
---|
| 55 | * @return A string with exception name and call stack. |
---|
| 56 | */ |
---|
| 57 | public static String stringifyException(Throwable e) { |
---|
| 58 | StringWriter stm = new StringWriter(); |
---|
| 59 | PrintWriter wrt = new PrintWriter(stm); |
---|
| 60 | e.printStackTrace(wrt); |
---|
| 61 | wrt.close(); |
---|
| 62 | return stm.toString(); |
---|
| 63 | } |
---|
| 64 | |
---|
| 65 | /** |
---|
| 66 | * Given a full hostname, return the word upto the first dot. |
---|
| 67 | * @param fullHostname the full hostname |
---|
| 68 | * @return the hostname to the first dot |
---|
| 69 | */ |
---|
| 70 | public static String simpleHostname(String fullHostname) { |
---|
| 71 | int offset = fullHostname.indexOf('.'); |
---|
| 72 | if (offset != -1) { |
---|
| 73 | return fullHostname.substring(0, offset); |
---|
| 74 | } |
---|
| 75 | return fullHostname; |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | private static DecimalFormat oneDecimal = new DecimalFormat("0.0"); |
---|
| 79 | |
---|
| 80 | /** |
---|
| 81 | * Given an integer, return a string that is in an approximate, but human |
---|
| 82 | * readable format. |
---|
| 83 | * It uses the bases 'k', 'm', and 'g' for 1024, 1024**2, and 1024**3. |
---|
| 84 | * @param number the number to format |
---|
| 85 | * @return a human readable form of the integer |
---|
| 86 | */ |
---|
| 87 | public static String humanReadableInt(long number) { |
---|
| 88 | long absNumber = Math.abs(number); |
---|
| 89 | double result = number; |
---|
| 90 | String suffix = ""; |
---|
| 91 | if (absNumber < 1024) { |
---|
| 92 | // nothing |
---|
| 93 | } else if (absNumber < 1024 * 1024) { |
---|
| 94 | result = number / 1024.0; |
---|
| 95 | suffix = "k"; |
---|
| 96 | } else if (absNumber < 1024 * 1024 * 1024) { |
---|
| 97 | result = number / (1024.0 * 1024); |
---|
| 98 | suffix = "m"; |
---|
| 99 | } else { |
---|
| 100 | result = number / (1024.0 * 1024 * 1024); |
---|
| 101 | suffix = "g"; |
---|
| 102 | } |
---|
| 103 | return oneDecimal.format(result) + suffix; |
---|
| 104 | } |
---|
| 105 | |
---|
| 106 | /** |
---|
| 107 | * Format a percentage for presentation to the user. |
---|
| 108 | * @param done the percentage to format (0.0 to 1.0) |
---|
| 109 | * @param digits the number of digits past the decimal point |
---|
| 110 | * @return a string representation of the percentage |
---|
| 111 | */ |
---|
| 112 | public static String formatPercent(double done, int digits) { |
---|
| 113 | DecimalFormat percentFormat = new DecimalFormat("0.00%"); |
---|
| 114 | double scale = Math.pow(10.0, digits+2); |
---|
| 115 | double rounded = Math.floor(done * scale); |
---|
| 116 | percentFormat.setDecimalSeparatorAlwaysShown(false); |
---|
| 117 | percentFormat.setMinimumFractionDigits(digits); |
---|
| 118 | percentFormat.setMaximumFractionDigits(digits); |
---|
| 119 | return percentFormat.format(rounded / scale); |
---|
| 120 | } |
---|
| 121 | |
---|
| 122 | /** |
---|
| 123 | * Given an array of strings, return a comma-separated list of its elements. |
---|
| 124 | * @param strs Array of strings |
---|
| 125 | * @return Empty string if strs.length is 0, comma separated list of strings |
---|
| 126 | * otherwise |
---|
| 127 | */ |
---|
| 128 | |
---|
| 129 | public static String arrayToString(String[] strs) { |
---|
| 130 | if (strs.length == 0) { return ""; } |
---|
| 131 | StringBuffer sbuf = new StringBuffer(); |
---|
| 132 | sbuf.append(strs[0]); |
---|
| 133 | for (int idx = 1; idx < strs.length; idx++) { |
---|
| 134 | sbuf.append(","); |
---|
| 135 | sbuf.append(strs[idx]); |
---|
| 136 | } |
---|
| 137 | return sbuf.toString(); |
---|
| 138 | } |
---|
| 139 | |
---|
| 140 | /** |
---|
| 141 | * Given an array of bytes it will convert the bytes to a hex string |
---|
| 142 | * representation of the bytes |
---|
| 143 | * @param bytes |
---|
| 144 | * @param start start index, inclusively |
---|
| 145 | * @param end end index, exclusively |
---|
| 146 | * @return hex string representation of the byte array |
---|
| 147 | */ |
---|
| 148 | public static String byteToHexString(byte[] bytes, int start, int end) { |
---|
| 149 | if (bytes == null) { |
---|
| 150 | throw new IllegalArgumentException("bytes == null"); |
---|
| 151 | } |
---|
| 152 | StringBuilder s = new StringBuilder(); |
---|
| 153 | for(int i = start; i < end; i++) { |
---|
| 154 | s.append(String.format("%02x", bytes[i])); |
---|
| 155 | } |
---|
| 156 | return s.toString(); |
---|
| 157 | } |
---|
| 158 | |
---|
| 159 | /** Same as byteToHexString(bytes, 0, bytes.length). */ |
---|
| 160 | public static String byteToHexString(byte bytes[]) { |
---|
| 161 | return byteToHexString(bytes, 0, bytes.length); |
---|
| 162 | } |
---|
| 163 | |
---|
| 164 | /** |
---|
| 165 | * Given a hexstring this will return the byte array corresponding to the |
---|
| 166 | * string |
---|
| 167 | * @param hex the hex String array |
---|
| 168 | * @return a byte array that is a hex string representation of the given |
---|
| 169 | * string. The size of the byte array is therefore hex.length/2 |
---|
| 170 | */ |
---|
| 171 | public static byte[] hexStringToByte(String hex) { |
---|
| 172 | byte[] bts = new byte[hex.length() / 2]; |
---|
| 173 | for (int i = 0; i < bts.length; i++) { |
---|
| 174 | bts[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16); |
---|
| 175 | } |
---|
| 176 | return bts; |
---|
| 177 | } |
---|
| 178 | /** |
---|
| 179 | * |
---|
| 180 | * @param uris |
---|
| 181 | */ |
---|
| 182 | public static String uriToString(URI[] uris){ |
---|
| 183 | if (uris == null) { |
---|
| 184 | return null; |
---|
| 185 | } |
---|
| 186 | StringBuffer ret = new StringBuffer(uris[0].toString()); |
---|
| 187 | for(int i = 1; i < uris.length;i++){ |
---|
| 188 | ret.append(","); |
---|
| 189 | ret.append(uris[i].toString()); |
---|
| 190 | } |
---|
| 191 | return ret.toString(); |
---|
| 192 | } |
---|
| 193 | |
---|
| 194 | /** |
---|
| 195 | * |
---|
| 196 | * @param str |
---|
| 197 | */ |
---|
| 198 | public static URI[] stringToURI(String[] str){ |
---|
| 199 | if (str == null) |
---|
| 200 | return null; |
---|
| 201 | URI[] uris = new URI[str.length]; |
---|
| 202 | for (int i = 0; i < str.length;i++){ |
---|
| 203 | try{ |
---|
| 204 | uris[i] = new URI(str[i]); |
---|
| 205 | }catch(URISyntaxException ur){ |
---|
| 206 | System.out.println("Exception in specified URI's " + StringUtils.stringifyException(ur)); |
---|
| 207 | //making sure its asssigned to null in case of an error |
---|
| 208 | uris[i] = null; |
---|
| 209 | } |
---|
| 210 | } |
---|
| 211 | return uris; |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | /** |
---|
| 215 | * |
---|
| 216 | * @param str |
---|
| 217 | */ |
---|
| 218 | public static Path[] stringToPath(String[] str){ |
---|
| 219 | if (str == null) { |
---|
| 220 | return null; |
---|
| 221 | } |
---|
| 222 | Path[] p = new Path[str.length]; |
---|
| 223 | for (int i = 0; i < str.length;i++){ |
---|
| 224 | p[i] = new Path(str[i]); |
---|
| 225 | } |
---|
| 226 | return p; |
---|
| 227 | } |
---|
| 228 | /** |
---|
| 229 | * |
---|
| 230 | * Given a finish and start time in long milliseconds, returns a |
---|
| 231 | * String in the format Xhrs, Ymins, Z sec, for the time difference between two times. |
---|
| 232 | * If finish time comes before start time then negative valeus of X, Y and Z wil return. |
---|
| 233 | * |
---|
| 234 | * @param finishTime finish time |
---|
| 235 | * @param startTime start time |
---|
| 236 | */ |
---|
| 237 | public static String formatTimeDiff(long finishTime, long startTime){ |
---|
| 238 | long timeDiff = finishTime - startTime; |
---|
| 239 | return formatTime(timeDiff); |
---|
| 240 | } |
---|
| 241 | |
---|
| 242 | /** |
---|
| 243 | * |
---|
| 244 | * Given the time in long milliseconds, returns a |
---|
| 245 | * String in the format Xhrs, Ymins, Z sec. |
---|
| 246 | * |
---|
| 247 | * @param timeDiff The time difference to format |
---|
| 248 | */ |
---|
| 249 | public static String formatTime(long timeDiff){ |
---|
| 250 | StringBuffer buf = new StringBuffer(); |
---|
| 251 | long hours = timeDiff / (60*60*1000); |
---|
| 252 | long rem = (timeDiff % (60*60*1000)); |
---|
| 253 | long minutes = rem / (60*1000); |
---|
| 254 | rem = rem % (60*1000); |
---|
| 255 | long seconds = rem / 1000; |
---|
| 256 | |
---|
| 257 | if (hours != 0){ |
---|
| 258 | buf.append(hours); |
---|
| 259 | buf.append("hrs, "); |
---|
| 260 | } |
---|
| 261 | if (minutes != 0){ |
---|
| 262 | buf.append(minutes); |
---|
| 263 | buf.append("mins, "); |
---|
| 264 | } |
---|
| 265 | // return "0sec if no difference |
---|
| 266 | buf.append(seconds); |
---|
| 267 | buf.append("sec"); |
---|
| 268 | return buf.toString(); |
---|
| 269 | } |
---|
| 270 | /** |
---|
| 271 | * Formats time in ms and appends difference (finishTime - startTime) |
---|
| 272 | * as returned by formatTimeDiff(). |
---|
| 273 | * If finish time is 0, empty string is returned, if start time is 0 |
---|
| 274 | * then difference is not appended to return value. |
---|
| 275 | * @param dateFormat date format to use |
---|
| 276 | * @param finishTime fnish time |
---|
| 277 | * @param startTime start time |
---|
| 278 | * @return formatted value. |
---|
| 279 | */ |
---|
| 280 | public static String getFormattedTimeWithDiff(DateFormat dateFormat, |
---|
| 281 | long finishTime, long startTime){ |
---|
| 282 | StringBuffer buf = new StringBuffer(); |
---|
| 283 | if (0 != finishTime) { |
---|
| 284 | buf.append(dateFormat.format(new Date(finishTime))); |
---|
| 285 | if (0 != startTime){ |
---|
| 286 | buf.append(" (" + formatTimeDiff(finishTime , startTime) + ")"); |
---|
| 287 | } |
---|
| 288 | } |
---|
| 289 | return buf.toString(); |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | /** |
---|
| 293 | * Returns an arraylist of strings. |
---|
| 294 | * @param str the comma seperated string values |
---|
| 295 | * @return the arraylist of the comma seperated string values |
---|
| 296 | */ |
---|
| 297 | public static String[] getStrings(String str){ |
---|
| 298 | Collection<String> values = getStringCollection(str); |
---|
| 299 | if(values.size() == 0) { |
---|
| 300 | return null; |
---|
| 301 | } |
---|
| 302 | return values.toArray(new String[values.size()]); |
---|
| 303 | } |
---|
| 304 | |
---|
| 305 | /** |
---|
| 306 | * Returns a collection of strings. |
---|
| 307 | * @param str comma seperated string values |
---|
| 308 | * @return an <code>ArrayList</code> of string values |
---|
| 309 | */ |
---|
| 310 | public static Collection<String> getStringCollection(String str){ |
---|
| 311 | List<String> values = new ArrayList<String>(); |
---|
| 312 | if (str == null) |
---|
| 313 | return values; |
---|
| 314 | StringTokenizer tokenizer = new StringTokenizer (str,","); |
---|
| 315 | values = new ArrayList<String>(); |
---|
| 316 | while (tokenizer.hasMoreTokens()) { |
---|
| 317 | values.add(tokenizer.nextToken()); |
---|
| 318 | } |
---|
| 319 | return values; |
---|
| 320 | } |
---|
| 321 | |
---|
| 322 | final public static char COMMA = ','; |
---|
| 323 | final public static String COMMA_STR = ","; |
---|
| 324 | final public static char ESCAPE_CHAR = '\\'; |
---|
| 325 | |
---|
| 326 | /** |
---|
| 327 | * Split a string using the default separator |
---|
| 328 | * @param str a string that may have escaped separator |
---|
| 329 | * @return an array of strings |
---|
| 330 | */ |
---|
| 331 | public static String[] split(String str) { |
---|
| 332 | return split(str, ESCAPE_CHAR, COMMA); |
---|
| 333 | } |
---|
| 334 | |
---|
| 335 | /** |
---|
| 336 | * Split a string using the given separator |
---|
| 337 | * @param str a string that may have escaped separator |
---|
| 338 | * @param escapeChar a char that be used to escape the separator |
---|
| 339 | * @param separator a separator char |
---|
| 340 | * @return an array of strings |
---|
| 341 | */ |
---|
| 342 | public static String[] split( |
---|
| 343 | String str, char escapeChar, char separator) { |
---|
| 344 | if (str==null) { |
---|
| 345 | return null; |
---|
| 346 | } |
---|
| 347 | ArrayList<String> strList = new ArrayList<String>(); |
---|
| 348 | StringBuilder split = new StringBuilder(); |
---|
| 349 | int index = 0; |
---|
| 350 | while ((index = findNext(str, separator, escapeChar, index, split)) >= 0) { |
---|
| 351 | ++index; // move over the separator for next search |
---|
| 352 | strList.add(split.toString()); |
---|
| 353 | split.setLength(0); // reset the buffer |
---|
| 354 | } |
---|
| 355 | strList.add(split.toString()); |
---|
| 356 | // remove trailing empty split(s) |
---|
| 357 | int last = strList.size(); // last split |
---|
| 358 | while (--last>=0 && "".equals(strList.get(last))) { |
---|
| 359 | strList.remove(last); |
---|
| 360 | } |
---|
| 361 | return strList.toArray(new String[strList.size()]); |
---|
| 362 | } |
---|
| 363 | |
---|
| 364 | /** |
---|
| 365 | * Finds the first occurrence of the separator character ignoring the escaped |
---|
| 366 | * separators starting from the index. Note the substring between the index |
---|
| 367 | * and the position of the separator is passed. |
---|
| 368 | * @param str the source string |
---|
| 369 | * @param separator the character to find |
---|
| 370 | * @param escapeChar character used to escape |
---|
| 371 | * @param start from where to search |
---|
| 372 | * @param split used to pass back the extracted string |
---|
| 373 | */ |
---|
| 374 | public static int findNext(String str, char separator, char escapeChar, |
---|
| 375 | int start, StringBuilder split) { |
---|
| 376 | int numPreEscapes = 0; |
---|
| 377 | for (int i = start; i < str.length(); i++) { |
---|
| 378 | char curChar = str.charAt(i); |
---|
| 379 | if (numPreEscapes == 0 && curChar == separator) { // separator |
---|
| 380 | return i; |
---|
| 381 | } else { |
---|
| 382 | split.append(curChar); |
---|
| 383 | numPreEscapes = (curChar == escapeChar) |
---|
| 384 | ? (++numPreEscapes) % 2 |
---|
| 385 | : 0; |
---|
| 386 | } |
---|
| 387 | } |
---|
| 388 | return -1; |
---|
| 389 | } |
---|
| 390 | |
---|
| 391 | /** |
---|
| 392 | * Escape commas in the string using the default escape char |
---|
| 393 | * @param str a string |
---|
| 394 | * @return an escaped string |
---|
| 395 | */ |
---|
| 396 | public static String escapeString(String str) { |
---|
| 397 | return escapeString(str, ESCAPE_CHAR, COMMA); |
---|
| 398 | } |
---|
| 399 | |
---|
| 400 | /** |
---|
| 401 | * Escape <code>charToEscape</code> in the string |
---|
| 402 | * with the escape char <code>escapeChar</code> |
---|
| 403 | * |
---|
| 404 | * @param str string |
---|
| 405 | * @param escapeChar escape char |
---|
| 406 | * @param charToEscape the char to be escaped |
---|
| 407 | * @return an escaped string |
---|
| 408 | */ |
---|
| 409 | public static String escapeString( |
---|
| 410 | String str, char escapeChar, char charToEscape) { |
---|
| 411 | return escapeString(str, escapeChar, new char[] {charToEscape}); |
---|
| 412 | } |
---|
| 413 | |
---|
| 414 | // check if the character array has the character |
---|
| 415 | private static boolean hasChar(char[] chars, char character) { |
---|
| 416 | for (char target : chars) { |
---|
| 417 | if (character == target) { |
---|
| 418 | return true; |
---|
| 419 | } |
---|
| 420 | } |
---|
| 421 | return false; |
---|
| 422 | } |
---|
| 423 | |
---|
| 424 | /** |
---|
| 425 | * @param charsToEscape array of characters to be escaped |
---|
| 426 | */ |
---|
| 427 | public static String escapeString(String str, char escapeChar, |
---|
| 428 | char[] charsToEscape) { |
---|
| 429 | if (str == null) { |
---|
| 430 | return null; |
---|
| 431 | } |
---|
| 432 | StringBuilder result = new StringBuilder(); |
---|
| 433 | for (int i=0; i<str.length(); i++) { |
---|
| 434 | char curChar = str.charAt(i); |
---|
| 435 | if (curChar == escapeChar || hasChar(charsToEscape, curChar)) { |
---|
| 436 | // special char |
---|
| 437 | result.append(escapeChar); |
---|
| 438 | } |
---|
| 439 | result.append(curChar); |
---|
| 440 | } |
---|
| 441 | return result.toString(); |
---|
| 442 | } |
---|
| 443 | |
---|
| 444 | /** |
---|
| 445 | * Unescape commas in the string using the default escape char |
---|
| 446 | * @param str a string |
---|
| 447 | * @return an unescaped string |
---|
| 448 | */ |
---|
| 449 | public static String unEscapeString(String str) { |
---|
| 450 | return unEscapeString(str, ESCAPE_CHAR, COMMA); |
---|
| 451 | } |
---|
| 452 | |
---|
| 453 | /** |
---|
| 454 | * Unescape <code>charToEscape</code> in the string |
---|
| 455 | * with the escape char <code>escapeChar</code> |
---|
| 456 | * |
---|
| 457 | * @param str string |
---|
| 458 | * @param escapeChar escape char |
---|
| 459 | * @param charToEscape the escaped char |
---|
| 460 | * @return an unescaped string |
---|
| 461 | */ |
---|
| 462 | public static String unEscapeString( |
---|
| 463 | String str, char escapeChar, char charToEscape) { |
---|
| 464 | return unEscapeString(str, escapeChar, new char[] {charToEscape}); |
---|
| 465 | } |
---|
| 466 | |
---|
| 467 | /** |
---|
| 468 | * @param charsToEscape array of characters to unescape |
---|
| 469 | */ |
---|
| 470 | public static String unEscapeString(String str, char escapeChar, |
---|
| 471 | char[] charsToEscape) { |
---|
| 472 | if (str == null) { |
---|
| 473 | return null; |
---|
| 474 | } |
---|
| 475 | StringBuilder result = new StringBuilder(str.length()); |
---|
| 476 | boolean hasPreEscape = false; |
---|
| 477 | for (int i=0; i<str.length(); i++) { |
---|
| 478 | char curChar = str.charAt(i); |
---|
| 479 | if (hasPreEscape) { |
---|
| 480 | if (curChar != escapeChar && !hasChar(charsToEscape, curChar)) { |
---|
| 481 | // no special char |
---|
| 482 | throw new IllegalArgumentException("Illegal escaped string " + str + |
---|
| 483 | " unescaped " + escapeChar + " at " + (i-1)); |
---|
| 484 | } |
---|
| 485 | // otherwise discard the escape char |
---|
| 486 | result.append(curChar); |
---|
| 487 | hasPreEscape = false; |
---|
| 488 | } else { |
---|
| 489 | if (hasChar(charsToEscape, curChar)) { |
---|
| 490 | throw new IllegalArgumentException("Illegal escaped string " + str + |
---|
| 491 | " unescaped " + curChar + " at " + i); |
---|
| 492 | } else if (curChar == escapeChar) { |
---|
| 493 | hasPreEscape = true; |
---|
| 494 | } else { |
---|
| 495 | result.append(curChar); |
---|
| 496 | } |
---|
| 497 | } |
---|
| 498 | } |
---|
| 499 | if (hasPreEscape ) { |
---|
| 500 | throw new IllegalArgumentException("Illegal escaped string " + str + |
---|
| 501 | ", not expecting " + escapeChar + " in the end." ); |
---|
| 502 | } |
---|
| 503 | return result.toString(); |
---|
| 504 | } |
---|
| 505 | |
---|
| 506 | /** |
---|
| 507 | * Return hostname without throwing exception. |
---|
| 508 | * @return hostname |
---|
| 509 | */ |
---|
| 510 | public static String getHostname() { |
---|
| 511 | try {return "" + InetAddress.getLocalHost();} |
---|
| 512 | catch(UnknownHostException uhe) {return "" + uhe;} |
---|
| 513 | } |
---|
| 514 | |
---|
| 515 | /** |
---|
| 516 | * Return a message for logging. |
---|
| 517 | * @param prefix prefix keyword for the message |
---|
| 518 | * @param msg content of the message |
---|
| 519 | * @return a message for logging |
---|
| 520 | */ |
---|
| 521 | private static String toStartupShutdownString(String prefix, String [] msg) { |
---|
| 522 | StringBuffer b = new StringBuffer(prefix); |
---|
| 523 | b.append("\n/************************************************************"); |
---|
| 524 | for(String s : msg) |
---|
| 525 | b.append("\n" + prefix + s); |
---|
| 526 | b.append("\n************************************************************/"); |
---|
| 527 | return b.toString(); |
---|
| 528 | } |
---|
| 529 | |
---|
| 530 | /** |
---|
| 531 | * Print a log message for starting up and shutting down |
---|
| 532 | * @param clazz the class of the server |
---|
| 533 | * @param args arguments |
---|
| 534 | * @param LOG the target log object |
---|
| 535 | */ |
---|
| 536 | public static void startupShutdownMessage(Class<?> clazz, String[] args, |
---|
| 537 | final org.apache.commons.logging.Log LOG) { |
---|
| 538 | final String hostname = getHostname(); |
---|
| 539 | final String classname = clazz.getSimpleName(); |
---|
| 540 | LOG.info( |
---|
| 541 | toStartupShutdownString("STARTUP_MSG: ", new String[] { |
---|
| 542 | "Starting " + classname, |
---|
| 543 | " host = " + hostname, |
---|
| 544 | " args = " + Arrays.asList(args), |
---|
| 545 | " version = " + VersionInfo.getVersion(), |
---|
| 546 | " build = " + VersionInfo.getUrl() + " -r " |
---|
| 547 | + VersionInfo.getRevision() |
---|
| 548 | + "; compiled by '" + VersionInfo.getUser() |
---|
| 549 | + "' on " + VersionInfo.getDate()} |
---|
| 550 | ) |
---|
| 551 | ); |
---|
| 552 | |
---|
| 553 | Runtime.getRuntime().addShutdownHook(new Thread() { |
---|
| 554 | public void run() { |
---|
| 555 | LOG.info(toStartupShutdownString("SHUTDOWN_MSG: ", new String[]{ |
---|
| 556 | "Shutting down " + classname + " at " + hostname})); |
---|
| 557 | } |
---|
| 558 | }); |
---|
| 559 | } |
---|
| 560 | |
---|
| 561 | /** |
---|
| 562 | * The traditional binary prefixes, kilo, mega, ..., exa, |
---|
| 563 | * which can be represented by a 64-bit integer. |
---|
| 564 | * TraditionalBinaryPrefix symbol are case insensitive. |
---|
| 565 | */ |
---|
| 566 | public static enum TraditionalBinaryPrefix { |
---|
| 567 | KILO(1024), |
---|
| 568 | MEGA(KILO.value << 10), |
---|
| 569 | GIGA(MEGA.value << 10), |
---|
| 570 | TERA(GIGA.value << 10), |
---|
| 571 | PETA(TERA.value << 10), |
---|
| 572 | EXA(PETA.value << 10); |
---|
| 573 | |
---|
| 574 | public final long value; |
---|
| 575 | public final char symbol; |
---|
| 576 | |
---|
| 577 | TraditionalBinaryPrefix(long value) { |
---|
| 578 | this.value = value; |
---|
| 579 | this.symbol = toString().charAt(0); |
---|
| 580 | } |
---|
| 581 | |
---|
| 582 | /** |
---|
| 583 | * @return The TraditionalBinaryPrefix object corresponding to the symbol. |
---|
| 584 | */ |
---|
| 585 | public static TraditionalBinaryPrefix valueOf(char symbol) { |
---|
| 586 | symbol = Character.toUpperCase(symbol); |
---|
| 587 | for(TraditionalBinaryPrefix prefix : TraditionalBinaryPrefix.values()) { |
---|
| 588 | if (symbol == prefix.symbol) { |
---|
| 589 | return prefix; |
---|
| 590 | } |
---|
| 591 | } |
---|
| 592 | throw new IllegalArgumentException("Unknown symbol '" + symbol + "'"); |
---|
| 593 | } |
---|
| 594 | |
---|
| 595 | /** |
---|
| 596 | * Convert a string to long. |
---|
| 597 | * The input string is first be trimmed |
---|
| 598 | * and then it is parsed with traditional binary prefix. |
---|
| 599 | * |
---|
| 600 | * For example, |
---|
| 601 | * "-1230k" will be converted to -1230 * 1024 = -1259520; |
---|
| 602 | * "891g" will be converted to 891 * 1024^3 = 956703965184; |
---|
| 603 | * |
---|
| 604 | * @param s input string |
---|
| 605 | * @return a long value represented by the input string. |
---|
| 606 | */ |
---|
| 607 | public static long string2long(String s) { |
---|
| 608 | s = s.trim(); |
---|
| 609 | final int lastpos = s.length() - 1; |
---|
| 610 | final char lastchar = s.charAt(lastpos); |
---|
| 611 | if (Character.isDigit(lastchar)) |
---|
| 612 | return Long.parseLong(s); |
---|
| 613 | else { |
---|
| 614 | long prefix = TraditionalBinaryPrefix.valueOf(lastchar).value; |
---|
| 615 | long num = Long.parseLong(s.substring(0, lastpos)); |
---|
| 616 | if (num > (Long.MAX_VALUE/prefix) || num < (Long.MIN_VALUE/prefix)) { |
---|
| 617 | throw new IllegalArgumentException(s + " does not fit in a Long"); |
---|
| 618 | } |
---|
| 619 | return num * prefix; |
---|
| 620 | } |
---|
| 621 | } |
---|
| 622 | } |
---|
| 623 | |
---|
| 624 | /** |
---|
| 625 | * Escapes HTML Special characters present in the string. |
---|
| 626 | * @param string |
---|
| 627 | * @return HTML Escaped String representation |
---|
| 628 | */ |
---|
| 629 | public static String escapeHTML(String string) { |
---|
| 630 | if(string == null) { |
---|
| 631 | return null; |
---|
| 632 | } |
---|
| 633 | StringBuffer sb = new StringBuffer(); |
---|
| 634 | boolean lastCharacterWasSpace = false; |
---|
| 635 | char[] chars = string.toCharArray(); |
---|
| 636 | for(char c : chars) { |
---|
| 637 | if(c == ' ') { |
---|
| 638 | if(lastCharacterWasSpace){ |
---|
| 639 | lastCharacterWasSpace = false; |
---|
| 640 | sb.append(" "); |
---|
| 641 | }else { |
---|
| 642 | lastCharacterWasSpace=true; |
---|
| 643 | sb.append(" "); |
---|
| 644 | } |
---|
| 645 | }else { |
---|
| 646 | lastCharacterWasSpace = false; |
---|
| 647 | switch(c) { |
---|
| 648 | case '<': sb.append("<"); break; |
---|
| 649 | case '>': sb.append(">"); break; |
---|
| 650 | case '&': sb.append("&"); break; |
---|
| 651 | case '"': sb.append("""); break; |
---|
| 652 | default : sb.append(c);break; |
---|
| 653 | } |
---|
| 654 | } |
---|
| 655 | } |
---|
| 656 | |
---|
| 657 | return sb.toString(); |
---|
| 658 | } |
---|
| 659 | |
---|
| 660 | /** |
---|
| 661 | * Return an abbreviated English-language desc of the byte length |
---|
| 662 | */ |
---|
| 663 | public static String byteDesc(long len) { |
---|
| 664 | double val = 0.0; |
---|
| 665 | String ending = ""; |
---|
| 666 | if (len < 1024 * 1024) { |
---|
| 667 | val = (1.0 * len) / 1024; |
---|
| 668 | ending = " KB"; |
---|
| 669 | } else if (len < 1024 * 1024 * 1024) { |
---|
| 670 | val = (1.0 * len) / (1024 * 1024); |
---|
| 671 | ending = " MB"; |
---|
| 672 | } else if (len < 1024L * 1024 * 1024 * 1024) { |
---|
| 673 | val = (1.0 * len) / (1024 * 1024 * 1024); |
---|
| 674 | ending = " GB"; |
---|
| 675 | } else if (len < 1024L * 1024 * 1024 * 1024 * 1024) { |
---|
| 676 | val = (1.0 * len) / (1024L * 1024 * 1024 * 1024); |
---|
| 677 | ending = " TB"; |
---|
| 678 | } else { |
---|
| 679 | val = (1.0 * len) / (1024L * 1024 * 1024 * 1024 * 1024); |
---|
| 680 | ending = " PB"; |
---|
| 681 | } |
---|
| 682 | return limitDecimalTo2(val) + ending; |
---|
| 683 | } |
---|
| 684 | |
---|
| 685 | public static synchronized String limitDecimalTo2(double d) { |
---|
| 686 | return decimalFormat.format(d); |
---|
| 687 | } |
---|
| 688 | } |
---|