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         int lineCount = 0;
     78         try (BufferedReader br =
     79                 new BufferedReader(new InputStreamReader(source.createInputStream()))) {
     80             while (br.readLine() != null) {
     81                 lineCount++;
     82             }
     83         }
     84         return lineCount;
     85     }
     86 
     87     /**
     88      * Retrieves a {@link ByteArrayList} from an {@link InputStreamSource}.
     89      *
     90      * @param source the {@link InputStreamSource}
     91      * @return a {@link ByteArrayList} containing the stream contents
     92      * @throws IOException if failure occurred reading the stream
     93      */
     94     public static ByteArrayList getByteArrayListFromSource(InputStreamSource source)
     95             throws IOException {
     96         final InputStream stream = source.createInputStream();
     97         final ByteArrayList contents;
     98         try {
     99             contents = getByteArrayListFromStream(stream);
    100         } finally {
    101             close(stream);
    102         }
    103         return contents;
    104     }
    105 
    106     /**
    107      * Retrieves a {@link String} from a character stream.
    108      *
    109      * @param stream the {@link InputStream}
    110      * @return a {@link String} containing the stream contents
    111      * @throws IOException if failure occurred reading the stream
    112      */
    113     public static String getStringFromStream(InputStream stream) throws IOException {
    114         int irChar = -1;
    115         StringBuilder builder = new StringBuilder();
    116         try (Reader ir = new BufferedReader(new InputStreamReader(stream))) {
    117             while ((irChar = ir.read()) != -1) {
    118                 builder.append((char) irChar);
    119             }
    120         }
    121         return builder.toString();
    122     }
    123 
    124     /**
    125      * Retrieves a {@link ByteArrayList} from a byte stream.
    126      *
    127      * @param stream the {@link InputStream}
    128      * @return a {@link ByteArrayList} containing the stream contents
    129      * @throws IOException if failure occurred reading the stream
    130      */
    131     public static ByteArrayList getByteArrayListFromStream(InputStream stream) throws IOException {
    132         InputStream is = new BufferedInputStream(stream);
    133         int inputByte = -1;
    134         ByteArrayList list = new ByteArrayList();
    135         while ((inputByte = is.read()) != -1) {
    136             list.add((byte)inputByte);
    137         }
    138         list.trimToSize();
    139         return list;
    140     }
    141 
    142     /**
    143      * Copies contents of origStream to destStream.
    144      * <p/>
    145      * Recommended to provide a buffered stream for input and output
    146      *
    147      * @param inStream the {@link InputStream}
    148      * @param outStream the {@link OutputStream}
    149      * @throws IOException
    150      */
    151     public static void copyStreams(InputStream inStream, OutputStream outStream)
    152             throws IOException {
    153         byte[] buf = new byte[BUF_SIZE];
    154         int size = -1;
    155         while ((size = inStream.read(buf)) != -1) {
    156             outStream.write(buf, 0, size);
    157         }
    158     }
    159 
    160     /**
    161      * Copies contents of inStream to writer.
    162      * <p/>
    163      * Recommended to provide a buffered stream for input and output
    164      *
    165      * @param inStream the {@link InputStream}
    166      * @param writer the {@link Writer} destination
    167      * @throws IOException
    168      */
    169     public static void copyStreamToWriter(InputStream inStream, Writer writer) throws IOException {
    170         byte[] buf = new byte[BUF_SIZE];
    171         int size = -1;
    172         while ((size = inStream.read(buf)) != -1) {
    173             writer.write(new String(buf, 0, size));
    174         }
    175     }
    176 
    177     /**
    178      * Gets the stack trace as a {@link String}.
    179      *
    180      * @param throwable the {@link Throwable} to convert.
    181      * @return a {@link String} stack trace
    182      */
    183     public static String getStackTrace(Throwable throwable) {
    184         // dump the print stream results to the ByteArrayOutputStream, so contents can be evaluated
    185         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    186         PrintStream bytePrintStream = new PrintStream(outputStream);
    187         throwable.printStackTrace(bytePrintStream);
    188         return outputStream.toString();
    189     }
    190 
    191     /**
    192      * @deprecated use {@link #close(Closeable)} instead.
    193      */
    194     @Deprecated
    195     public static void closeStream(OutputStream out) {
    196         close(out);
    197     }
    198 
    199     /**
    200      * @deprecated use {@link #close(Closeable)} instead.
    201      */
    202     @Deprecated
    203     public static void closeStream(InputStream in) {
    204         close(in);
    205     }
    206 
    207     /**
    208      * Attempts to flush the given output stream, and then closes it.
    209      *
    210      * @param outStream the {@link OutputStream}. No action taken if outStream is null.
    211      */
    212     public static void flushAndCloseStream(OutputStream outStream) {
    213         if (outStream != null) {
    214             try {
    215                 outStream.flush();
    216             } catch (IOException e) {
    217                 // ignore
    218             }
    219             try {
    220                 outStream.close();
    221             } catch (IOException e) {
    222                 // ignore
    223             }
    224         }
    225     }
    226 
    227     /**
    228      * Closes given zip output stream.
    229      *
    230      * @param outStream the {@link ZipOutputStream}. No action taken if outStream is null.
    231      */
    232     public static void closeZipStream(ZipOutputStream outStream) {
    233         if (outStream != null) {
    234             try {
    235                 outStream.closeEntry();
    236                 outStream.close();
    237             } catch (IOException e) {
    238                 // ignore
    239             }
    240         }
    241     }
    242 
    243     /**
    244      * Closes given gzip output stream.
    245      *
    246      * @param outStream the {@link ZipOutputStream}. No action taken if outStream is null.
    247      */
    248     public static void closeGZipStream(GZIPOutputStream outStream) {
    249         if (outStream != null) {
    250             try {
    251                 outStream.finish();
    252                 outStream.close();
    253             } catch (IOException e) {
    254                 // ignore
    255             }
    256         }
    257     }
    258 
    259     /**
    260      * Closes the given {@link Closeable}.
    261      *
    262      * @param closeable the {@link Closeable}. No action taken if <code>null</code>.
    263      */
    264     public static void close(Closeable closeable) {
    265         if (closeable != null) {
    266             try {
    267                 closeable.close();
    268             } catch (IOException e) {
    269                 // ignore
    270             }
    271         }
    272     }
    273 
    274     /**
    275      * Cancels the given {@link InputStreamSource} if non-null.
    276      */
    277     public static void cancel(InputStreamSource outputSource) {
    278         if (outputSource != null) {
    279             outputSource.close();
    280         }
    281     }
    282 
    283     /**
    284      * Create a {@link OutputStream} that discards all writes.
    285      */
    286     public static OutputStream nullOutputStream() {
    287         return ByteStreams.nullOutputStream();
    288     }
    289 
    290     /**
    291      * Helper method to calculate md5 for a inputStream. The inputStream will be consumed and
    292      * closed.
    293      *
    294      * @param inputSource used to create inputStream
    295      * @return md5 of the stream
    296      * @throws IOException
    297      */
    298     public static String calculateMd5(InputStream inputSource) throws IOException {
    299         MessageDigest md = null;
    300         try {
    301             md = MessageDigest.getInstance("md5");
    302         } catch (NoSuchAlgorithmException e) {
    303             // This should not happen
    304             throw new RuntimeException(e);
    305         }
    306         InputStream input = new BufferedInputStream(new DigestInputStream(inputSource, md));
    307         byte[] buf = new byte[BUF_SIZE];
    308         while (input.read(buf) != -1) {
    309             // Read through the stream to update digest.
    310         }
    311         input.close();
    312         String md5 = DatatypeConverter.printHexBinary(md.digest()).toLowerCase();
    313         return md5;
    314     }
    315 }
    316