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    *      http://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} <b>without</b> 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 {
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           * Builds a new {@link UnsynchronizedByteArrayOutputStream}.
69           *
70           * <p>
71           * This builder use the following aspects:
72           * </p>
73           * <ul>
74           * <li>{@link #getBufferSize()}</li>
75           * </ul>
76           *
77           * @return a new instance.
78           * @see AbstractOrigin#getByteArray()
79           */
80          @Override
81          public UnsynchronizedByteArrayOutputStream get() {
82              return new UnsynchronizedByteArrayOutputStream(getBufferSize());
83          }
84  
85      }
86  
87      /**
88       * Constructs a new {@link Builder}.
89       *
90       * @return a new {@link Builder}.
91       */
92      public static Builder builder() {
93          return new Builder();
94      }
95  
96      /**
97       * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream.
98       * <p>
99       * This method is useful where,
100      * </p>
101      * <ul>
102      * <li>Source InputStream is slow.</li>
103      * <li>It has network resources associated, so we cannot keep it open for long time.</li>
104      * <li>It has network timeout associated.</li>
105      * </ul>
106      * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].<br>
107      * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}.
108      *
109      * @param input Stream to be fully buffered.
110      * @return A fully buffered stream.
111      * @throws IOException if an I/O error occurs.
112      */
113     public static InputStream toBufferedInputStream(final InputStream input) throws IOException {
114         return toBufferedInputStream(input, DEFAULT_SIZE);
115     }
116 
117     /**
118      * Fetches entire contents of an {@link InputStream} and represent same data as result InputStream.
119      * <p>
120      * This method is useful where,
121      * </p>
122      * <ul>
123      * <li>Source InputStream is slow.</li>
124      * <li>It has network resources associated, so we cannot keep it open for long time.</li>
125      * <li>It has network timeout associated.</li>
126      * </ul>
127      * It can be used in favor of {@link #toByteArray()}, since it avoids unnecessary allocation and copy of byte[].<br>
128      * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}.
129      *
130      * @param input Stream to be fully buffered.
131      * @param size the initial buffer size
132      * @return A fully buffered stream.
133      * @throws IOException if an I/O error occurs.
134      */
135     public static InputStream toBufferedInputStream(final InputStream input, final int size) throws IOException {
136         // It does not matter if a ByteArrayOutputStream is not closed as close() is a no-op
137         try (UnsynchronizedByteArrayOutputStream output = builder().setBufferSize(size).get()) {
138             output.write(input);
139             return output.toInputStream();
140         }
141     }
142 
143     /**
144      * Constructs a new byte array output stream. The buffer capacity is initially
145      *
146      * {@value AbstractByteArrayOutputStream#DEFAULT_SIZE} bytes, though its size increases if necessary.
147      * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}.
148      */
149     @Deprecated
150     public UnsynchronizedByteArrayOutputStream() {
151         this(DEFAULT_SIZE);
152     }
153 
154     /**
155      * Constructs a new byte array output stream, with a buffer capacity of the specified size, in bytes.
156      *
157      * @param size the initial size
158      * @throws IllegalArgumentException if size is negative
159      * @deprecated Use {@link #builder()}, {@link Builder}, and {@link Builder#get()}. Will be private in 3.0.0.
160      */
161     @Deprecated
162     public UnsynchronizedByteArrayOutputStream(final int size) {
163         if (size < 0) {
164             throw new IllegalArgumentException("Negative initial size: " + size);
165         }
166         needNewBuffer(size);
167     }
168 
169     /**
170      * @see java.io.ByteArrayOutputStream#reset()
171      */
172     @Override
173     public void reset() {
174         resetImpl();
175     }
176 
177     @Override
178     public int size() {
179         return count;
180     }
181 
182     @Override
183     public byte[] toByteArray() {
184         return toByteArrayImpl();
185     }
186 
187     @Override
188     public InputStream toInputStream() {
189         // @formatter:off
190         return toInputStream((buffer, offset, length) -> Uncheck
191                 .get(() -> UnsynchronizedByteArrayInputStream.builder()
192                         .setByteArray(buffer)
193                         .setOffset(offset)
194                         .setLength(length)
195                         .get()));
196         // @formatter:on
197     }
198 
199     @Override
200     public void write(final byte[] b, final int off, final int len) {
201         if (off < 0 || off > b.length || len < 0 || off + len > b.length || off + len < 0) {
202             throw new IndexOutOfBoundsException(String.format("offset=%,d, length=%,d", off, len));
203         }
204         if (len == 0) {
205             return;
206         }
207         writeImpl(b, off, len);
208     }
209 
210     @Override
211     public int write(final InputStream in) throws IOException {
212         return writeImpl(in);
213     }
214 
215     @Override
216     public void write(final int b) {
217         writeImpl(b);
218     }
219 
220     @Override
221     public void writeTo(final OutputStream out) throws IOException {
222         writeToImpl(out);
223     }
224 }