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}