    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 *      https://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 java.io.IOException;
    020import java.io.InputStream;
    021import java.util.function.Supplier;
    022
    023import org.apache.commons.io.function.Erase;
    024
    025/**
    026 * Always throws an exception from all {@link InputStream} methods where {@link IOException} is declared.
    027 * <p>
    028 * This class is mostly useful for testing error handling.
    029 * </p>
    030 *
    031 * @since 2.0
    032 */
    033public class BrokenInputStream extends InputStream {
    034
    035    /**
    036     * The singleton instance using a default IOException.
    037     *
    038     * @since 2.12.0
    039     */
    040    public static final BrokenInputStream INSTANCE = new BrokenInputStream();
    041
    042    /**
    043     * A supplier for the exception that is thrown by all methods of this class.
    044     */
    045    private final Supplier<Throwable> exceptionSupplier;
    046
    047    /**
    048     * Constructs a new stream that always throws an {@link IOException}.
    049     */
    050    public BrokenInputStream() {
    051        this(() -> new IOException("Broken input stream"));
    052    }
    053
    054    /**
    055     * Constructs a new stream that always throws the given exception.
    056     *
    057     * @param exception the exception to be thrown.
    058     * @deprecated Use {@link #BrokenInputStream(Throwable)}.
    059     */
    060    @Deprecated
    061    public BrokenInputStream(final IOException exception) {
    062        this(() -> exception);
    063    }
    064
    065    /**
    066     * Constructs a new stream that always throws the supplied exception.
    067     *
    068     * @param exceptionSupplier a supplier for the IOException or RuntimeException to be thrown.
    069     * @since 2.12.0
    070     */
    071    public BrokenInputStream(final Supplier<Throwable> exceptionSupplier) {
    072        this.exceptionSupplier = exceptionSupplier;
    073    }
    074
    075    /**
    076     * Constructs a new stream that always throws the given exception.
    077     *
    078     * @param exception the exception to be thrown.
    079     * @since 2.16.0
    080     */
    081    public BrokenInputStream(final Throwable exception) {
    082        this(() -> exception);
    083    }
    084
    085    /**
    086     * Throws the configured exception.
    087     *
    088     * @return nothing.
    089     * @throws IOException always throws the exception configured in a constructor.
    090     */
    091    @Override
    092    public int available() throws IOException {
    093        throw rethrow();
    094    }
    095
    096    /**
    097     * Throws the configured exception.
    098     *
    099     * @throws IOException always throws the exception configured in a constructor.
    100     */
    101    @Override
    102    public void close() throws IOException {
    103        throw rethrow();
    104    }
    105
    106    /**
    107     * Gets the Throwable to throw. Package-private for testing.
    108     *
    109     * @return  the Throwable to throw.
    110     */
    111    Throwable getThrowable() {
    112        return exceptionSupplier.get();
    113    }
    114
    115    /**
    116     * Throws the configured exception.
    117     *
    118     * @return nothing.
    119     * @throws IOException always throws the exception configured in a constructor.
    120     */
    121    @Override
    122    public int read() throws IOException {
    123        throw rethrow();
    124    }
    125
    126    /**
    127     * Throws the configured exception.
    128     *
    129     * @throws IOException always throws the exception configured in a constructor.
    130     */
    131    @Override
    132    public synchronized void reset() throws IOException {
    133        throw rethrow();
    134    }
    135
    136    /**
    137     * Throws the configured exception from its supplier.
    138     *
    139     * @return Throws the configured exception from its supplier.
    140     */
    141    private RuntimeException rethrow() {
    142        return Erase.rethrow(getThrowable());
    143    }
    144
    145    /**
    146     * Throws the configured exception.
    147     *
    148     * @param n ignored.
    149     * @return nothing.
    150     * @throws IOException always throws the exception configured in a constructor.
    151     */
    152    @Override
    153    public long skip(final long n) throws IOException {
    154        throw rethrow();
    155    }
    156
    157}