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[].<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 }