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[].<br>
117 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}.
118 * </p>
119 *
120 * @param input Stream to be fully buffered.
121 * @return A fully buffered stream.
122 * @throws IOException if an I/O error occurs.
123 */
124 public static InputStream toBufferedInputStream(final InputStream input) throws IOException {
125 return toBufferedInputStream(input, DEFAULT_SIZE);
126 }
127
128 /**
129 * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream.
130 * <p>
131 * This method is useful where,
132 * </p>
133 * <ul>
134 * <li>Source InputStream is slow.</li>
135 * <li>It has network resources associated, so we cannot keep it open for long time.</li>
136 * <li>It has network timeout associated.</li>
137 * </ul>
138 * <p>
139 * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].<br>
140 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}.
141 * </p>
142 *
143 * @param input Stream to be fully buffered.
144 * @param size the initial buffer size.
145 * @return A fully buffered stream.
146 * @throws IOException if an I/O error occurs.
147 */
148 public static InputStream toBufferedInputStream(final InputStream input, final int size) throws IOException {
149 // It does not matter if a ByteArrayOutputStream is not closed as close() is a no-op
150 try (UnsynchronizedByteArrayOutputStream output = builder().setBufferSize(size).get()) {
151 output.write(input);
152 return output.toInputStream();
153 }
154 }
155
156 /**
157 * Constructs a new byte array output stream. The buffer capacity is initially.
158 *
159 * {@value AbstractByteArrayOutputStream#DEFAULT_SIZE} bytes, though its size increases if necessary.
160 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}.
161 */
162 @Deprecated
163 public UnsynchronizedByteArrayOutputStream() {
164 this(DEFAULT_SIZE);
165 }
166
167 private UnsynchronizedByteArrayOutputStream(final Builder builder) {
168 this(builder.getBufferSize());
169 }
170
171 /**
172 * Constructs a new byte array output stream, with a buffer capacity of the specified size, in bytes.
173 *
174 * @param size the initial size.
175 * @throws IllegalArgumentException if size is negative.
176 * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. Will be private in 3.0.0.
177 */
178 @Deprecated
179 public UnsynchronizedByteArrayOutputStream(final int size) {
180 if (size < 0) {
181 throw new IllegalArgumentException("Negative initial size: " + size);
182 }
183 needNewBuffer(size);
184 }
185
186 /**
187 * @see java.io.ByteArrayOutputStream#reset()
188 */
189 @Override
190 public void reset() {
191 resetImpl();
192 }
193
194 @Override
195 public int size() {
196 return count;
197 }
198
199 @Override
200 public byte[] toByteArray() {
201 return toByteArrayImpl();
202 }
203
204 @Override
205 public InputStream toInputStream() {
206 // @formatter:off
207 return toInputStream((buffer, offset, length) -> Uncheck
208 .get(() -> UnsynchronizedByteArrayInputStream.builder()
209 .setByteArray(buffer)
210 .setOffset(offset)
211 .setLength(length)
212 .get()));
213 // @formatter:on
214 }
215
216 @Override
217 public void write(final byte[] b, final int off, final int len) {
218 IOUtils.checkFromIndexSize(b, off, len);
219 if (len == 0) {
220 return;
221 }
222 writeImpl(b, off, len);
223 }
224
225 @Override
226 public int write(final InputStream in) throws IOException {
227 return writeImpl(in);
228 }
229
230 @Override
231 public void write(final int b) {
232 writeImpl(b);
233 }
234
235 @Override
236 public void writeTo(final OutputStream out) throws IOException {
237 writeToImpl(out);
238 }
239 }