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 */
017package org.apache.juneau.commons.io;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020
021import java.io.*;
022
023/**
024 * A wrapper around an {@link OutputStream} that prevents the underlying stream from being closed.
025 *
026 * <p>
027 * This class wraps an existing {@link OutputStream} and intercepts the {@link #close()} method,
028 * making it a no-op (except for flushing). All other operations are delegated to the underlying
029 * stream. This is useful when you need to pass a stream to code that will close it, but you
030 * want to keep the underlying stream open for further use.
031 *
032 * <h5 class='section'>Features:</h5>
033 * <ul class='spaced-list'>
034 *    <li>Prevents closing - {@link #close()} flushes but doesn't close the underlying stream
035 *    <li>Transparent delegation - all other operations pass through to the wrapped stream
036 *    <li>Useful for resource management - allows multiple consumers without premature closing
037 * </ul>
038 *
039 * <h5 class='section'>Use Cases:</h5>
040 * <ul class='spaced-list'>
041 *    <li>Passing streams to APIs that close them, but you need to keep the stream open
042 *    <li>Multiple operations on the same stream where intermediate operations might close it
043 *    <li>Resource management scenarios where you control the stream lifecycle
044 *    <li>Wrapping system streams (System.out, System.err) that should not be closed
045 * </ul>
046 *
047 * <h5 class='section'>Usage:</h5>
048 * <p class='bjava'>
049 *    <jc>// Wrap a stream that should not be closed</jc>
050 *    FileOutputStream <jv>fos</jv> = <jk>new</jk> FileOutputStream(<js>"output.txt"</js>);
051 *    NoCloseOutputStream <jv>wrapper</jv> = <jk>new</jk> NoCloseOutputStream(<jv>fos</jv>);
052 *
053 *    <jc>// Pass to code that might close it</jc>
054 *    <jv>someMethod</jv>(<jv>wrapper</jv>);  <jc>// May call close(), but fos remains open</jc>
055 *
056 *    <jc>// Continue using the original stream</jc>
057 *    <jv>fos</jv>.write(<js>"more data"</js>.getBytes());
058 *    <jv>fos</jv>.close();  <jc>// Close when actually done</jc>
059 * </p>
060 *
061 * <h5 class='section'>Important Notes:</h5>
062 * <ul class='spaced-list'>
063 *    <li>The {@link #close()} method flushes the stream but does not close the underlying stream
064 *    <li>You are responsible for closing the underlying stream when you're done with it
065 *    <li>This wrapper does not prevent resource leaks - ensure the underlying stream is eventually closed
066 * </ul>
067 *
068 * <h5 class='section'>See Also:</h5><ul>
069 *    <li class='jc'>{@link NoCloseWriter} - Writer counterpart
070 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsIO">I/O Package</a>
071 * </ul>
072 */
073public class NoCloseOutputStream extends OutputStream {
074
075   private final OutputStream os;
076
077   /**
078    * Constructor.
079    *
080    * <p>
081    * Creates a new NoCloseOutputStream that wraps the specified OutputStream. The wrapper
082    * will prevent the underlying stream from being closed via the {@link #close()} method.
083    *
084    * <h5 class='section'>Example:</h5>
085    * <p class='bjava'>
086    *    FileOutputStream <jv>fos</jv> = <jk>new</jk> FileOutputStream(<js>"file.txt"</js>);
087    *    NoCloseOutputStream <jv>wrapper</jv> = <jk>new</jk> NoCloseOutputStream(<jv>fos</jv>);
088    * </p>
089    *
090    * @param os The OutputStream to wrap. Must not be <jk>null</jk>.
091    */
092   public NoCloseOutputStream(OutputStream os) {
093      this.os = assertArgNotNull("os", os);
094   }
095
096   /**
097    * Flushes the stream but does not close the underlying OutputStream.
098    *
099    * <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}