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 package org.apache.commons.io.output;
18
19 import java.io.BufferedInputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23
24 import org.apache.commons.io.IOUtils;
25 import org.apache.commons.io.build.AbstractOrigin;
26 import org.apache.commons.io.build.AbstractStreamBuilder;
27 import org.apache.commons.io.function.Uncheck;
28 import org.apache.commons.io.input.UnsynchronizedByteArrayInputStream;
29
30 /**
31 * Implements a version of {@link AbstractByteArrayOutputStream} <strong>without</strong> any concurrent thread safety.
32 * <p>
33 * To build an instance, use {@link Builder}.
34 * </p>
35 *
36 * @see Builder
37 * @since 2.7
38 */
39 //@NotThreadSafe
40 public final class UnsynchronizedByteArrayOutputStream extends AbstractByteArrayOutputStream<UnsynchronizedByteArrayOutputStream> {
41
42 // @formatter:off
43 /**
44 * Builds a new {@link UnsynchronizedByteArrayOutputStream}.
45 *
46 * <p>
47 * Using File IO:
48 * </p>
49 * <pre>{@code
50 * UnsynchronizedByteArrayOutputStream s = UnsynchronizedByteArrayOutputStream.builder()
51 * .setBufferSize(8192)
52 * .get();}
53 * </pre>
54 * <p>
55 * Using NIO Path:
56 * </p>
57 * <pre>{@code
58 * UnsynchronizedByteArrayOutputStream s = UnsynchronizedByteArrayOutputStream.builder()
59 * .setBufferSize(8192)
60 * .get();}
61 * </pre>
62 *
63 * @see #get()
64 */
65 // @formatter:on
66 public static class Builder extends AbstractStreamBuilder<UnsynchronizedByteArrayOutputStream, Builder> {
67
68 /**
69 * Constructs a new builder of {@link UnsynchronizedByteArrayOutputStream}.
70 */
71 public Builder() {
72 // empty
73 }
74
75 /**
76 * Builds a new {@link UnsynchronizedByteArrayOutputStream}.
77 *
78 * <p>
79 * This builder uses the following aspects:
80 * </p>
81 * <ul>
82 * <li>{@link #getBufferSize()}</li>
83 * </ul>
84 *
85 * @return a new instance.
86 * @see AbstractOrigin#getByteArray()
87 * @see #getUnchecked()
88 */
89 @Override
90 public UnsynchronizedByteArrayOutputStream get() {
91 return new UnsynchronizedByteArrayOutputStream(this);
92 }
93
94 }
95
96 /**
97 * Constructs a new {@link Builder}.
98 *
99 * @return a new {@link Builder}.
100 */
101 public static Builder builder() {
102 return new Builder();
103 }
104
105 /**
106 * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream.
107 * <p>
108 * This method is useful where,
109 * </p>
110 * <ul>
111 * <li>Source InputStream is slow.</li>
112 * <li>It has network resources associated, so we cannot keep it open for long time.</li>
113 * <li>It has network timeout associated.</li>
114 * </ul>
115 * <p>
116 * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].
117 * </p>
118 * <p>
119 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}.
120 * </p>
121 *
122 * @param input Stream to be fully buffered.
123 * @return A fully buffered stream.
124 * @throws IOException if an I/O error occurs.
125 */
126 public static InputStream toBufferedInputStream(final InputStream input) throws IOException {
127 return toBufferedInputStream(input, DEFAULT_SIZE);
128 }
129
130 /**
131 * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream.
132 * <p>
133 * This method is useful where,
134 * </p>
135 * <ul>
136 * <li>Source InputStream is slow.</li>
137 * <li>It has network resources associated, so we cannot keep it open for long time.</li>
138 * <li>It has network timeout associated.</li>
139 * </ul>
140 * <p>
141 * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].
142 * </p>
143 * <p>
144 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}.
145 * </p>
146 *
147 * @param input Stream to be fully buffered.
148 * @param size the initial buffer size.
149 * @return A fully buffered stream.
150 * @throws IOException if an I/O error occurs.
151 */
152 public static InputStream toBufferedInputStream(final InputStream input, final int size) throws IOException {
153 // It does not matter if a ByteArrayOutputStream is not closed as close() is a no-op
154 try (UnsynchronizedByteArrayOutputStream output = builder().setBufferSize(size).get()) {
155 output.write(input);
156 return output.toInputStream();
157 }
158 }
159
160 /**
161 * Constructs a new byte array output stream. The buffer capacity is initially.
162 *
163 * {@value AbstractByteArrayOutputStream#DEFAULT_SIZE} bytes, though its size increases if necessary.
164 *
165 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}.
166 */
167 @Deprecated
168 public UnsynchronizedByteArrayOutputStream() {
169 this(DEFAULT_SIZE);
170 }
171
172 private UnsynchronizedByteArrayOutputStream(final Builder builder) {
173 this(builder.getBufferSize());
174 }
175
176 /**
177 * Constructs a new byte array output stream, with a buffer capacity of the specified size, in bytes.
178 *
179 * @param size the initial size.
180 * @throws IllegalArgumentException if size is negative.
181 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. Will be private in 3.0.0.
182 */
183 @Deprecated
184 public UnsynchronizedByteArrayOutputStream(final int size) {
185 if (size < 0) {
186 throw new IllegalArgumentException("Negative initial size: " + size);
187 }
188 needNewBuffer(size);
189 }
190
191 /**
192 * @see java.io.ByteArrayOutputStream#reset()
193 */
194 @Override
195 public void reset() {
196 resetImpl();
197 }
198
199 @Override
200 public int size() {
201 return count;
202 }
203
204 @Override
205 public byte[] toByteArray() {
206 return toByteArrayImpl();
207 }
208
209 @Override
210 public InputStream toInputStream() {
211 // @formatter:off
212 return toInputStream((buffer, offset, length) -> Uncheck
213 .get(() -> UnsynchronizedByteArrayInputStream.builder()
214 .setByteArray(buffer)
215 .setOffset(offset)
216 .setLength(length)
217 .get()));
218 // @formatter:on
219 }
220
221 @Override
222 public void write(final byte[] b, final int off, final int len) {
223 IOUtils.checkFromIndexSize(b, off, len);
224 if (len == 0) {
225 return;
226 }
227 writeImpl(b, off, len);
228 }
229
230 @Override
231 public int write(final InputStream in) throws IOException {
232 return writeImpl(in);
233 }
234
235 @Override
236 public void write(final int b) {
237 writeImpl(b);
238 }
239
240 @Override
241 public void writeTo(final OutputStream out) throws IOException {
242 writeToImpl(out);
243 }
244 }