View Javadoc
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 }