    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.input;
    018
    019import static org.apache.commons.io.IOUtils.EOF;
    020
    021import java.io.FilterInputStream;
    022import java.io.IOException;
    023import java.io.InputStream;
    024
    025import org.apache.commons.io.IOUtils;
    026
    027/**
    028 * A proxy stream which acts as a {@link FilterInputStream}, by passing all method calls on to the proxied stream, not changing which methods are called.
    029 * <p>
    030 * It is an alternative base class to {@link FilterInputStream} to increase reusability, because {@link FilterInputStream} changes the methods being called,
    031 * such as read(byte[]) to read(byte[], int, int).
    032 * </p>
    033 * <p>
    034 * In addition, this class allows you to:
    035 * </p>
    036 * <ul>
    037 * <li>notify a subclass that <em>n</em> bytes are about to be read through {@link #beforeRead(int)}</li>
    038 * <li>notify a subclass that <em>n</em> bytes were read through {@link #afterRead(int)}</li>
    039 * <li>notify a subclass that an exception was caught through {@link #handleIOException(IOException)}</li>
    040 * <li>{@link #unwrap()} itself</li>
    041 * </ul>
    042 * <p>
    043 * This class does not add any state (no additional instance variables).
    044 * </p>
    045 */
    046public abstract class ProxyInputStream extends FilterInputStream {
    047
    048    /**
    049     * Constructs a new ProxyInputStream.
    050     *
    051     * @param proxy  the InputStream to delegate to
    052     */
    053    public ProxyInputStream(final InputStream proxy) {
    054        super(proxy);
    055        // the proxy is stored in a protected superclass variable named 'in'
    056    }
    057
    058    /**
    059     * Invoked by the {@code read} methods after the proxied call has returned
    060     * successfully. The number of bytes returned to the caller (or -1 if
    061     * the end of stream was reached) is given as an argument.
    062     * <p>
    063     * Subclasses can override this method to add common post-processing
    064     * functionality without having to override all the read methods.
    065     * The default implementation does nothing.
    066     * </p>
    067     * <p>
    068     * Note this method is <em>not</em> called from {@link #skip(long)} or
    069     * {@link #reset()}. You need to explicitly override those methods if
    070     * you want to add post-processing steps also to them.
    071     * </p>
    072     *
    073     * @since 2.0
    074     * @param n number of bytes read, or -1 if the end of stream was reached.
    075     * @throws IOException if the post-processing fails in a subclass.
    076     */
    077    @SuppressWarnings("unused") // Possibly thrown from subclasses.
    078    protected void afterRead(final int n) throws IOException {
    079        // no-op default
    080    }
    081
    082    /**
    083     * Invokes the delegate's {@code available()} method.
    084     *
    085     * @return the number of available bytes
    086     * @throws IOException if an I/O error occurs.
    087     */
    088    @Override
    089    public int available() throws IOException {
    090        try {
    091            return super.available();
    092        } catch (final IOException e) {
    093            handleIOException(e);
    094            return 0;
    095        }
    096    }
    097
    098    /**
    099     * Invoked by the {@code read} methods before the call is proxied. The number
    100     * of bytes that the caller wanted to read (1 for the {@link #read()}
    101     * method, buffer length for {@link #read(byte[])}, etc.) is given as
    102     * an argument.
    103     * <p>
    104     * Subclasses can override this method to add common pre-processing
    105     * functionality without having to override all the read methods.
    106     * The default implementation does nothing.
    107     * </p>
    108     * <p>
    109     * Note this method is <em>not</em> called from {@link #skip(long)} or
    110     * {@link #reset()}. You need to explicitly override those methods if
    111     * you want to add pre-processing steps also to them.
    112     * </p>
    113     *
    114     * @since 2.0
    115     * @param n number of bytes that the caller asked to be read.
    116     * @throws IOException if the pre-processing fails in a subclass.
    117     */
    118    @SuppressWarnings("unused") // Possibly thrown from subclasses.
    119    protected void beforeRead(final int n) throws IOException {
    120        // no-op default
    121    }
    122
    123    /**
    124     * Invokes the delegate's {@code close()} method.
    125     *
    126     * @throws IOException if an I/O error occurs.
    127     */
    128    @Override
    129    public void close() throws IOException {
    130        IOUtils.close(in, this::handleIOException);
    131    }
    132
    133    /**
    134     * Handles any IOExceptions thrown; by default, throws the given exception.
    135     * <p>
    136     * This method provides a point to implement custom exception
    137     * handling. The default behavior is to re-throw the exception.
    138     * </p>
    139     *
    140     * @param e The IOException thrown
    141     * @throws IOException if an I/O error occurs.
    142     * @since 2.0
    143     */
    144    protected void handleIOException(final IOException e) throws IOException {
    145        throw e;
    146    }
    147
    148    /**
    149     * Invokes the delegate's {@code mark(int)} method.
    150     *
    151     * @param readLimit read ahead limit
    152     */
    153    @Override
    154    public synchronized void mark(final int readLimit) {
    155        in.mark(readLimit);
    156    }
    157
    158    /**
    159     * Invokes the delegate's {@code markSupported()} method.
    160     *
    161     * @return true if mark is supported, otherwise false
    162     */
    163    @Override
    164    public boolean markSupported() {
    165        return in.markSupported();
    166    }
    167
    168    /**
    169     * Invokes the delegate's {@code read()} method.
    170     *
    171     * @return the byte read or -1 if the end of stream
    172     * @throws IOException if an I/O error occurs.
    173     */
    174    @Override
    175    public int read() throws IOException {
    176        try {
    177            beforeRead(1);
    178            final int b = in.read();
    179            afterRead(b != EOF ? 1 : EOF);
    180            return b;
    181        } catch (final IOException e) {
    182            handleIOException(e);
    183            return EOF;
    184        }
    185    }
    186
    187    /**
    188     * Invokes the delegate's {@code read(byte[])} method.
    189     *
    190     * @param b the buffer to read the bytes into
    191     * @return the number of bytes read or EOF if the end of stream
    192     * @throws IOException if an I/O error occurs.
    193     */
    194    @Override
    195    public int read(final byte[] b) throws IOException {
    196        try {
    197            beforeRead(IOUtils.length(b));
    198            final int n = in.read(b);
    199            afterRead(n);
    200            return n;
    201        } catch (final IOException e) {
    202            handleIOException(e);
    203            return EOF;
    204        }
    205    }
    206
    207    /**
    208     * Invokes the delegate's {@code read(byte[], int, int)} method.
    209     *
    210     * @param b the buffer to read the bytes into
    211     * @param off The start offset
    212     * @param len The number of bytes to read
    213     * @return the number of bytes read or -1 if the end of stream
    214     * @throws IOException if an I/O error occurs.
    215     */
    216    @Override
    217    public int read(final byte[] b, final int off, final int len) throws IOException {
    218        try {
    219            beforeRead(len);
    220            final int n = in.read(b, off, len);
    221            afterRead(n);
    222            return n;
    223        } catch (final IOException e) {
    224            handleIOException(e);
    225            return EOF;
    226        }
    227    }
    228
    229    /**
    230     * Invokes the delegate's {@code reset()} method.
    231     *
    232     * @throws IOException if an I/O error occurs.
    233     */
    234    @Override
    235    public synchronized void reset() throws IOException {
    236        try {
    237            in.reset();
    238        } catch (final IOException e) {
    239            handleIOException(e);
    240        }
    241    }
    242
    243    /**
    244     * Invokes the delegate's {@code skip(long)} method.
    245     *
    246     * @param n the number of bytes to skip
    247     * @return the actual number of bytes skipped
    248     * @throws IOException if an I/O error occurs.
    249     */
    250    @Override
    251    public long skip(final long n) throws IOException {
    252        try {
    253            return in.skip(n);
    254        } catch (final IOException e) {
    255            handleIOException(e);
    256            return 0;
    257        }
    258    }
    259
    260    /**
    261     * Unwraps this instance by returning the underlying InputStream.
    262     * <p>
    263     * Use with caution; useful to query the underlying InputStream.
    264     * </p>
    265     * @return the underlying InputStream.
    266     * @since 2.16.0
    267     */
    268    public InputStream unwrap() {
    269        return in;
    270    }
    271}