source: proiecte/HadoopJUnit/hadoop-0.20.1/src/core/org/apache/hadoop/util/StringUtils.java @ 120

Last change on this file since 120 was 120, checked in by (none), 14 years ago

Added the mail files for the Hadoop JUNit Project

  • Property svn:executable set to *
File size: 21.1 KB
Line 
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
19package org.apache.hadoop.util;
20
21import java.io.PrintWriter;
22import java.io.StringWriter;
23import java.net.InetAddress;
24import java.net.URI;
25import java.net.URISyntaxException;
26import java.net.UnknownHostException;
27import java.text.DateFormat;
28import java.text.DecimalFormat;
29import java.text.NumberFormat;
30import java.util.Locale;
31import java.util.ArrayList;
32import java.util.Arrays;
33import java.util.Date;
34import java.util.List;
35import java.util.StringTokenizer;
36import java.util.Collection;
37
38import org.apache.hadoop.fs.*;
39
40/**
41 * General string utils
42 */
43public 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("&nbsp;");
641          }else {
642            lastCharacterWasSpace=true;
643            sb.append(" ");
644          }
645        }else {
646          lastCharacterWasSpace = false;
647          switch(c) {
648          case '<': sb.append("&lt;"); break;
649          case '>': sb.append("&gt;"); break;
650          case '&': sb.append("&amp;"); break;
651          case '"': sb.append("&quot;"); 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}
Note: See TracBrowser for help on using the repository browser.