1 /*
2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   - Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *
11  *   - Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *   - Neither the name of Oracle nor the names of its
16  *     contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * This source code is provided to illustrate the usage of a given feature
34  * or technique and has been deliberately simplified. Additional steps
35  * required for a production-quality application, such as security checks,
36  * input validation, and proper error handling, might not be present in
37  * this sample code.
38  */
39 
40 import java.io.BufferedOutputStream;
41 import java.io.IOException;
42 import java.io.OutputStream;
43 import java.io.PrintStream;
44 import java.nio.file.Files;
45 import java.nio.file.Path;
46 import java.nio.file.Paths;
47 
48 /**
49  * This sample demonstrates the ability to create custom resource that
50  * implements the {@code AutoCloseable} interface. This resource can be used in
51  * the try-with-resources construct.
52  */
53 public class CustomAutoCloseableSample {
54 
55     /**
56      * The main method for the CustomAutoCloseableSample program.
57      *
58      * @param args is not used.
59      */
main(String[] args)60     public static void main(String[] args) {
61         /*
62          * TeeStream will be closed automatically after the try block.
63          */
64         try (TeeStream teeStream = new TeeStream(System.out, Paths.get("out.txt"));
65              PrintStream out = new PrintStream(teeStream)) {
66             out.print("Hello, world");
67         } catch (Exception e) {
68             e.printStackTrace();
69             System.exit(1);
70         }
71     }
72 
73     /**
74      * Passes the output through to the specified output stream while copying it into a file.
75      * The TeeStream functionality is similar to the Unix tee utility.
76      * TeeStream implements AutoCloseable interface. See OutputStream for details.
77      */
78     public static class TeeStream extends OutputStream {
79 
80         private final OutputStream fileStream;
81         private final OutputStream outputStream;
82 
83         /**
84          * Creates a TeeStream.
85          *
86          * @param outputStream an output stream.
87          * @param outputFile   an path to file.
88          * @throws IOException If an I/O error occurs.
89          */
TeeStream(OutputStream outputStream, Path outputFile)90         public TeeStream(OutputStream outputStream, Path outputFile) throws IOException {
91             this.fileStream = new BufferedOutputStream(Files.newOutputStream(outputFile));
92             this.outputStream = outputStream;
93         }
94 
95         /**
96          * Writes the specified byte to the specified output stream
97          * and copies it to the file.
98          *
99          * @param b the byte to be written.
100          * @throws IOException If an I/O error occurs.
101          */
102         @Override
write(int b)103         public void write(int b) throws IOException {
104             fileStream.write(b);
105             outputStream.write(b);
106         }
107 
108         /**
109          * Flushes this output stream and forces any buffered output bytes
110          * to be written out.
111          * The <code>flush</code> method of <code>TeeStream</code> flushes
112          * the specified output stream and the file output stream.
113          *
114          * @throws IOException if an I/O error occurs.
115          */
116         @Override
flush()117         public void flush() throws IOException {
118             outputStream.flush();
119             fileStream.flush();
120         }
121 
122         /**
123          * Closes underlying streams and resources.
124          * The external output stream won't be closed.
125          * This method is the member of AutoCloseable interface and
126          * it will be invoked automatically after the try-with-resources block.
127          *
128          * @throws IOException If an I/O error occurs.
129          */
130         @Override
close()131         public void close() throws IOException {
132             try (OutputStream file = fileStream) {
133                 flush();
134             }
135         }
136     }
137 }
138