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        }
063        if (len == 0) {
064            return;
065        }
066        synchronized (this) {
067            writeImpl(b, off, len);
068        }
069    }
070
071    @Override
072    public synchronized void write(final int b) {
073        writeImpl(b);
074    }
075
076    @Override
077    public synchronized int write(final InputStream in) throws IOException {
078        return writeImpl(in);
079    }
080
081    @Override
082    public synchronized int size() {
083        return count;
084    }
085
086    /**
087     * @see java.io.ByteArrayOutputStream#reset()
088     */
089    @Override
090    public synchronized void reset() {
091        resetImpl();
092    }
093
094    @Override
095    public synchronized void writeTo(final OutputStream out) throws IOException {
096        writeToImpl(out);
097    }
098
099    /**
100     * Fetches entire contents of an {@code InputStream} and represent
101     * same data as result InputStream.
102     * <p>
103     * This method is useful where,
104     * </p>
105     * <ul>
106     * <li>Source InputStream is slow.</li>
107     * <li>It has network resources associated, so we cannot keep it open for
108     * long time.</li>
109     * <li>It has network timeout associated.</li>
110     * </ul>
111     * It can be used in favor of {@link #toByteArray()}, since it
112     * avoids unnecessary allocation and copy of byte[].<br>
113     * This method buffers the input internally, so there is no need to use a
114     * {@code BufferedInputStream}.
115     *
116     * @param input Stream to be fully buffered.
117     * @return A fully buffered stream.
118     * @throws IOException if an I/O error occurs.
119     * @since 2.0
120     */
121    public static InputStream toBufferedInputStream(final InputStream input)
122            throws IOException {
123        return toBufferedInputStream(input, DEFAULT_SIZE);
124    }
125
126    /**
127     * Fetches entire contents of an {@code InputStream} and represent
128     * same data as result InputStream.
129     * <p>
130     * This method is useful where,
131     * </p>
132     * <ul>
133     * <li>Source InputStream is slow.</li>
134     * <li>It has network resources associated, so we cannot keep it open for
135     * long time.</li>
136     * <li>It has network timeout associated.</li>
137     * </ul>
138     * It can be used in favor of {@link #toByteArray()}, since it
139     * avoids unnecessary allocation and copy of byte[].<br>
140     * This method buffers the input internally, so there is no need to use a
141     * {@code BufferedInputStream}.
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     * @since 2.5
148     */
149    public static InputStream toBufferedInputStream(final InputStream input, final int size)
150        throws IOException {
151        try (final ByteArrayOutputStream output = new ByteArrayOutputStream(size)) {
152            output.write(input);
153            return output.toInputStream();
154        }
155    }
156
157    @Override
158    public synchronized InputStream toInputStream() {
159        return toInputStream(java.io.ByteArrayInputStream::new);
160    }
161
162    @Override
163    public synchronized byte[] toByteArray() {
164        return toByteArrayImpl();
165    }
166}