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