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    *      http://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.juneau.commons.io;
18  
19  import static org.apache.juneau.commons.utils.AssertionUtils.*;
20  
21  import java.io.*;
22  
23  /**
24   * A wrapper around an {@link OutputStream} that prevents the underlying stream from being closed.
25   *
26   * <p>
27   * This class wraps an existing {@link OutputStream} and intercepts the {@link #close()} method,
28   * making it a no-op (except for flushing). All other operations are delegated to the underlying
29   * stream. This is useful when you need to pass a stream to code that will close it, but you
30   * want to keep the underlying stream open for further use.
31   *
32   * <h5 class='section'>Features:</h5>
33   * <ul class='spaced-list'>
34   * 	<li>Prevents closing - {@link #close()} flushes but doesn't close the underlying stream
35   * 	<li>Transparent delegation - all other operations pass through to the wrapped stream
36   * 	<li>Useful for resource management - allows multiple consumers without premature closing
37   * </ul>
38   *
39   * <h5 class='section'>Use Cases:</h5>
40   * <ul class='spaced-list'>
41   * 	<li>Passing streams to APIs that close them, but you need to keep the stream open
42   * 	<li>Multiple operations on the same stream where intermediate operations might close it
43   * 	<li>Resource management scenarios where you control the stream lifecycle
44   * 	<li>Wrapping system streams (System.out, System.err) that should not be closed
45   * </ul>
46   *
47   * <h5 class='section'>Usage:</h5>
48   * <p class='bjava'>
49   * 	<jc>// Wrap a stream that should not be closed</jc>
50   * 	FileOutputStream <jv>fos</jv> = <jk>new</jk> FileOutputStream(<js>"output.txt"</js>);
51   * 	NoCloseOutputStream <jv>wrapper</jv> = <jk>new</jk> NoCloseOutputStream(<jv>fos</jv>);
52   *
53   * 	<jc>// Pass to code that might close it</jc>
54   * 	<jv>someMethod</jv>(<jv>wrapper</jv>);  <jc>// May call close(), but fos remains open</jc>
55   *
56   * 	<jc>// Continue using the original stream</jc>
57   * 	<jv>fos</jv>.write(<js>"more data"</js>.getBytes());
58   * 	<jv>fos</jv>.close();  <jc>// Close when actually done</jc>
59   * </p>
60   *
61   * <h5 class='section'>Important Notes:</h5>
62   * <ul class='spaced-list'>
63   * 	<li>The {@link #close()} method flushes the stream but does not close the underlying stream
64   * 	<li>You are responsible for closing the underlying stream when you're done with it
65   * 	<li>This wrapper does not prevent resource leaks - ensure the underlying stream is eventually closed
66   * </ul>
67   *
68   * <h5 class='section'>See Also:</h5><ul>
69   * 	<li class='jc'>{@link NoCloseWriter} - Writer counterpart
70   * 	<li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsIO">I/O Package</a>
71   * </ul>
72   */
73  public class NoCloseOutputStream extends OutputStream {
74  
75  	private final OutputStream os;
76  
77  	/**
78  	 * Constructor.
79  	 *
80  	 * <p>
81  	 * Creates a new NoCloseOutputStream that wraps the specified OutputStream. The wrapper
82  	 * will prevent the underlying stream from being closed via the {@link #close()} method.
83  	 *
84  	 * <h5 class='section'>Example:</h5>
85  	 * <p class='bjava'>
86  	 * 	FileOutputStream <jv>fos</jv> = <jk>new</jk> FileOutputStream(<js>"file.txt"</js>);
87  	 * 	NoCloseOutputStream <jv>wrapper</jv> = <jk>new</jk> NoCloseOutputStream(<jv>fos</jv>);
88  	 * </p>
89  	 *
90  	 * @param os The OutputStream to wrap. Must not be <jk>null</jk>.
91  	 */
92  	public NoCloseOutputStream(OutputStream os) {
93  		this.os = assertArgNotNull("os", os);
94  	}
95  
96  	/**
97  	 * Flushes the stream but does not close the underlying OutputStream.
98  	 *
99  	 * <p>
100 	 * This method flushes any buffered data to the underlying stream but does not close it.
101 	 * The underlying stream remains open and can continue to be used after this method is called.
102 	 *
103 	 * <h5 class='section'>Example:</h5>
104 	 * <p class='bjava'>
105 	 * 	FileOutputStream <jv>fos</jv> = <jk>new</jk> FileOutputStream(<js>"file.txt"</js>);
106 	 * 	NoCloseOutputStream <jv>wrapper</jv> = <jk>new</jk> NoCloseOutputStream(<jv>fos</jv>);
107 	 * 	<jv>wrapper</jv>.close();  <jc>// Flushes but doesn't close fos</jc>
108 	 * 	<jv>fos</jv>.write(<js>"still works"</js>.getBytes());  <jc>// fos is still open</jc>
109 	 * </p>
110 	 *
111 	 * @throws IOException If an I/O error occurs while flushing.
112 	 */
113 	@Override /* Overridden from OutputStream */
114 	public void close() throws IOException {
115 		os.flush();
116 	}
117 
118 	@Override /* Overridden from OutputStream */
119 	public void flush() throws IOException {
120 		os.flush();
121 	}
122 
123 	@Override /* Overridden from OutputStream */
124 	public void write(byte[] b) throws IOException {
125 		assertArgNotNull("b", b);
126 		os.write(b);
127 	}
128 
129 	@Override /* Overridden from OutputStream */
130 	public void write(byte[] b, int off, int len) throws IOException {
131 		assertArgNotNull("b", b);
132 		os.write(b, off, len);
133 	}
134 
135 	@Override /* Overridden from OutputStream */
136 	public void write(int b) throws IOException {
137 		os.write(b);
138 	}
139 }