001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.util.io;
018
019import java.io.BufferedReader;
020import java.io.IOException;
021import java.io.InputStream;
022import java.io.InputStreamReader;
023import java.io.OutputStream;
024import java.io.Reader;
025import java.net.URL;
026import java.net.URLConnection;
027import java.util.Properties;
028
029import org.apache.wicket.util.lang.Args;
030
031/**
032 * Utilities methods for working with input and output streams.
033 * 
034 * @author Jonathan Locke
035 * @author Igor Vaynberg
036 */
037public final class Streams
038{
039        /**
040         * Writes the input stream to the output stream. Input is done without a Reader object, meaning
041         * that the input is copied in its raw form. After it is copied it will close the streams.
042         * 
043         * @param in
044         *            The input stream
045         * @param out
046         *            The output stream
047         * @return Number of bytes copied from one stream to the other
048         * @throws IOException
049         */
050        public static int copyAndClose(final InputStream in, final OutputStream out) throws IOException
051        {
052                try
053                {
054                        return copy(in, out);
055                }
056                finally
057                {
058                        IOUtils.closeQuietly(in);
059                        IOUtils.closeQuietly(out);
060                }
061        }
062
063        /**
064         * Writes the input stream to the output stream. Input is done without a Reader object, meaning
065         * that the input is copied in its raw form.
066         * 
067         * @param in
068         *            The input stream
069         * @param out
070         *            The output stream
071         * @return Number of bytes copied from one stream to the other
072         * @throws IOException
073         */
074        public static int copy(final InputStream in, final OutputStream out) throws IOException
075        {
076                return copy(in, out, 4096);
077        }
078
079        /**
080         * Writes the input stream to the output stream. Input is done without a Reader object, meaning
081         * that the input is copied in its raw form.
082         * 
083         * @param in
084         *            The input stream
085         * @param out
086         *            The output stream
087         * @param bufSize
088         *            The buffer size. A good value is 4096.
089         * @return Number of bytes copied from one stream to the other
090         * @throws IOException
091         */
092        public static int copy(final InputStream in, final OutputStream out, final int bufSize)
093                throws IOException
094        {
095                if (bufSize <= 0)
096                {
097                        throw new IllegalArgumentException("The parameter 'bufSize' must not be <= 0");
098                }
099
100                final byte[] buffer = new byte[bufSize];
101                int bytesCopied = 0;
102                while (true)
103                {
104                        int byteCount = in.read(buffer, 0, buffer.length);
105                        if (byteCount <= 0)
106                        {
107                                break;
108                        }
109                        out.write(buffer, 0, byteCount);
110                        bytesCopied += byteCount;
111                }
112                return bytesCopied;
113        }
114
115        /**
116         * Loads properties from an XML input stream into the provided properties object.
117         * 
118         * @param properties
119         *            The object to load the properties into
120         * @param inputStream
121         * @throws IOException
122         *             When the input stream could not be read from
123         */
124        public static void loadFromXml(final Properties properties, final InputStream inputStream)
125                throws IOException
126        {
127                if (properties == null)
128                {
129                        throw new IllegalArgumentException("properties must not be null");
130                }
131                if (inputStream == null)
132                {
133                        throw new IllegalArgumentException("inputStream must not be null");
134                }
135
136                properties.loadFromXML(inputStream);
137        }
138
139        /**
140         * Sets the connection to a URL as non-caching and returns the input stream.
141         *
142         * @param url
143         *      the url to read from
144         * @return the input stream for this url
145         * @throws IOException when a connection cannot be opened
146         */
147        public static InputStream readNonCaching(final URL url) throws IOException
148        {
149                Args.notNull(url, "url");
150
151                URLConnection urlConnection = url.openConnection();
152                urlConnection.setUseCaches(false);
153                InputStream inputStream = urlConnection.getInputStream();
154                return inputStream;
155        }
156
157        /**
158         * Reads a stream as a string.
159         * 
160         * @param in
161         *            The input stream
162         * @return The string
163         * @throws IOException
164         */
165        public static String readString(final InputStream in) throws IOException
166        {
167                return readString(new BufferedReader(new InputStreamReader(in)));
168        }
169
170        /**
171         * Reads a string using a character encoding.
172         * 
173         * @param in
174         *            The input
175         * @param encoding
176         *            The character encoding of the input data
177         * @return The string
178         * @throws IOException
179         */
180        public static String readString(final InputStream in, final CharSequence encoding)
181                throws IOException
182        {
183                return readString(new BufferedReader(new InputStreamReader(in, encoding.toString())));
184        }
185
186        /**
187         * Reads all input from a reader into a string.
188         * 
189         * @param in
190         *            The input
191         * @return The string
192         * @throws IOException
193         */
194        public static String readString(final Reader in) throws IOException
195        {
196                final StringBuilder buffer = new StringBuilder(2048);
197                int value;
198
199                while ((value = in.read()) != -1)
200                {
201                        buffer.append((char)value);
202                }
203
204                return buffer.toString();
205        }
206
207        /**
208         * Private to prevent instantiation.
209         */
210        private Streams()
211        {
212        }
213}