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 */
017
018package org.apache.commons.io.output;
019
020import java.io.FilterOutputStream;
021import java.io.IOException;
022import java.io.OutputStream;
023import java.io.UncheckedIOException;
024
025import org.apache.commons.io.build.AbstractStreamBuilder;
026import org.apache.commons.io.function.Uncheck;
027
028/**
029 * A {@link FilterOutputStream} that throws {@link UncheckedIOException} instead of {@link UncheckedIOException}.
030 * <p>
031 * To build an instance, use {@link Builder}.
032 * </p>
033 *
034 * @see Builder
035 * @see FilterOutputStream
036 * @see UncheckedIOException
037 * @since 2.12.0
038 */
039public final class UncheckedFilterOutputStream extends FilterOutputStream {
040
041    // @formatter:off
042    /**
043     * Builds a new {@link UncheckedFilterOutputStream}.
044     *
045     * <p>
046     * Using File IO:
047     * </p>
048     * <pre>{@code
049     * UncheckedFilterOutputStream s = UncheckedFilterOutputStream.builder()
050     *   .setFile(file)
051     *   .get();}
052     * </pre>
053     * <p>
054     * Using NIO Path:
055     * </p>
056     * <pre>{@code
057     * UncheckedFilterOutputStream s = UncheckedFilterOutputStream.builder()
058     *   .setPath(path)
059     *   .get();}
060     * </pre>
061     *
062     * @see #get()
063     */
064    // @formatter:on
065    public static class Builder extends AbstractStreamBuilder<UncheckedFilterOutputStream, Builder> {
066
067        /**
068         * Constructs a new builder of {@link UncheckedFilterOutputStream}.
069         */
070        public Builder() {
071            // empty
072        }
073
074        /**
075         * Builds a new {@link UncheckedFilterOutputStream}.
076         * <p>
077         * You must set an aspect that supports {@link #getOutputStream()} on this builder, otherwise, this method throws an exception.
078         * </p>
079         * <p>
080         * This builder uses the following aspects:
081         * </p>
082         * <ul>
083         * <li>{@link #getOutputStream()}</li>
084         * </ul>
085         *
086         * @return a new instance.
087         * @throws IllegalStateException         if the {@code origin} is {@code null}.
088         * @throws UnsupportedOperationException if the origin cannot be converted to an {@link OutputStream}.
089         * @throws IOException                   if an I/O error occurs converting to an {@link OutputStream} using {@link #getOutputStream()}.
090         * @see #getOutputStream()
091         * @see #getUnchecked()
092         */
093        @Override
094        public UncheckedFilterOutputStream get() throws IOException {
095            return new UncheckedFilterOutputStream(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 an output stream filter built on top of the specified underlying output stream.
111     *
112     * @param builder the buider.
113     * @throws IOException if an I/O error occurs converting to an {@link OutputStream} using {@link #getOutputStream()}.
114     */
115    @SuppressWarnings("resource") // Caller closes.
116    private UncheckedFilterOutputStream(final Builder builder) throws IOException {
117        super(builder.getOutputStream());
118    }
119
120    /**
121     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
122     */
123    @Override
124    public void close() throws UncheckedIOException {
125        Uncheck.run(super::close);
126    }
127
128    /**
129     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
130     */
131    @Override
132    public void flush() throws UncheckedIOException {
133        Uncheck.run(super::flush);
134    }
135
136    /**
137     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
138     */
139    @Override
140    public void write(final byte[] b) throws UncheckedIOException {
141        Uncheck.accept(super::write, b);
142    }
143
144    /**
145     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
146     */
147    @Override
148    public void write(final byte[] b, final int off, final int len) throws UncheckedIOException {
149        Uncheck.accept(super::write, b, off, len);
150    }
151
152    /**
153     * Calls this method's super and rethrow {@link IOException} as {@link UncheckedIOException}.
154     */
155    @Override
156    public void write(final int b) throws UncheckedIOException {
157        Uncheck.accept(super::write, b);
158    }
159
160}