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