View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.io.input;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  
22  import org.apache.commons.io.function.IOUnaryOperator;
23  
24  /**
25   * Proxy stream that prevents the underlying input stream from being closed.
26   * <p>
27   * This class is typically used in cases where an input stream needs to be
28   * passed to a component that wants to explicitly close the stream even if more
29   * input would still be available to other components.
30   * </p>
31   *
32   * @since 1.4
33   */
34  public class CloseShieldInputStream extends ProxyInputStream {
35  
36      /**
37       * Constructs a new builder for {@link CloseShieldInputStream}.
38       *
39       * @since 2.22.0
40       */
41      public static class Builder extends AbstractBuilder<CloseShieldInputStream, Builder> {
42  
43          private IOUnaryOperator<InputStream> onClose = is -> ClosedInputStream.INSTANCE;
44  
45          /**
46           * Constructs a new instance.
47           */
48          public Builder() {
49              // empty
50          }
51  
52          @Override
53          public CloseShieldInputStream get() throws IOException {
54              return new CloseShieldInputStream(this);
55          }
56  
57          /**
58           * Sets the {@code onClose} function. By default, replaces the underlying input stream when {@link #close()} is called.
59           *
60           * @param onClose the onClose function.
61           * @return {@code this} instance.
62           */
63          public Builder setOnClose(final IOUnaryOperator<InputStream> onClose) {
64              this.onClose = onClose;
65              return asThis();
66          }
67  
68      }
69  
70      /**
71       * Constructs a new builder for {@link CloseShieldInputStream}.
72       *
73       * @return the new builder.
74       * @since 2.22.0
75       */
76      public static Builder builder() {
77          return new Builder();
78      }
79  
80      /**
81       * Constructs a proxy that only shields {@link System#in} from closing.
82       *
83       * @param inputStream the candidate input stream.
84       * @return the given stream or a proxy on {@link System#in}.
85       * @since 2.17.0
86       */
87      public static InputStream systemIn(final InputStream inputStream) {
88          return inputStream == System.in ? wrap(inputStream) : inputStream;
89      }
90  
91      /**
92       * Constructs a proxy that shields the given input stream from being closed.
93       *
94       * @param inputStream the input stream to wrap.
95       * @return the created proxy.
96       * @since 2.9.0
97       */
98      public static CloseShieldInputStream wrap(final InputStream inputStream) {
99          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 }