Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.tradefed.util;
     17 
     18 import com.android.tradefed.result.InputStreamSource;
     19 
     20 import com.google.common.io.ByteStreams;
     21 
     22 import java.io.BufferedInputStream;
     23 import java.io.BufferedReader;
     24 import java.io.ByteArrayOutputStream;
     25 import java.io.Closeable;
     26 import java.io.IOException;
     27 import java.io.InputStream;
     28 import java.io.InputStreamReader;
     29 import java.io.OutputStream;
     30 import java.io.PrintStream;
     31 import java.io.Reader;
     32 import java.io.Writer;
     33 import java.security.DigestInputStream;
     34 import java.security.MessageDigest;
     35 import java.security.NoSuchAlgorithmException;
     36 import java.util.zip.GZIPOutputStream;
     37 import java.util.zip.ZipOutputStream;
     38 
     39 import javax.xml.bind.DatatypeConverter;
     40 
     41 /**
     42  * Utility class for managing input streams.
     43  */
     44 public class StreamUtil {
     45 
     46     // 16K buffer size
     47     private static final int BUF_SIZE = 16 * 1024;
     48 
     49     private StreamUtil() {
     50     }
     51 
     52     /**
     53      * Retrieves a {@link String} from an {@link InputStreamSource}.
     54      *
     55      * @param source the {@link InputStreamSource}
     56      * @return a {@link String} containing the stream contents
     57      * @throws IOException if failure occurred reading the stream
     58      */
     59     public static String getStringFromSource(InputStreamSource source) throws IOException {
     60         final InputStream stream = source.createInputStream();
     61         final String contents;
     62         try {
     63             contents = getStringFromStream(stream);
     64         } finally {
     65             close(stream);
     66         }
     67         return contents;
     68     }
     69 
     70     /**
     71      * Count number of lines in an {@link InputStreamSource}
     72      * @param source the {@link InputStreamSource}
     73      * @return number of lines
     74      * @throws IOException if failure occurred reading the stream
     75      */
     76     public static int countLinesFromSource(InputStreamSource source) throws IOException {
     77         BufferedReader br = null;
     78         int lineCount = 0;
     79         try {
     80             br = new BufferedReader(new InputStreamReader(source.createInputStream()));
     81             while (br.readLine() != null) {
     82                 lineCount++;
     83             }
     84         } finally {
     85             close(br);
     86         }
     87         return lineCount;
     88     }
     89 
     90     /**
     91      * Retrieves a {@link ByteArrayList} from an {@link InputStreamSource}.
     92      *
     93      * @param source the {@link InputStreamSource}
     94      * @return a {@link ByteArrayList} containing the stream contents
     95      * @throws IOException if failure occurred reading the stream
     96      */
     97     public static ByteArrayList getByteArrayListFromSource(InputStreamSource source)
     98             throws IOException {
     99         final InputStream stream = source.createInputStream();
    100         final ByteArrayList contents;
    101         try {
    102             contents = getByteArrayListFromStream(stream);
    103         } finally {
    104             close(stream);
    105         }
    106         return contents;
    107     }
    108 
    109     /**
    110      * Retrieves a {@link String} from a character stream.
    111      *
    112      * @param stream the {@link InputStream}
    113      * @return a {@link String} containing the stream contents
    114      * @throws IOException if failure occurred reading the stream
    115      */
    116     public static String getStringFromStream(InputStream stream) throws IOException {
    117         Reader ir = new BufferedReader(new InputStreamReader(stream));
    118         int irChar = -1;
    119         StringBuilder builder = new StringBuilder();
    120         while ((irChar = ir.read()) != -1) {
    121             builder.append((char)irChar);
    122         }
    123         StreamUtil.close(ir);
    124         return builder.toString();
    125     }
    126 
    127     /**
    128      * Retrieves a {@link ByteArrayList} from a byte stream.
    129      *
    130      * @param stream the {@link InputStream}
    131      * @return a {@link ByteArrayList} containing the stream contents
    132      * @throws IOException if failure occurred reading the stream
    133      */
    134     public static ByteArrayList getByteArrayListFromStream(InputStream stream) throws IOException {
    135         InputStream is = new BufferedInputStream(stream);
    136         int inputByte = -1;
    137         ByteArrayList list = new ByteArrayList();
    138         while ((inputByte = is.read()) != -1) {
    139             list.add((byte)inputByte);
    140         }
    141         list.trimToSize();
    142         return list;
    143     }
    144 
    145     /**
    146      * Copies contents of origStream to destStream.
    147      * <p/>
    148      * Recommended to provide a buffered stream for input and output
    149      *
    150      * @param inStream the {@link InputStream}
    151      * @param outStream the {@link OutputStream}
    152      * @throws IOException
    153      */
    154     public static void copyStreams(InputStream inStream, OutputStream outStream)
    155             throws IOException {
    156         byte[] buf = new byte[BUF_SIZE];
    157         int size = -1;
    158         while ((size = inStream.read(buf)) != -1) {
    159             outStream.write(buf, 0, size);
    160         }
    161     }
    162 
    163     /**
    164      * Copies contents of inStream to writer.
    165      * <p/>
    166      * Recommended to provide a buffered stream for input and output
    167      *
    168      * @param inStream the {@link InputStream}
    169      * @param writer the {@link Writer} destination
    170      * @throws IOException
    171      */
    172     public static void copyStreamToWriter(InputStream inStream, Writer writer) throws IOException {
    173         byte[] buf = new byte[BUF_SIZE];
    174         int size = -1;
    175         while ((size = inStream.read(buf)) != -1) {
    176             writer.write(new String(buf, 0, size));
    177         }
    178     }
    179 
    180     /**
    181      * Gets the stack trace as a {@link String}.
    182      *
    183      * @param throwable the {@link Throwable} to convert.
    184      * @return a {@link String} stack trace
    185      */
    186     public static String getStackTrace(Throwable throwable) {
    187         // dump the print stream results to the ByteArrayOutputStream, so contents can be evaluated
    188         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    189         PrintStream bytePrintStream = new PrintStream(outputStream);
    190         throwable.printStackTrace(bytePrintStream);
    191         return outputStream.toString();
    192     }
    193 
    194     /**
    195      * @deprecated use {@link #close(Closeable)} instead.
    196      */
    197     @Deprecated
    198     public static void closeStream(OutputStream out) {
    199         close(out);
    200     }
    201 
    202     /**
    203      * @deprecated use {@link #close(Closeable)} instead.
    204      */
    205     @Deprecated
    206     public static void closeStream(InputStream in) {
    207         close(in);
    208     }
    209 
    210     /**
    211      * Attempts to flush the given output stream, and then closes it.
    212      *
    213      * @param outStream the {@link OutputStream}. No action taken if outStream is null.
    214      */
    215     public static void flushAndCloseStream(OutputStream outStream) {
    216         if (outStream != null) {
    217             try {
    218                 outStream.flush();
    219             } catch (IOException e) {
    220                 // ignore
    221             }
    222             try {
    223                 outStream.close();
    224             } catch (IOException e) {
    225                 // ignore
    226             }
    227         }
    228     }
    229 
    230     /**
    231      * Closes given zip output stream.
    232      *
    233      * @param outStream the {@link ZipOutputStream}. No action taken if outStream is null.
    234      */
    235     public static void closeZipStream(ZipOutputStream outStream) {
    236         if (outStream != null) {
    237             try {
    238                 outStream.closeEntry();
    239                 outStream.close();
    240             } catch (IOException e) {
    241                 // ignore
    242             }
    243         }
    244     }
    245 
    246     /**
    247      * Closes given gzip output stream.
    248      *
    249      * @param outStream the {@link ZipOutputStream}. No action taken if outStream is null.
    250      */
    251     public static void closeGZipStream(GZIPOutputStream outStream) {
    252         if (outStream != null) {
    253             try {
    254                 outStream.finish();
    255                 outStream.close();
    256             } catch (IOException e) {
    257                 // ignore
    258             }
    259         }
    260     }
    261 
    262     /**
    263      * Closes the given {@link Closeable}.
    264      *
    265      * @param closeable the {@link Closeable}. No action taken if <code>null</code>.
    266      */
    267     public static void close(Closeable closeable) {
    268         if (closeable != null) {
    269             try {
    270                 closeable.close();
    271             } catch (IOException e) {
    272                 // ignore
    273             }
    274         }
    275     }
    276 
    277     /**
    278      * Cancels the given {@link InputStreamSource} if non-null.
    279      */
    280     public static void cancel(InputStreamSource outputSource) {
    281         if (outputSource != null) {
    282             outputSource.cancel();
    283         }
    284     }
    285 
    286     /**
    287      * Create a {@link OutputStream} that discards all writes.
    288      */
    289     public static OutputStream nullOutputStream() {
    290         return ByteStreams.nullOutputStream();
    291     }
    292 
    293     /**
    294      * Helper method to calculate md5 for a inputStream. The inputStream will be consumed and
    295      * closed.
    296      *
    297      * @param inputSource used to create inputStream
    298      * @return md5 of the stream
    299      * @throws IOException
    300      */
    301     public static String calculateMd5(InputStream inputSource) throws IOException {
    302         MessageDigest md = null;
    303         try {
    304             md = MessageDigest.getInstance("md5");
    305         } catch (NoSuchAlgorithmException e) {
    306             // This should not happen
    307             throw new RuntimeException(e);
    308         }
    309         InputStream input = new BufferedInputStream(new DigestInputStream(inputSource, md));
    310         byte[] buf = new byte[BUF_SIZE];
    311         while (input.read(buf) != -1) {
    312             // Read through the stream to update digest.
    313         }
    314         input.close();
    315         String md5 = DatatypeConverter.printHexBinary(md.digest()).toLowerCase();
    316         return md5;
    317     }
    318 }
    319