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 */
017
018package org.apache.commons.io.input;
019
020import java.io.BufferedReader;
021import java.io.FilterInputStream;
022import java.io.IOException;
023import java.io.UncheckedIOException;
024
025import org.apache.commons.io.build.AbstractStreamBuilder;
026import org.apache.commons.io.function.Uncheck;
027
028/**
029 * A {@link BufferedReader} that throws {@link UncheckedIOException} instead of {@link IOException}.
030 * <p>
031 * To build an instance, use {@link Builder}.
032 * </p>
033 *
034 * @see Builder
035 * @see BufferedReader
036 * @see IOException
037 * @see UncheckedIOException
038 * @since 2.12.0
039 */
040public final class UncheckedFilterInputStream extends FilterInputStream {
041
042    // @formatter:off
043    /**
044     * Builds a new {@link UncheckedFilterInputStream}.
045     *
046     * <p>
047     * Using File IO:
048     * </p>
049     * <pre>{@code
050     * UncheckedFilterInputStream s = UncheckedFilterInputStream.builder()
051     *   .setFile(file)
052     *   .get();}
053     * </pre>
054     * <p>
055     * Using NIO Path:
056     * </p>
057     * <pre>{@code
058     * UncheckedFilterInputStream s = UncheckedFilterInputStream.builder()
059     *   .setPath(path)
060     *   .get();}
061     * </pre>
062     *
063     * @see #get()
064     */
065    // @formatter:on
066    public static class Builder extends AbstractStreamBuilder<UncheckedFilterInputStream, Builder> {
067
068        /**
069         * Constructs a new builder of {@link UncheckedFilterInputStream}.
070         */
071        public Builder() {
072            // empty
073        }
074
075        /**
076         * Builds a new {@link UncheckedFilterInputStream}.
077         * <p>
078         * You must set an aspect that supports {@link #getInputStream()} on this builder, otherwise, this method throws an exception.
079         * </p>
080         * <p>
081         * This builder uses the following aspects:
082         * </p>
083         * <ul>
084         * <li>{@link #getInputStream()} gets the target aspect.</li>
085         * </ul>
086         *
087         * @return a new instance.
088         * @throws UnsupportedOperationException if the origin cannot provide an {@link #getInputStream()}.
089         * @see #getInputStream()
090         * @see #getUnchecked()
091         */
092        @Override
093        public UncheckedFilterInputStream get() {
094            // This an unchecked class, so this method is as well.
095            return Uncheck.get(() -> new UncheckedFilterInputStream(this));
096        }
097
098    }
099
100    /**
101     * Constructs a new {@link Builder}.
102     *
103     * @return a new {@link Builder}.
104     */
105    public static Builder builder() {
106        return new Builder();
107    }
108
109    /**
110     * Constructs a {@link UncheckedFilterInputStream}.
111     *
112     * @param builder A builder providing the underlying input stream.
113     * @throws IOException
114     */
115    @SuppressWarnings("resource") // caller closes
116    private UncheckedFilterInputStream(final Builder builder) throws IOException {
117        super(builder.getInputStream());
118    }
119
120    /**
121     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
122     */
123    @Override
124    public int available() throws UncheckedIOException {
125        return Uncheck.getAsInt(super::available);
126    }
127
128    /**
129     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
130     */
131    @Override
132    public void close() throws UncheckedIOException {
133        Uncheck.run(super::close);
134    }
135
136    /**
137     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
138     */
139    @Override
140    public int read() throws UncheckedIOException {
141        return Uncheck.getAsInt(super::read);
142    }
143
144    /**
145     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
146     */
147    @Override
148    public int read(final byte[] b) throws UncheckedIOException {
149        return Uncheck.apply(super::read, b);
150    }
151
152    /**
153     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
154     */
155    @Override
156    public int read(final byte[] b, final int off, final int len) throws UncheckedIOException {
157        return Uncheck.apply(super::read, b, off, len);
158    }
159
160    /**
161     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
162     */
163    @Override
164    public synchronized void reset() throws UncheckedIOException {
165        Uncheck.run(super::reset);
166    }
167
168    /**
169     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
170     */
171    @Override
172    public long skip(final long n) throws UncheckedIOException {
173        return Uncheck.apply(super::skip, n);
174    }
175
176}