    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;
    021
    022import org.apache.commons.io.function.IOUnaryOperator;
    023
    024/**
    025 * Proxy stream that prevents the underlying input stream from being closed.
    026 * <p>
    027 * This class is typically used in cases where an input stream needs to be
    028 * passed to a component that wants to explicitly close the stream even if more
    029 * input would still be available to other components.
    030 * </p>
    031 *
    032 * @since 1.4
    033 */
    034public class CloseShieldInputStream extends ProxyInputStream {
    035
    036    /**
    037     * Constructs a new builder for {@link CloseShieldInputStream}.
    038     *
    039     * @since 2.22.0
    040     */
    041    public static class Builder extends AbstractBuilder<CloseShieldInputStream, Builder> {
    042
    043        private IOUnaryOperator<InputStream> onClose = is -> ClosedInputStream.INSTANCE;
    044
    045        /**
    046         * Constructs a new instance.
    047         */
    048        public Builder() {
    049            // empty
    050        }
    051
    052        @Override
    053        public CloseShieldInputStream get() throws IOException {
    054            return new CloseShieldInputStream(this);
    055        }
    056
    057        /**
    058         * Sets the {@code onClose} function. By default, replaces the underlying input stream when {@link #close()} is called.
    059         *
    060         * @param onClose the onClose function.
    061         * @return {@code this} instance.
    062         */
    063        public Builder setOnClose(final IOUnaryOperator<InputStream> onClose) {
    064            this.onClose = onClose;
    065            return asThis();
    066        }
    067
    068    }
    069
    070    /**
    071     * Constructs a new builder for {@link CloseShieldInputStream}.
    072     *
    073     * @return the new builder.
    074     * @since 2.22.0
    075     */
    076    public static Builder builder() {
    077        return new Builder();
    078    }
    079
    080    /**
    081     * Constructs a proxy that only shields {@link System#in} from closing.
    082     *
    083     * @param inputStream the candidate input stream.
    084     * @return the given stream or a proxy on {@link System#in}.
    085     * @since 2.17.0
    086     */
    087    public static InputStream systemIn(final InputStream inputStream) {
    088        return inputStream == System.in ? wrap(inputStream) : inputStream;
    089    }
    090
    091    /**
    092     * Constructs a proxy that shields the given input stream from being closed.
    093     *
    094     * @param inputStream the input stream to wrap.
    095     * @return the created proxy.
    096     * @since 2.9.0
    097     */
    098    public static CloseShieldInputStream wrap(final InputStream inputStream) {
    099        return new CloseShieldInputStream(inputStream);
    100    }
    101
    102    private final IOUnaryOperator<InputStream> onClose;
    103
    104    private CloseShieldInputStream(final Builder builder) throws IOException {
    105        super(builder.getInputStream());
    106        this.onClose = builder.onClose;
    107    }
    108
    109    /**
    110     * Constructs a proxy that shields the given input stream from being closed.
    111     *
    112     * @param inputStream underlying input stream.
    113     * @deprecated Using this constructor prevents IDEs from warning if the
    114     *             underlying input stream is never closed. Use
    115     *             {@link #wrap(InputStream)} instead.
    116     */
    117    @Deprecated
    118    public CloseShieldInputStream(final InputStream inputStream) {
    119        super(inputStream);
    120        this.onClose = builder().onClose;
    121    }
    122
    123    /**
    124     * Applies the {@code onClose} function to the underlying input stream, replacing it with the result.
    125     * <p>
    126     * By default, replaces the underlying input stream with a {@link ClosedInputStream} sentinel. The original input stream will remain open, but this proxy
    127     * will appear closed.
    128     * </p>
    129     *
    130     * @throws IOException Thrown by the {@code onClose} function.
    131     */
    132    @Override
    133    public void close() throws IOException {
    134        in = onClose.apply(in);
    135    }
    136
    137}