View Javadoc

    1   /*
    2    * ArchiveUtils
    3    *
    4    * $Header: /cvsroot/archive-crawler/ArchiveOpenCrawler/src/java/org/archive/util/ArchiveUtils.java,v 1.38 2007/01/23 00:29:48 gojomo Exp $
    5    *
    6    * Created on Jul 7, 2003
    7    *
    8    * Copyright (C) 2003 Internet Archive.
    9    *
    10   * This file is part of the Heritrix web crawler (crawler.archive.org).
    11   *
    12   * Heritrix is free software; you can redistribute it and/or modify
    13   * it under the terms of the GNU Lesser Public License as published by
    14   * the Free Software Foundation; either version 2.1 of the License, or
    15   * any later version.
    16   *
    17   * Heritrix is distributed in the hope that it will be useful,
    18   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    19   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    20   * GNU Lesser Public License for more details.
    21   *
    22   * You should have received a copy of the GNU Lesser Public License
    23   * along with Heritrix; if not, write to the Free Software
    24   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    25   *
    26   */
    27  package org.archive.util;
    28
    29  import java.io.IOException;
    30  import java.io.PrintWriter;
    31  import java.io.StringWriter;
    32  import java.text.NumberFormat;
    33  import java.text.ParseException;
    34  import java.text.SimpleDateFormat;
    35  import java.util.Calendar;
    36  import java.util.Date;
    37  import java.util.GregorianCalendar;
    38  import java.util.Locale;
    39  import java.util.TimeZone;
    40
    41  /***
    42   * Miscellaneous useful methods.
    43   *
    44   * @author gojomo & others
    45   */
    46  public class ArchiveUtils {
    47
    48      /***
    49       * Arc-style date stamp in the format yyyyMMddHHmm and UTC time zone.
    50       */
    51      private static final ThreadLocal<SimpleDateFormat>
    52          TIMESTAMP12 = threadLocalDateFormat("yyyyMMddHHmm");;
    53
    54      /***
    55       * Arc-style date stamp in the format yyyyMMddHHmmss and UTC time zone.
    56       */
    57      private static final ThreadLocal<SimpleDateFormat>
    58         TIMESTAMP14 = threadLocalDateFormat("yyyyMMddHHmmss");
    59      /***
    60       * Arc-style date stamp in the format yyyyMMddHHmmssSSS and UTC time zone.
    61       */
    62      private static final ThreadLocal<SimpleDateFormat>
    63          TIMESTAMP17 = threadLocalDateFormat("yyyyMMddHHmmssSSS");
    64
    65      /***
    66       * Log-style date stamp in the format yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
    67       * UTC time zone is assumed.
    68       */
    69      private static final ThreadLocal<SimpleDateFormat>
    70          TIMESTAMP17ISO8601Z = threadLocalDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    71
    72      /***
    73       * Log-style date stamp in the format yyyy-MM-dd'T'HH:mm:ss'Z'
    74       * UTC time zone is assumed.
    75       */
    76      private static final ThreadLocal<SimpleDateFormat>
    77          TIMESTAMP14ISO8601Z = threadLocalDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    78
    79      /***
    80       * Default character to use padding strings.
    81       */
    82      private static final char DEFAULT_PAD_CHAR = ' ';
    83
    84      /*** milliseconds in an hour */
    85      private static final int HOUR_IN_MS = 60 * 60 * 1000;
    86      /*** milliseconds in a day */
    87      private static final int DAY_IN_MS = 24 * HOUR_IN_MS;
    88
    89      private static ThreadLocal<SimpleDateFormat> threadLocalDateFormat(final String pattern) {
    90          ThreadLocal<SimpleDateFormat> tl = new ThreadLocal<SimpleDateFormat>() {
    91              protected SimpleDateFormat initialValue() {
    92                  SimpleDateFormat df = new SimpleDateFormat(pattern);
    93                  df.setTimeZone(TimeZone.getTimeZone("GMT"));
    94                  return df;
    95              }
    96          };
    97          return tl;
    98      }
    99
    100     public static int MAX_INT_CHAR_WIDTH =
    101         Integer.toString(Integer.MAX_VALUE).length();
    102
    103     /***
    104      * Utility function for creating arc-style date stamps
    105      * in the format yyyMMddHHmmssSSS.
    106      * Date stamps are in the UTC time zone
    107      * @return the date stamp
    108      */
    109     public static String get17DigitDate(){
    110         return TIMESTAMP17.get().format(new Date());
    111     }
    112
    113     /***
    114      * Utility function for creating arc-style date stamps
    115      * in the format yyyMMddHHmmss.
    116      * Date stamps are in the UTC time zone
    117      * @return the date stamp
    118      */
    119     public static String get14DigitDate(){
    120         return TIMESTAMP14.get().format(new Date());
    121     }
    122
    123     /***
    124      * Utility function for creating arc-style date stamps
    125      * in the format yyyMMddHHmm.
    126      * Date stamps are in the UTC time zone
    127      * @return the date stamp
    128      */
    129     public static String get12DigitDate(){
    130         return TIMESTAMP12.get().format(new Date());
    131     }
    132
    133     /***
    134      * Utility function for creating log timestamps, in
    135      * W3C/ISO8601 format, assuming UTC. Use current time.
    136      *
    137      * Format is yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
    138      *
    139      * @return the date stamp
    140      */
    141     public static String getLog17Date(){
    142         return TIMESTAMP17ISO8601Z.get().format(new Date());
    143     }
    144
    145     /***
    146      * Utility function for creating log timestamps, in
    147      * W3C/ISO8601 format, assuming UTC.
    148      *
    149      * Format is yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
    150      * @param date Date to format.
    151      *
    152      * @return the date stamp
    153      */
    154     public static String getLog17Date(long date){
    155         return TIMESTAMP17ISO8601Z.get().format(new Date(date));
    156     }
    157
    158     /***
    159      * Utility function for creating log timestamps, in
    160      * W3C/ISO8601 format, assuming UTC. Use current time.
    161      *
    162      * Format is yyyy-MM-dd'T'HH:mm:ss'Z'
    163      *
    164      * @return the date stamp
    165      */
    166     public static String getLog14Date(){
    167         return TIMESTAMP14ISO8601Z.get().format(new Date());
    168     }
    169
    170     /***
    171      * Utility function for creating log timestamps, in
    172      * W3C/ISO8601 format, assuming UTC.
    173      *
    174      * Format is yyyy-MM-dd'T'HH:mm:ss'Z'
    175      * @param date long timestamp to format.
    176      *
    177      * @return the date stamp
    178      */
    179     public static String getLog14Date(long date){
    180         return TIMESTAMP14ISO8601Z.get().format(new Date(date));
    181     }
    182
    183     /***
    184      * Utility function for creating log timestamps, in
    185      * W3C/ISO8601 format, assuming UTC.
    186      *
    187      * Format is yyyy-MM-dd'T'HH:mm:ss'Z'
    188      * @param date Date to format.
    189      *
    190      * @return the date stamp
    191      */
    192     public static String getLog14Date(Date date){
    193         return TIMESTAMP14ISO8601Z.get().format(date);
    194     }
    195
    196     /***
    197      * Utility function for creating arc-style date stamps
    198      * in the format yyyyMMddHHmmssSSS.
    199      * Date stamps are in the UTC time zone
    200      *
    201      * @param date milliseconds since epoc
    202      * @return the date stamp
    203      */
    204     public static String get17DigitDate(long date){
    205         return TIMESTAMP17.get().format(new Date(date));
    206     }
    207
    208     public static String get17DigitDate(Date date){
    209         return TIMESTAMP17.get().format(date);
    210     }
    211
    212     /***
    213      * Utility function for creating arc-style date stamps
    214      * in the format yyyyMMddHHmmss.
    215      * Date stamps are in the UTC time zone
    216      *
    217      * @param date milliseconds since epoc
    218      * @return the date stamp
    219      */
    220     public static String get14DigitDate(long date){
    221         return TIMESTAMP14.get().format(new Date(date));
    222     }
    223
    224     public static String get14DigitDate(Date d) {
    225         return TIMESTAMP14.get().format(d);
    226     }
    227
    228     /***
    229      * Utility function for creating arc-style date stamps
    230      * in the format yyyyMMddHHmm.
    231      * Date stamps are in the UTC time zone
    232      *
    233      * @param date milliseconds since epoc
    234      * @return the date stamp
    235      */
    236     public static String get12DigitDate(long date){
    237         return TIMESTAMP12.get().format(new Date(date));
    238     }
    239
    240     public static String get12DigitDate(Date d) {
    241         return TIMESTAMP12.get().format(d);
    242     }
    243
    244     /***
    245      * Parses an ARC-style date.  If passed String is < 12 characters in length,
    246      * we pad.  At a minimum, String should contain a year (>=4 characters).
    247      * Parse will also fail if day or month are incompletely specified.  Depends
    248      * on the above getXXDigitDate methods.
    249      * @param A 4-17 digit date in ARC style (<code>yyyy</code> to
    250      * <code>yyyyMMddHHmmssSSS</code>) formatting.
    251      * @return A Date object representing the passed String.
    252      * @throws ParseException
    253      */
    254     public static Date getDate(String d) throws ParseException {
    255         Date date = null;
    256         if (d == null) {
    257             throw new IllegalArgumentException("Passed date is null");
    258         }
    259         switch (d.length()) {
    260         case 14:
    261             date = ArchiveUtils.parse14DigitDate(d);
    262             break;
    263
    264         case 17:
    265             date = ArchiveUtils.parse17DigitDate(d);
    266             break;
    267
    268         case 12:
    269             date = ArchiveUtils.parse12DigitDate(d);
    270             break;
    271
    272         case 0:
    273         case 1:
    274         case 2:
    275         case 3:
    276             throw new ParseException("Date string must at least contain a" +
    277                 "year: " + d, d.length());
    278
    279         default:
    280             if (!(d.startsWith("19") || d.startsWith("20"))) {
    281                 throw new ParseException("Unrecognized century: " + d, 0);
    282             }
    283             if (d.length() < 8 && (d.length() % 2) != 0) {
    284                 throw new ParseException("Incomplete month/date: " + d,
    285                     d.length());
    286             }
    287             StringBuilder sb = new StringBuilder(d);
    288             if (sb.length() < 8) {
    289                 for (int i = sb.length(); sb.length() < 8; i += 2) {
    290                     sb.append("01");
    291                 }
    292             }
    293             if (sb.length() < 12) {
    294                 for (int i = sb.length(); sb.length() < 12; i++) {
    295                     sb.append("0");
    296                 }
    297             }
    298             date = ArchiveUtils.parse12DigitDate(sb.toString());
    299         }
    300
    301         return date;
    302     }
    303
    304     /***
    305      * Utility function for parsing arc-style date stamps
    306      * in the format yyyMMddHHmmssSSS.
    307      * Date stamps are in the UTC time zone.  The whole string will not be
    308      * parsed, only the first 17 digits.
    309      *
    310      * @param date an arc-style formatted date stamp
    311      * @return the Date corresponding to the date stamp string
    312      * @throws ParseException if the inputstring was malformed
    313      */
    314     public static Date parse17DigitDate(String date) throws ParseException {
    315         return TIMESTAMP17.get().parse(date);
    316     }
    317
    318     /***
    319      * Utility function for parsing arc-style date stamps
    320      * in the format yyyMMddHHmmss.
    321      * Date stamps are in the UTC time zone.  The whole string will not be
    322      * parsed, only the first 14 digits.
    323      *
    324      * @param date an arc-style formatted date stamp
    325      * @return the Date corresponding to the date stamp string
    326      * @throws ParseException if the inputstring was malformed
    327      */
    328     public static Date parse14DigitDate(String date) throws ParseException{
    329         return TIMESTAMP14.get().parse(date);
    330     }
    331
    332     /***
    333      * Utility function for parsing arc-style date stamps
    334      * in the format yyyMMddHHmm.
    335      * Date stamps are in the UTC time zone.  The whole string will not be
    336      * parsed, only the first 12 digits.
    337      *
    338      * @param date an arc-style formatted date stamp
    339      * @return the Date corresponding to the date stamp string
    340      * @throws ParseException if the inputstring was malformed
    341      */
    342     public static Date parse12DigitDate(String date) throws ParseException{
    343         return TIMESTAMP12.get().parse(date);
    344     }
    345
    346     /***
    347      * Convert 17-digit date format timestamps (as found in crawl.log, for
    348      * example) into a GregorianCalendar object. + * Useful so you can convert
    349      * into milliseconds-since-epoch. Note: it is possible to compute
    350      * milliseconds-since-epoch + * using {@link #parse17DigitDate}.UTC(), but
    351      * that method is deprecated in favor of using Calendar.getTimeInMillis(). + *
    352      * <p/>I probably should have dug into all the utility methods in
    353      * DateFormat.java to parse the timestamp, but this was + * easier. If
    354      * someone wants to fix this to use those methods, please have at it! <p/>
    355      * Mike Schwartz, schwartz at CodeOnTheRoad dot com.
    356      *
    357      * @param timestamp17String
    358      * @return Calendar set to <code>timestamp17String</code>.
    359      */
    360     public static Calendar timestamp17ToCalendar(String timestamp17String) {
    361         GregorianCalendar calendar = new GregorianCalendar();
    362         int year = Integer.parseInt(timestamp17String.substring(0, 4));
    363         int dayOfMonth = Integer.parseInt(timestamp17String.substring(6, 8));
    364         // Month is 0-based
    365         int month = Integer.parseInt(timestamp17String.substring(4, 6)) - 1;
    366         int hourOfDay = Integer.parseInt(timestamp17String.substring(8, 10));
    367         int minute = Integer.parseInt(timestamp17String.substring(10, 12));
    368         int second = Integer.parseInt(timestamp17String.substring(12, 14));
    369         int milliseconds = Integer
    370                 .parseInt(timestamp17String.substring(14, 17));
    371         calendar.set(Calendar.YEAR, year);
    372         calendar.set(Calendar.MONTH, month);
    373         calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
    374         calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
    375         calendar.set(Calendar.MINUTE, minute);
    376         calendar.set(Calendar.SECOND, second);
    377         calendar.set(Calendar.MILLISECOND, milliseconds);
    378         return calendar;
    379     }
    380
    381     /***
    382      * @param timestamp A 14-digit timestamp or the suffix for a 14-digit
    383      * timestamp: E.g. '20010909014640' or '20010101' or '1970'.
    384      * @return Seconds since the epoch as a string zero-pre-padded so always
    385      * Integer.MAX_VALUE wide (Makes it so sorting of resultant string works
    386      * properly).
    387      * @throws ParseException
    388      */
    389     public static String secondsSinceEpoch(String timestamp)
    390     throws ParseException {
    391         return zeroPadInteger((int)
    392             (getSecondsSinceEpoch(timestamp).getTime()/1000));
    393     }
    394
    395     /***
    396      * @param timestamp A 14-digit timestamp or the suffix for a 14-digit
    397      * timestamp: E.g. '20010909014640' or '20010101' or '1970'.
    398      * @return A date.
    399      * @see #secondsSinceEpoch(String)
    400      * @throws ParseException
    401      */
    402     public static Date getSecondsSinceEpoch(String timestamp)
    403     throws ParseException {
    404         if (timestamp.length() < 14) {
    405             if (timestamp.length() < 10 && (timestamp.length() % 2) == 1) {
    406                 throw new IllegalArgumentException("Must have year, " +
    407                     "month, date, hour or second granularity: " + timestamp);
    408             }
    409             if (timestamp.length() == 4) {
    410                 // Add first month and first date.
    411                 timestamp = timestamp + "01010000";
    412             }
    413             if (timestamp.length() == 6) {
    414                 // Add a date of the first.
    415                 timestamp = timestamp + "010000";
    416             }
    417             if (timestamp.length() < 14) {
    418                 timestamp = timestamp +
    419                     ArchiveUtils.padTo("", 14 - timestamp.length(), '0');
    420             }
    421         }
    422         return ArchiveUtils.parse14DigitDate(timestamp);
    423     }
    424
    425     /***
    426      * @param i Integer to add prefix of zeros too.  If passed
    427      * 2005, will return the String <code>0000002005</code>. String
    428      * width is the width of Integer.MAX_VALUE as a string (10
    429      * digits).
    430      * @return Padded String version of <code>i</code>.
    431      */
    432     public static String zeroPadInteger(int i) {
    433         return ArchiveUtils.padTo(Integer.toString(i),
    434                 MAX_INT_CHAR_WIDTH, '0');
    435     }
    436
    437     /***
    438      * Convert an <code>int</code> to a <code>String</code>, and pad it to
    439      * <code>pad</code> spaces.
    440      * @param i the int
    441      * @param pad the width to pad to.
    442      * @return String w/ padding.
    443      */
    444     public static String padTo(final int i, final int pad) {
    445         String n = Integer.toString(i);
    446         return padTo(n, pad);
    447     }
    448
    449     /***
    450      * Pad the given <code>String</code> to <code>pad</code> characters wide
    451      * by pre-pending spaces.  <code>s</code> should not be <code>null</code>.
    452      * If <code>s</code> is already wider than <code>pad</code> no change is
    453      * done.
    454      *
    455      * @param s the String to pad
    456      * @param pad the width to pad to.
    457      * @return String w/ padding.
    458      */
    459     public static String padTo(final String s, final int pad) {
    460         return padTo(s, pad, DEFAULT_PAD_CHAR);
    461     }
    462
    463     /***
    464      * Pad the given <code>String</code> to <code>pad</code> characters wide
    465      * by pre-pending <code>padChar</code>.
    466      *
    467      * <code>s</code> should not be <code>null</code>. If <code>s</code> is
    468      * already wider than <code>pad</code> no change is done.
    469      *
    470      * @param s the String to pad
    471      * @param pad the width to pad to.
    472      * @param padChar The pad character to use.
    473      * @return String w/ padding.
    474      */
    475     public static String padTo(final String s, final int pad,
    476             final char padChar) {
    477         String result = s;
    478         int l = s.length();
    479         if (l < pad) {
    480             StringBuffer sb = new StringBuffer(pad);
    481             while(l < pad) {
    482                 sb.append(padChar);
    483                 l++;
    484             }
    485             sb.append(s);
    486             result = sb.toString();
    487         }
    488         return result;
    489     }
    490
    491     /*** check that two byte arrays are equal.  They may be <code>null</code>.
    492      *
    493      * @param lhs a byte array
    494      * @param rhs another byte array.
    495      * @return <code>true</code> if they are both equal (or both
    496      * <code>null</code>)
    497      */
    498     public static boolean byteArrayEquals(final byte[] lhs, final byte[] rhs) {
    499         if (lhs == null && rhs != null || lhs != null && rhs == null) {
    500             return false;
    501         }
    502         if (lhs==rhs) {
    503             return true;
    504         }
    505         if (lhs.length != rhs.length) {
    506             return false;
    507         }
    508         for(int i = 0; i<lhs.length; i++) {
    509             if (lhs[i]!=rhs[i]) {
    510                 return false;
    511             }
    512         }
    513         return true;
    514     }
    515
    516     /***
    517      * Converts a double to a string.
    518      * @param val The double to convert
    519      * @param precision How many characters to include after '.'
    520      * @return the double as a string.
    521      */
    522     public static String doubleToString(double val, int maxFractionDigits){
    523         return doubleToString(val, maxFractionDigits, 0);
    524     }
    525
    526     private static String doubleToString(double val, int maxFractionDigits, int minFractionDigits) {
    527         NumberFormat f = NumberFormat.getNumberInstance(Locale.US);
    528         f.setMaximumFractionDigits(maxFractionDigits);
    529         f.setMinimumFractionDigits(minFractionDigits);
    530         return f.format(val);
    531     }
    532
    533     /***
    534      * Takes a byte size and formats it for display with 'friendly' units.
    535      * <p>
    536      * This involves converting it to the largest unit
    537      * (of B, KB, MB, GB, TB) for which the amount will be > 1.
    538      * <p>
    539      * Additionally, at least 2 significant digits are always displayed.
    540      * <p>
    541      * Displays as bytes (B): 0-1023
    542      * Displays as kilobytes (KB): 1024 - 2097151 (~2Mb)
    543      * Displays as megabytes (MB): 2097152 - 4294967295 (~4Gb)
    544      * Displays as gigabytes (GB): 4294967296 - infinity
    545      * <p>
    546      * Negative numbers will be returned as '0 B'.
    547      *
    548      * @param amount the amount of bytes
    549      * @return A string containing the amount, properly formated.
    550      */
    551     public static String formatBytesForDisplay(long amount) {
    552         double displayAmount = (double) amount;
    553         int unitPowerOf1024 = 0;
    554
    555         if(amount <= 0){
    556             return "0 B";
    557         }
    558
    559         while(displayAmount>=1024 && unitPowerOf1024 < 4) {
    560             displayAmount = displayAmount / 1024;
    561             unitPowerOf1024++;
    562         }
    563
    564         // TODO: get didactic, make these KiB, MiB, GiB, TiB
    565         final String[] units = { " B", " KB", " MB", " GB", " TB" };
    566
    567         // ensure at least 2 significant digits (#.#) for small displayValues
    568         int fractionDigits = (displayAmount < 10) ? 1 : 0;
    569         return doubleToString(displayAmount, fractionDigits, fractionDigits)
    570                    + units[unitPowerOf1024];
    571     }
    572
    573     /***
    574      * Convert milliseconds value to a human-readable duration
    575      * @param time
    576      * @return Human readable string version of passed <code>time</code>
    577      */
    578     public static String formatMillisecondsToConventional(long time) {
    579         return formatMillisecondsToConventional(time,true);
    580     }
    581
    582     /***
    583      * Convert milliseconds value to a human-readable duration
    584      * @param time
    585      * @param toMs whether to print to the ms
    586      * @return Human readable string version of passed <code>time</code>
    587      */
    588     public static String formatMillisecondsToConventional(long time, boolean toMs) {
    589         StringBuffer sb = new StringBuffer();
    590         if(time<0) {
    591             sb.append("-");
    592         }
    593         long absTime = Math.abs(time);
    594         if(!toMs && absTime < 1000) {
    595             return "0s";
    596         }
    597         if(absTime > DAY_IN_MS) {
    598             // days
    599             sb.append(absTime / DAY_IN_MS + "d");
    600             absTime = absTime % DAY_IN_MS;
    601         }
    602         if (absTime > HOUR_IN_MS) {
    603             //got hours.
    604             sb.append(absTime / HOUR_IN_MS + "h");
    605             absTime = absTime % HOUR_IN_MS;
    606         }
    607         if (absTime > 60000) {
    608             sb.append(absTime / 60000 + "m");
    609             absTime = absTime % 60000;
    610         }
    611         if (absTime > 1000) {
    612             sb.append(absTime / 1000 + "s");
    613             absTime = absTime % 1000;
    614         }
    615         if(toMs) {
    616             sb.append(absTime + "ms");
    617         }
    618         return sb.toString();
    619     }
    620
    621
    622     /***
    623      * Generate a long UID based on the given class and version number.
    624      * Using this instead of the default will assume serialization
    625      * compatibility across class changes unless version number is
    626      * intentionally bumped.
    627      *
    628      * @param class1
    629      * @param version
    630      * @return UID based off class and version number.
    631      */
    632     public static long classnameBasedUID(Class class1, int version) {
    633         String callingClassname = class1.getName();
    634         return (long)callingClassname.hashCode() << 32 + version;
    635     }
    636
    637     /***
    638      * Copy the raw bytes of a long into a byte array, starting at
    639      * the specified offset.
    640      *
    641      * @param l
    642      * @param array
    643      * @param offset
    644      */
    645     public static void longIntoByteArray(long l, byte[] array, int offset) {
    646         int i, shift;
    647
    648         for(i = 0, shift = 56; i < 8; i++, shift -= 8)
    649         array[offset+i] = (byte)(0xFF & (l >> shift));
    650     }
    651
    652     public static long byteArrayIntoLong(byte [] bytearray) {
    653         return byteArrayIntoLong(bytearray, 0);
    654     }
    655
    656     /***
    657      * Byte array into long.
    658      * @param bytearray Array to convert to a long.
    659      * @param offset Offset into array at which we start decoding the long.
    660      * @return Long made of the bytes of <code>array</code> beginning at
    661      * offset <code>offset</code>.
    662      * @see #longIntoByteArray(long, byte[], int)
    663      */
    664     public static long byteArrayIntoLong(byte [] bytearray,
    665             int offset) {
    666         long result = 0;
    667         for (int i = offset; i < 8 /*Bytes in long*/; i++) {
    668             result = (result << 8 /*Bits in byte*/) |
    669                 (0xff & (byte)(bytearray[i] & 0xff));
    670         }
    671         return result;
    672     }
    673
    674     /***
    675      * Given a string that may be a plain host or host/path (without
    676      * URI scheme), add an implied http:// if necessary.
    677      *
    678      * @param u string to evaluate
    679      * @return string with http:// added if no scheme already present
    680      */
    681     public static String addImpliedHttpIfNecessary(String u) {
    682         if(u.indexOf(':') == -1 || u.indexOf('.') < u.indexOf(':')) {
    683             // No scheme present; prepend "http://"
    684             u = "http://" + u;
    685         }
    686         return u;
    687     }
    688
    689     /***
    690      * Verify that the array begins with the prefix.
    691      *
    692      * @param array
    693      * @param prefix
    694      * @return true if array is identical to prefix for the first prefix.length
    695      * positions
    696      */
    697     public static boolean startsWith(byte[] array, byte[] prefix) {
    698         if(prefix.length>array.length) {
    699             return false;
    700         }
    701         for(int i = 0; i < prefix.length; i++) {
    702             if(array[i]!=prefix[i]) {
    703                 return false;
    704             }
    705         }
    706         return true;
    707     }
    708
    709     /***
    710      * Utility method to get a String singleLineReport from Reporter
    711      * @param rep  Reporter to get singleLineReport from
    712      * @return String of report
    713      */
    714     public static String singleLineReport(Reporter rep) {
    715         StringWriter sw = new StringWriter();
    716         PrintWriter pw = new PrintWriter(sw);
    717         try {
    718             rep.singleLineReportTo(pw);
    719         } catch (IOException e) {
    720             // not really possible
    721             e.printStackTrace();
    722         }
    723         pw.flush();
    724         return sw.toString();
    725     }
    726
    727     /***
    728      * Compose the requested report into a String. DANGEROUS IF REPORT
    729      * CAN BE LARGE.
    730      *
    731      * @param rep Reported
    732      * @param name String name of report to compose
    733      * @return String of report
    734      */
    735     public static String writeReportToString(Reporter rep, String name) {
    736         StringWriter sw = new StringWriter();
    737         PrintWriter pw = new PrintWriter(sw);
    738         rep.reportTo(name,pw);
    739         pw.flush();
    740         return sw.toString();
    741     }
    742 }
    743