1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net.io;
19
20 import java.io.Closeable;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.io.OutputStreamWriter;
25 import java.io.PrintStream;
26 import java.io.PrintWriter;
27 import java.io.Reader;
28 import java.io.Writer;
29 import java.net.Socket;
30 import java.nio.charset.Charset;
31 import java.util.concurrent.atomic.AtomicLong;
32
33 import org.apache.commons.io.IOUtils;
34 import org.apache.commons.io.output.ProxyOutputStream;
35 import org.apache.commons.io.output.ProxyWriter;
36
37 /**
38 * The Util class cannot be instantiated and stores short static convenience methods that are often quite useful.
39 *
40 * @see CopyStreamException
41 * @see CopyStreamListener
42 * @see CopyStreamAdapter
43 */
44 public final class Util {
45
46 /**
47 * The default buffer size ({@value}) used by {@link #copyStream copyStream} and {@link #copyReader copyReader} and by the copyReader/copyStream methods if
48 * a zero or negative buffer size is supplied.
49 */
50 public static final int DEFAULT_COPY_BUFFER_SIZE = IOUtils.DEFAULT_BUFFER_SIZE;
51
52 /**
53 * Closes the object quietly, catching rather than throwing IOException. Intended for use from finally blocks.
54 *
55 * @param closeable the object to close, may be {@code null}
56 * @since 3.0
57 * @deprecated Use {@link IOUtils#closeQuietly(Closeable)}.
58 */
59 @Deprecated
60 public static void closeQuietly(final Closeable closeable) {
61 IOUtils.closeQuietly(closeable);
62 }
63
64 /**
65 * Closes the socket quietly, catching rather than throwing IOException. Intended for use from finally blocks.
66 *
67 * @param socket the socket to close, may be {@code null}
68 * @since 3.0
69 * @deprecated Use {@link IOUtils#closeQuietly(Socket)}.
70 */
71 @Deprecated
72 public static void closeQuietly(final Socket socket) {
73 IOUtils.closeQuietly(socket);
74 }
75
76 /**
77 * Same as {@code copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);}
78 *
79 * @param source where to copy from
80 * @param dest where to copy to
81 * @return number of bytes copied
82 * @throws CopyStreamException on error
83 * @deprecated Use {@link IOUtils#copy(Reader, Writer)}.
84 */
85 @Deprecated
86 public static long copyReader(final Reader source, final Writer dest) throws CopyStreamException {
87 return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE);
88 }
89
90 /**
91 * Copies the contents of a Reader to a Writer using a copy buffer of a given size. The contents of the Reader are read until its end is reached, but
92 * neither the source nor the destination are closed. You must do this yourself outside the method call. The number of characters read/written is
93 * returned.
94 *
95 * @param source The source Reader.
96 * @param dest The destination writer.
97 * @param bufferSize The number of characters to buffer during the copy. A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
98 * @return The number of characters read/written in the copy operation.
99 * @throws CopyStreamException If an error occurs while reading from the source or writing to the destination. The CopyStreamException will contain the
100 * number of bytes confirmed to have been transferred before an IOException occurred, and it will also contain the IOException
101 * that caused the error. These values can be retrieved with the CopyStreamException getTotalBytesTransferred() and
102 * getIOException() methods.
103 */
104 public static long copyReader(final Reader source, final Writer dest, final int bufferSize) throws CopyStreamException {
105 return copyReader(source, dest, bufferSize, CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
106 }
107
108 /**
109 * Copies the contents of a Reader to a Writer using a copy buffer of a given size and notifies the provided CopyStreamListener of the progress of the copy
110 * operation by calling its bytesTransferred(long, int) method after each write to the destination. If you wish to notify more than one listener you should
111 * use a CopyStreamAdapter as the listener and register the additional listeners with the CopyStreamAdapter.
112 * <p>
113 * The contents of the Reader are read until its end is reached, but neither the source nor the destination are closed. You must do this yourself outside
114 * the method call. The number of characters read/written is returned.
115 * </p>
116 *
117 * @param source The source Reader.
118 * @param dest The destination writer.
119 * @param bufferSize The number of characters to buffer during the copy. A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
120 * @param streamSize The number of characters in the stream being copied. Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. Not currently
121 * used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)}
122 * @param listener The CopyStreamListener to notify of progress. If this parameter is null, notification is not attempted.
123 * @return The number of characters read/written in the copy operation.
124 * @throws CopyStreamException If an error occurs while reading from the source or writing to the destination. The CopyStreamException will contain the
125 * number of bytes confirmed to have been transferred before an IOException occurred, and it will also contain the IOException
126 * that caused the error. These values can be retrieved with the CopyStreamException getTotalBytesTransferred() and
127 * getIOException() methods.
128 */
129 public static long copyReader(final Reader source, final Writer dest, final int bufferSize, final long streamSize, final CopyStreamListener listener)
130 throws CopyStreamException {
131 final AtomicLong total = new AtomicLong();
132 try {
133 return IOUtils.copyLarge(source, listener == null ? dest : new ProxyWriter(dest) {
134
135 @Override
136 protected void afterWrite(int n) throws IOException {
137 dest.flush();
138 listener.bytesTransferred(total.addAndGet(n), n, streamSize);
139 }
140 }, new char[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]);
141 } catch (IOException e) {
142 throw new CopyStreamException("IOException caught while copying.", total.get(), e);
143 }
144 }
145
146 /**
147 * Same as {@code copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE);}
148 *
149 * @param source where to copy from
150 * @param dest where to copy to
151 * @return number of bytes copied
152 * @throws CopyStreamException on error
153 */
154 public static long copyStream(final InputStream source, final OutputStream dest) throws CopyStreamException {
155 return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE);
156 }
157
158 /**
159 * Copies the contents of an InputStream to an OutputStream using a copy buffer of a given size. The contents of the InputStream are read until the end of
160 * the stream is reached, but neither the source nor the destination are closed. You must do this yourself outside the method call. The number of bytes
161 * read/written is returned.
162 *
163 * @param source The source InputStream.
164 * @param dest The destination OutputStream.
165 * @param bufferSize The number of bytes to buffer during the copy. A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
166 * @return The number of bytes read/written in the copy operation.
167 * @throws CopyStreamException If an error occurs while reading from the source or writing to the destination. The CopyStreamException will contain the
168 * number of bytes confirmed to have been transferred before an IOException occurred, and it will also contain the IOException
169 * that caused the error. These values can be retrieved with the CopyStreamException getTotalBytesTransferred() and
170 * getIOException() methods.
171 */
172 public static long copyStream(final InputStream source, final OutputStream dest, final int bufferSize) throws CopyStreamException {
173 return copyStream(source, dest, bufferSize, CopyStreamEvent.UNKNOWN_STREAM_SIZE, null);
174 }
175
176 /**
177 * Copies the contents of an InputStream to an OutputStream using a copy buffer of a given size and notifies the provided CopyStreamListener of the progress
178 * of the copy operation by calling its bytesTransferred(long, int) method after each write to the destination. If you wish to notify more than one listener
179 * you should use a CopyStreamAdapter as the listener and register the additional listeners with the CopyStreamAdapter.
180 * <p>
181 * The contents of the InputStream are read until the end of the stream is reached, but neither the source nor the destination are closed. You must do this
182 * yourself outside the method call. The number of bytes read/written is returned.
183 *
184 * @param source The source InputStream.
185 * @param dest The destination OutputStream.
186 * @param bufferSize The number of bytes to buffer during the copy. A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
187 * @param streamSize The number of bytes in the stream being copied. Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. Not currently used
188 * (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)}
189 * @param listener The CopyStreamListener to notify of progress. If this parameter is null, notification is not attempted.
190 * @return number of bytes read/written
191 * @throws CopyStreamException If an error occurs while reading from the source or writing to the destination. The CopyStreamException will contain the
192 * number of bytes confirmed to have been transferred before an IOException occurred, and it will also contain the IOException
193 * that caused the error. These values can be retrieved with the CopyStreamException getTotalBytesTransferred() and
194 * getIOException() methods.
195 */
196 public static long copyStream(final InputStream source, final OutputStream dest, final int bufferSize, final long streamSize,
197 final CopyStreamListener listener) throws CopyStreamException {
198 return copyStream(source, dest, bufferSize, streamSize, listener, true);
199 }
200
201 /**
202 * Copies the contents of an InputStream to an OutputStream using a copy buffer of a given size and notifies the provided CopyStreamListener of the progress
203 * of the copy operation by calling its bytesTransferred(long, int) method after each write to the destination. If you wish to notify more than one listener
204 * you should use a CopyStreamAdapter as the listener and register the additional listeners with the CopyStreamAdapter.
205 * <p>
206 * The contents of the InputStream are read until the end of the stream is reached, but neither the source nor the destination are closed. You must do this
207 * yourself outside the method call. The number of bytes read/written is returned.
208 *
209 * @param source The source InputStream.
210 * @param dest The destination OutputStream.
211 * @param bufferSize The number of bytes to buffer during the copy. A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}.
212 * @param streamSize The number of bytes in the stream being copied. Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. Not currently used
213 * (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)}
214 * @param listener The CopyStreamListener to notify of progress. If this parameter is null, notification is not attempted.
215 * @param flush Whether to flush the output stream after every write. This is necessary for interactive sessions that rely on buffered streams. If you
216 * don't flush, the data will stay in the stream buffer.
217 * @return number of bytes read/written
218 * @throws CopyStreamException If an error occurs while reading from the source or writing to the destination. The CopyStreamException will contain the
219 * number of bytes confirmed to have been transferred before an IOException occurred, and it will also contain the IOException
220 * that caused the error. These values can be retrieved with the CopyStreamException getTotalBytesTransferred() and
221 * getIOException() methods.
222 */
223 public static long copyStream(final InputStream source, final OutputStream dest, final int bufferSize, final long streamSize,
224 final CopyStreamListener listener, final boolean flush) throws CopyStreamException {
225 final AtomicLong total = new AtomicLong();
226 try {
227 return IOUtils.copyLarge(source, listener == null ? dest : new ProxyOutputStream(dest) {
228
229 @Override
230 protected void afterWrite(int n) throws IOException {
231 if (flush) {
232 dest.flush();
233 }
234 listener.bytesTransferred(total.addAndGet(n), n, streamSize);
235 }
236
237 }, new byte[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]);
238 } catch (IOException e) {
239 throw new CopyStreamException("IOException caught while copying.", total.get(), e);
240 }
241 }
242
243 /**
244 * Creates a new PrintWriter using the default encoding.
245 *
246 * @param printStream the target PrintStream.
247 * @return a new PrintWriter.
248 * @since 3.11.0
249 */
250 public static PrintWriter newPrintWriter(final PrintStream printStream) {
251 return new PrintWriter(new OutputStreamWriter(printStream, Charset.defaultCharset()));
252 }
253
254 /** Cannot be instantiated. */
255 private Util() {
256 }
257 }