001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.io.output;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.io.OutputStream;
022
023/**
024 * Implements a ThreadSafe version of {@link AbstractByteArrayOutputStream} using instance synchronization.
025 */
026//@ThreadSafe
027public class ByteArrayOutputStream extends AbstractByteArrayOutputStream {
028
029    /**
030     * Creates a new byte array output stream. The buffer capacity is
031     * initially {@value AbstractByteArrayOutputStream#DEFAULT_SIZE} bytes, though its size increases if necessary.
032     */
033    public ByteArrayOutputStream() {
034        this(DEFAULT_SIZE);
035    }
036
037    /**
038     * Creates a new byte array output stream, with a buffer capacity of
039     * the specified size, in bytes.
040     *
041     * @param size  the initial size
042     * @throws IllegalArgumentException if size is negative
043     */
044    public ByteArrayOutputStream(final int size) {
045        if (size < 0) {
046            throw new IllegalArgumentException(
047                "Negative initial size: " + size);
048        }
049        synchronized (this) {
050            needNewBuffer(size);
051        }
052    }
053
054    @Override
055    public void write(final byte[] b, final int off, final int len) {
056        if ((off < 0)
057                || (off > b.length)
058                || (len < 0)
059                || ((off + len) > b.length)
060                || ((off + len) < 0)) {
061            throw new IndexOutOfBoundsException();
062        } else if (len == 0) {
063            return;
064        }
065        synchronized (this) {
066            writeImpl(b, off, len);
067        }
068    }
069
070    @Override
071    public synchronized void write(final int b) {
072        writeImpl(b);
073    }
074
075    @Override
076    public synchronized int write(final InputStream in) throws IOException {
077        return writeImpl(in);
078    }
079
080    @Override
081    public synchronized int size() {
082        return count;
083    }
084
085    /**
086     * @see java.io.ByteArrayOutputStream#reset()
087     */
088    @Override
089    public synchronized void reset() {
090        resetImpl();
091    }
092
093    @Override
094    public synchronized void writeTo(final OutputStream out) throws IOException {
095        writeToImpl(out);
096    }
097
098    /**
099     * Fetches entire contents of an <code>InputStream</code> and represent
100     * same data as result InputStream.
101     * <p>
102     * This method is useful where,
103     * </p>
104     * <ul>
105     * <li>Source InputStream is slow.</li>
106     * <li>It has network resources associated, so we cannot keep it open for
107     * long time.</li>
108     * <li>It has network timeout associated.</li>
109     * </ul>
110     * It can be used in favor of {@link #toByteArray()}, since it
111     * avoids unnecessary allocation and copy of byte[].<br>
112     * This method buffers the input internally, so there is no need to use a
113     * <code>BufferedInputStream</code>.
114     *
115     * @param input Stream to be fully buffered.
116     * @return A fully buffered stream.
117     * @throws IOException if an I/O error occurs
118     * @since 2.0
119     */
120    public static InputStream toBufferedInputStream(final InputStream input)
121            throws IOException {
122        return toBufferedInputStream(input, DEFAULT_SIZE);
123    }
124
125    /**
126     * Fetches entire contents of an <code>InputStream</code> and represent
127     * same data as result InputStream.
128     * <p>
129     * This method is useful where,
130     * </p>
131     * <ul>
132     * <li>Source InputStream is slow.</li>
133     * <li>It has network resources associated, so we cannot keep it open for
134     * long time.</li>
135     * <li>It has network timeout associated.</li>
136     * </ul>
137     * It can be used in favor of {@link #toByteArray()}, since it
138     * avoids unnecessary allocation and copy of byte[].<br>
139     * This method buffers the input internally, so there is no need to use a
140     * <code>BufferedInputStream</code>.
141     *
142     * @param input Stream to be fully buffered.
143     * @param size the initial buffer size
144     * @return A fully buffered stream.
145     * @throws IOException if an I/O error occurs
146     * @since 2.5
147     */
148    public static InputStream toBufferedInputStream(final InputStream input, final int size)
149        throws IOException {
150        try (final ByteArrayOutputStream output = new ByteArrayOutputStream(size)) {
151            output.write(input);
152            return output.toInputStream();
153        }
154    }
155
156    @Override
157    public synchronized InputStream toInputStream() {
158        return toInputStream(java.io.ByteArrayInputStream::new);
159    }
160
161    @Override
162    public synchronized byte[] toByteArray() {
163        return toByteArrayImpl();
164    }
165}