StreamUtils.java

  1. /*
  2.  * StreamUtils
  3.  *
  4.  * $Id$
  5.  * $HeadURL$
  6.  */
  7. package gov.usgs.util;

  8. import java.io.BufferedInputStream;
  9. import java.io.BufferedOutputStream;
  10. import java.io.ByteArrayInputStream;
  11. import java.io.ByteArrayOutputStream;
  12. import java.io.File;
  13. import java.io.FileInputStream;
  14. import java.io.FileOutputStream;
  15. import java.io.FilterInputStream;
  16. import java.io.FilterOutputStream;
  17. import java.io.IOException;
  18. import java.io.InputStream;
  19. import java.io.OutputStream;
  20. import java.net.URL;
  21. import java.net.URLConnection;
  22. import java.util.zip.GZIPInputStream;

  23. /**
  24.  * Stream input, output, and transfer utilities.
  25.  */
  26. public class StreamUtils {

  27.     /** Default buffer size used for stream reads and writes. */
  28.     public static final int DEFAULT_BUFFER_SIZE = 4096;

  29.     /** Default connect timeout for url connections. */
  30.     public static final int DEFAULT_URL_CONNECT_TIMEOUT = 5000;

  31.     /** Default read timeout for url connections. */
  32.     public static final int DEFAULT_URL_READ_TIMEOUT = 15000;

  33.     /**
  34.      * Get an input stream for an Object if possible.
  35.      *
  36.      * @param obj
  37.      *            an InputStream, File, byte[], or String.
  38.      * @return an InputStream or null. If obj is a File, the stream is Buffered.
  39.      * @throws IOException
  40.      *             if an error occurs.
  41.      * @throws IllegalArgumentException
  42.      *             if obj is not an InputStream, URL, File, byte[], or String.
  43.      */
  44.     public static InputStream getInputStream(final Object obj)
  45.             throws IOException, IllegalArgumentException {
  46.         InputStream stream = null;
  47.         byte[] bytes = null;

  48.         if (obj instanceof InputStream) {
  49.             stream = (InputStream) obj;
  50.         } else if (obj instanceof URL) {
  51.             stream = getURLInputStream((URL) obj);
  52.         } else if (obj instanceof File) {
  53.             stream = new BufferedInputStream(new FileInputStream((File) obj));
  54.         } else if (obj instanceof byte[]) {
  55.             bytes = (byte[]) obj;
  56.         } else if (obj instanceof String) {
  57.             bytes = ((String) obj).getBytes();
  58.         } else {
  59.             throw new IllegalArgumentException(
  60.                     "Expected an InputStream, URL, File, byte[], or String");
  61.         }

  62.         if (bytes != null) {
  63.             stream = new ByteArrayInputStream(bytes);
  64.         }

  65.         return stream;
  66.     }

  67.     /**
  68.      * Get an InputStream from a URL. If URL is a HTTP url, attempts gzip
  69.      * compression.
  70.      *
  71.      * @param url
  72.      *            the url being accessed.
  73.      * @return an InputStream to content at URL.
  74.      * @throws IOException
  75.      *             if an error occurs.
  76.      */
  77.     public static InputStream getURLInputStream(final URL url)
  78.             throws IOException {
  79.         return getURLInputStream(url, DEFAULT_URL_CONNECT_TIMEOUT,
  80.                 DEFAULT_URL_READ_TIMEOUT);
  81.     }

  82.     /**
  83.      * Get an InputStream from a URL. If URL is a HTTP url, attempts gzip
  84.      * compression.
  85.      *
  86.      * @param url
  87.      *            the url being accessed.
  88.      * @param connectTimeout allowed time in milliseconds before connection.
  89.      * @param readTimeout allowed time in milliseconds before read.
  90.      * @return an InputStream to content at URL.
  91.      * @throws IOException
  92.      *             if an error occurs.
  93.      */
  94.     public static InputStream getURLInputStream(final URL url,
  95.             final int connectTimeout, final int readTimeout)
  96.             throws IOException {
  97.         InputStream in = null;

  98.         // initialize connection
  99.         URLConnection conn = url.openConnection();
  100.         conn.setRequestProperty("Accept-Encoding", "gzip");
  101.         conn.setConnectTimeout(connectTimeout);
  102.         conn.setReadTimeout(readTimeout);

  103.         // connect
  104.         conn.connect();

  105.         // get response
  106.         in = conn.getInputStream();
  107.         String contentEncoding = conn.getContentEncoding();
  108.         if (contentEncoding != null && contentEncoding.equals("gzip")) {
  109.             in = new GZIPInputStream(in);
  110.         }

  111.         return in;
  112.     }

  113.     /**
  114.      * Turn an object into an OutputStream if possible.
  115.      *
  116.      * @param obj
  117.      *            an OutputStream or File.
  118.      * @param append
  119.      *            if obj is a file and this parameter is true, the output stream
  120.      *            will be opened in append mode.
  121.      * @return an OutputStream. If obj is a File, the stream is Buffered.
  122.      * @throws IOException
  123.      *             if an error occurs
  124.      */
  125.     public static OutputStream getOutputStream(final Object obj,
  126.             final boolean append) throws IOException {
  127.         OutputStream stream = null;

  128.         if (obj instanceof OutputStream) {
  129.             stream = (OutputStream) obj;
  130.         } else if (obj instanceof File) {
  131.             File file = (File) obj;
  132.             // create parent directory first, if needed
  133.             File parent = file.getAbsoluteFile().getParentFile();
  134.             if (!parent.exists() && !parent.mkdirs()) {
  135.                 throw new IOException("Unable to create directory "
  136.                         + parent.getAbsolutePath());
  137.             }
  138.             if (!parent.canWrite()) {
  139.                 throw new IOException(
  140.                         "Do not have write permission for directory "
  141.                                 + parent.getAbsolutePath());
  142.             }

  143.             stream = new BufferedOutputStream(
  144.                     new FileOutputStream(file, append));
  145.         } else {
  146.             throw new IllegalArgumentException(
  147.                     "Expected an OutputStream or File");
  148.         }

  149.         return stream;
  150.     }

  151.     /**
  152.      * Same as calling getOutputStream(obj, false). If obj is a file, it will
  153.      * open a new output stream and will not append.
  154.      *
  155.      * @param obj
  156.      *            an OutputStream or File.
  157.      * @return an OutputStream. If obj is a File, the stream is Buffered.
  158.      * @throws IOException
  159.      *             if an error occurs.
  160.      */
  161.     public static OutputStream getOutputStream(final Object obj)
  162.             throws IOException {
  163.         return getOutputStream(obj, false);
  164.     }

  165.     /**
  166.      * Read stream contents into a byte array.
  167.      *
  168.      * @param from
  169.      *            stream to read.
  170.      * @return byte array of file content.
  171.      * @throws IOException
  172.      *             if an error occurs while reading.
  173.      */
  174.     public static byte[] readStream(final Object from) throws IOException {
  175.         ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  176.         transferStream(from, buffer);
  177.         return buffer.toByteArray();
  178.     }

  179.     /**
  180.      * Transfer contents of Object from to Object to.
  181.      *
  182.      * Calls transferStream(from, to, DEFAULT_BUFFER_SIZE).
  183.      *
  184.      * @param from
  185.      *            streamable source.
  186.      * @param to
  187.      *            streamable target.
  188.      * @throws IOException
  189.      *            if IO error occurs
  190.      */
  191.     public static void transferStream(final Object from, final Object to)
  192.             throws IOException {
  193.         transferStream(from, to, DEFAULT_BUFFER_SIZE);
  194.     }

  195.     /**
  196.      * Transfer contents of Object from to Object to. Uses getInputStream and
  197.      * getOutputStream to generate streams. Streams are closed after reading.
  198.      *
  199.      * @param from
  200.      *            streamable source.
  201.      * @param to
  202.      *            streamable target.
  203.      * @param bufferSize
  204.      *            size of buffer
  205.      * @throws IOException
  206.      *             if thrown by calls to read/write on streams.
  207.      */
  208.     public static void transferStream(final Object from, final Object to,
  209.             final int bufferSize) throws IOException {
  210.         InputStream in = null;
  211.         OutputStream out = null;

  212.         try {
  213.             in = getInputStream(from);
  214.             out = getOutputStream(to);
  215.             byte[] buffer = new byte[bufferSize];
  216.             int read;
  217.             while ((read = in.read(buffer, 0, bufferSize)) != -1) {
  218.                 out.write(buffer, 0, read);
  219.             }
  220.             closeStream(in);
  221.             closeStream(out);
  222.         } catch (Exception e) {
  223.             closeStream(in);
  224.             closeStream(out);
  225.             if (e instanceof IOException) {
  226.                 throw (IOException) e;
  227.             }
  228.         }
  229.     }

  230.     /**
  231.      * Close an InputStream or OutputStream.
  232.      *
  233.      * @param stream
  234.      *            stream to close.
  235.      */
  236.     public static void closeStream(final Object stream) {
  237.         try {
  238.             if (stream instanceof OutputStream) {
  239.                 OutputStream out = (OutputStream) stream;
  240.                 try {
  241.                     out.flush();
  242.                 } finally {
  243.                     out.close();
  244.                 }
  245.             } else if (stream instanceof InputStream) {
  246.                 ((InputStream) stream).close();
  247.             }
  248.         } catch (Exception e) {
  249.             // ignore
  250.         }
  251.     }

  252.     /**
  253.      * An InputStream that ignores calls to close.
  254.      *
  255.      * Used for methods that automatically close a stream at EOF, even though it
  256.      * is undesirable for the stream to be closed, such as when using a
  257.      * ZipInputStream.
  258.      *
  259.      * @author jmfee
  260.      *
  261.      */
  262.     public static class UnclosableInputStream extends FilterInputStream {

  263.         /**
  264.          * Create a new UnclosableInputStream object.
  265.          *
  266.          * @param in
  267.          *            the InputStream to wrap.
  268.          */
  269.         public UnclosableInputStream(final InputStream in) {
  270.             super(in);
  271.         }

  272.         /**
  273.          * Does not close stream.
  274.          */
  275.         public void close() {
  276.             // ignore
  277.         }
  278.     }

  279.     /**
  280.      * An OutputStream that ignores calls to close.
  281.      *
  282.      * Used for methods that automatically close a stream, even though it is
  283.      * undesirable for the stream to be closed, such as when using a
  284.      * ZipOutputStream.
  285.      *
  286.      * @author jmfee
  287.      *
  288.      */
  289.     public static class UnclosableOutputStream extends FilterOutputStream {

  290.         /**
  291.          * Create a new UnclosableOutputStream object.
  292.          *
  293.          * @param out
  294.          *            the OutputStream to wrap.
  295.          */
  296.         public UnclosableOutputStream(final OutputStream out) {
  297.             super(out);
  298.         }

  299.         /**
  300.          * Flush written content, but does not close stream.
  301.          */
  302.         public void close() throws IOException {
  303.             out.flush();
  304.             // otherwise ignore
  305.         }
  306.     }

  307. }