001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006     * See the AUTHORS.txt file in the distribution for a full listing of 
007     * individual contributors. 
008     *
009     * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010     * is licensed to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     *
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.common.util;
025    
026    import java.io.BufferedInputStream;
027    import java.io.ByteArrayOutputStream;
028    import java.io.File;
029    import java.io.FileInputStream;
030    import java.io.FileReader;
031    import java.io.IOException;
032    import java.io.InputStream;
033    import java.io.InputStreamReader;
034    import java.io.OutputStream;
035    import java.io.Reader;
036    import java.io.Writer;
037    import java.util.Arrays;
038    
039    /**
040     * @author Randall Hauch
041     */
042    public class IoUtil {
043    
044        /**
045         * Read and return the entire contents of the supplied {@link InputStream stream}. This method always closes the stream when
046         * finished reading.
047         * 
048         * @param stream the stream to the contents; may be null
049         * @return the contents, or an empty byte array if the supplied reader is null
050         * @throws IOException if there is an error reading the content
051         */
052        public static byte[] readBytes( InputStream stream ) throws IOException {
053            if (stream == null) return new byte[] {};
054            byte[] buffer = new byte[1024];
055            ByteArrayOutputStream output = new ByteArrayOutputStream();
056            boolean error = false;
057            try {
058                int numRead = 0;
059                while ((numRead = stream.read(buffer)) > -1) {
060                    output.write(buffer, 0, numRead);
061                }
062            } catch (IOException e) {
063                error = true; // this error should be thrown, even if there is an error closing stream
064                throw e;
065            } catch (RuntimeException e) {
066                error = true; // this error should be thrown, even if there is an error closing stream
067                throw e;
068            } finally {
069                try {
070                    stream.close();
071                } catch (IOException e) {
072                    if (!error) throw e;
073                }
074            }
075            output.flush();
076            return output.toByteArray();
077        }
078    
079        /**
080         * Read and return the entire contents of the supplied {@link File file}.
081         * 
082         * @param file the file containing the contents; may be null
083         * @return the contents, or an empty byte array if the supplied file is null
084         * @throws IOException if there is an error reading the content
085         */
086        public static byte[] readBytes( File file ) throws IOException {
087            if (file == null) return new byte[] {};
088            InputStream stream = new BufferedInputStream(new FileInputStream(file));
089            boolean error = false;
090            try {
091                return readBytes(stream);
092            } catch (IOException e) {
093                error = true; // this error should be thrown, even if there is an error closing stream
094                throw e;
095            } catch (RuntimeException e) {
096                error = true; // this error should be thrown, even if there is an error closing stream
097                throw e;
098            } finally {
099                try {
100                    stream.close();
101                } catch (IOException e) {
102                    if (!error) throw e;
103                }
104            }
105        }
106    
107        /**
108         * Read and return the entire contents of the supplied {@link Reader}. This method always closes the reader when finished
109         * reading.
110         * 
111         * @param reader the reader of the contents; may be null
112         * @return the contents, or an empty string if the supplied reader is null
113         * @throws IOException if there is an error reading the content
114         */
115        public static String read( Reader reader ) throws IOException {
116            if (reader == null) return "";
117            StringBuilder sb = new StringBuilder();
118            boolean error = false;
119            try {
120                int numRead = 0;
121                char[] buffer = new char[1024];
122                while ((numRead = reader.read(buffer)) > -1) {
123                    sb.append(buffer, 0, numRead);
124                }
125            } catch (IOException e) {
126                error = true; // this error should be thrown, even if there is an error closing reader
127                throw e;
128            } catch (RuntimeException e) {
129                error = true; // this error should be thrown, even if there is an error closing reader
130                throw e;
131            } finally {
132                try {
133                    reader.close();
134                } catch (IOException e) {
135                    if (!error) throw e;
136                }
137            }
138            return sb.toString();
139        }
140    
141        /**
142         * Read and return the entire contents of the supplied {@link InputStream}. This method always closes the stream when finished
143         * reading.
144         * 
145         * @param stream the streamed contents; may be null
146         * @return the contents, or an empty string if the supplied stream is null
147         * @throws IOException if there is an error reading the content
148         */
149        public static String read( InputStream stream ) throws IOException {
150            return stream == null ? "" : read(new InputStreamReader(stream));
151        }
152    
153        /**
154         * Read and return the entire contents of the supplied {@link File}.
155         * 
156         * @param file the file containing the information to be read; may be null
157         * @return the contents, or an empty string if the supplied reader is null
158         * @throws IOException if there is an error reading the content
159         */
160        public static String read( File file ) throws IOException {
161            if (file == null) return "";
162            StringBuilder sb = new StringBuilder();
163            boolean error = false;
164            Reader reader = new FileReader(file);
165            try {
166                int numRead = 0;
167                char[] buffer = new char[1024];
168                while ((numRead = reader.read(buffer)) > -1) {
169                    sb.append(buffer, 0, numRead);
170                }
171            } catch (IOException e) {
172                error = true; // this error should be thrown, even if there is an error closing reader
173                throw e;
174            } catch (RuntimeException e) {
175                error = true; // this error should be thrown, even if there is an error closing reader
176                throw e;
177            } finally {
178                try {
179                    reader.close();
180                } catch (IOException e) {
181                    if (!error) throw e;
182                }
183            }
184            return sb.toString();
185        }
186    
187        /**
188         * Write the entire contents of the supplied string to the given stream. This method always flushes and closes the stream when
189         * finished.
190         * 
191         * @param content the content to write to the stream; may be null
192         * @param stream the stream to which the content is to be written
193         * @throws IOException
194         * @throws IllegalArgumentException if the stream is null
195         */
196        public static void write( String content,
197                                  OutputStream stream ) throws IOException {
198            CheckArg.isNotNull(stream, "destination stream");
199            boolean error = false;
200            try {
201                if (content != null) {
202                    byte[] bytes = content.getBytes();
203                    stream.write(bytes, 0, bytes.length);
204                }
205            } catch (IOException e) {
206                error = true; // this error should be thrown, even if there is an error flushing/closing stream
207                throw e;
208            } catch (RuntimeException e) {
209                error = true; // this error should be thrown, even if there is an error flushing/closing stream
210                throw e;
211            } finally {
212                try {
213                    stream.flush();
214                } catch (IOException e) {
215                    if (!error) throw e;
216                } finally {
217                    try {
218                        stream.close();
219                    } catch (IOException e) {
220                        if (!error) throw e;
221                    }
222                }
223            }
224        }
225    
226        /**
227         * Write the entire contents of the supplied string to the given writer. This method always flushes and closes the writer when
228         * finished.
229         * 
230         * @param content the content to write to the writer; may be null
231         * @param writer the writer to which the content is to be written
232         * @throws IOException
233         * @throws IllegalArgumentException if the writer is null
234         */
235        public static void write( String content,
236                                  Writer writer ) throws IOException {
237            CheckArg.isNotNull(writer, "destination writer");
238            boolean error = false;
239            try {
240                if (content != null) {
241                    writer.write(content);
242                }
243            } catch (IOException e) {
244                error = true; // this error should be thrown, even if there is an error flushing/closing writer
245                throw e;
246            } catch (RuntimeException e) {
247                error = true; // this error should be thrown, even if there is an error flushing/closing writer
248                throw e;
249            } finally {
250                try {
251                    writer.flush();
252                } catch (IOException e) {
253                    if (!error) throw e;
254                } finally {
255                    try {
256                        writer.close();
257                    } catch (IOException e) {
258                        if (!error) throw e;
259                    }
260                }
261            }
262        }
263    
264        /**
265         * Write the entire contents of the supplied string to the given stream. This method always flushes and closes the stream when
266         * finished.
267         * 
268         * @param input the content to write to the stream; may be null
269         * @param stream the stream to which the content is to be written
270         * @throws IOException
271         * @throws IllegalArgumentException if the stream is null
272         */
273        public static void write( InputStream input,
274                                  OutputStream stream ) throws IOException {
275            CheckArg.isNotNull(stream, "destination stream");
276            boolean error = false;
277            try {
278                if (input != null) {
279                    byte[] buffer = new byte[1024];
280                    try {
281                        int numRead = 0;
282                        while ((numRead = input.read(buffer)) > -1) {
283                            stream.write(buffer, 0, numRead);
284                        }
285                    } finally {
286                        input.close();
287                    }
288                }
289            } catch (IOException e) {
290                error = true; // this error should be thrown, even if there is an error flushing/closing stream
291                throw e;
292            } catch (RuntimeException e) {
293                error = true; // this error should be thrown, even if there is an error flushing/closing stream
294                throw e;
295            } finally {
296                try {
297                    stream.flush();
298                } catch (IOException e) {
299                    if (!error) throw e;
300                } finally {
301                    try {
302                        stream.close();
303                    } catch (IOException e) {
304                        if (!error) throw e;
305                    }
306                }
307            }
308        }
309    
310        /**
311         * Write the entire contents of the supplied string to the given writer. This method always flushes and closes the writer when
312         * finished.
313         * 
314         * @param input the content to write to the writer; may be null
315         * @param writer the writer to which the content is to be written
316         * @throws IOException
317         * @throws IllegalArgumentException if the writer is null
318         */
319        public static void write( Reader input,
320                                  Writer writer ) throws IOException {
321            CheckArg.isNotNull(writer, "destination writer");
322            boolean error = false;
323            try {
324                if (input != null) {
325                    char[] buffer = new char[1024];
326                    try {
327                        int numRead = 0;
328                        while ((numRead = input.read(buffer)) > -1) {
329                            writer.write(buffer, 0, numRead);
330                        }
331                    } finally {
332                        input.close();
333                    }
334                }
335            } catch (IOException e) {
336                error = true; // this error should be thrown, even if there is an error flushing/closing writer
337                throw e;
338            } catch (RuntimeException e) {
339                error = true; // this error should be thrown, even if there is an error flushing/closing writer
340                throw e;
341            } finally {
342                try {
343                    writer.flush();
344                } catch (IOException e) {
345                    if (!error) throw e;
346                } finally {
347                    try {
348                        writer.close();
349                    } catch (IOException e) {
350                        if (!error) throw e;
351                    }
352                }
353            }
354        }
355    
356        /**
357         * Write the entire contents of the supplied string to the given stream. This method always flushes and closes the stream when
358         * finished.
359         * 
360         * @param input1 the first stream
361         * @param input2 the second stream
362         * @return true if the streams contain the same content, or false otherwise
363         * @throws IOException
364         * @throws IllegalArgumentException if the stream is null
365         */
366        public static boolean isSame( InputStream input1,
367                                      InputStream input2 ) throws IOException {
368            CheckArg.isNotNull(input1, "input1");
369            CheckArg.isNotNull(input2, "input2");
370            boolean error = false;
371            try {
372                byte[] buffer1 = new byte[1024];
373                byte[] buffer2 = new byte[1024];
374                try {
375                    int numRead1 = 0;
376                    int numRead2 = 0;
377                    while (true) {
378                        numRead1 = input1.read(buffer1);
379                        numRead2 = input2.read(buffer2);
380                        if (numRead1 > -1) {
381                            if (numRead2 != numRead1) return false;
382                            // Otherwise same number of bytes read
383                            if (!Arrays.equals(buffer1, buffer2)) return false;
384                            // Otherwise same bytes read, so continue ...
385                        } else {
386                            // Nothing more in stream 1 ...
387                            return numRead2 < 0;
388                        }
389                    }
390                } finally {
391                    input1.close();
392                }
393            } catch (IOException e) {
394                error = true; // this error should be thrown, even if there is an error closing stream 2
395                throw e;
396            } catch (RuntimeException e) {
397                error = true; // this error should be thrown, even if there is an error closing stream 2
398                throw e;
399            } finally {
400                try {
401                    input2.close();
402                } catch (IOException e) {
403                    if (!error) throw e;
404                }
405            }
406        }
407    
408        private IoUtil() {
409            // Prevent construction
410        }
411    }