1 /*
2  * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */

25
26 package java.io;
27
28
29 import java.util.Objects;
30
31 /**
32  * Abstract class for writing to character streams.  The only methods that a
33  * subclass must implement are write(char[], intint), flush(), and close().
34  * Most subclasses, however, will override some of the methods defined here in
35  * order to provide higher efficiency, additional functionality, or both.
36  *
37  * @see   BufferedWriter
38  * @see   CharArrayWriter
39  * @see   FilterWriter
40  * @see   OutputStreamWriter
41  * @see   FileWriter
42  * @see   PipedWriter
43  * @see   PrintWriter
44  * @see   StringWriter
45  * @see Reader
46  *
47  * @author      Mark Reinhold
48  * @since       1.1
49  */

50
51 public abstract class Writer implements Appendable, Closeable, Flushable {
52
53     /**
54      * Temporary buffer used to hold writes of strings and single characters
55      */

56     private char[] writeBuffer;
57
58     /**
59      * Size of writeBuffer, must be >= 1
60      */

61     private static final int WRITE_BUFFER_SIZE = 1024;
62
63     /**
64      * Returns a new {@code Writer} which discards all characters.  The
65      * returned stream is initially open.  The stream is closed by calling
66      * the {@code close()} method.  Subsequent calls to {@code close()} have
67      * no effect.
68      *
69      * <p> While the stream is open, the {@code append(char)}, {@code
70      * append(CharSequence)}, {@code append(CharSequence, intint)},
71      * {@code flush()}, {@code write(int)}, {@code write(char[])}, and
72      * {@code write(char[], intint)} methods do nothing. After the stream
73      * has been closed, these methods all throw {@code IOException}.
74      *
75      * <p> The {@link #lock object} used to synchronize operations on the
76      * returned {@code Writer} is not specified.
77      *
78      * @return a {@code Writer} which discards all characters
79      *
80      * @since 11
81      */

82     public static Writer nullWriter() {
83         return new Writer() {
84             private volatile boolean closed;
85
86             private void ensureOpen() throws IOException {
87                 if (closed) {
88                     throw new IOException("Stream closed");
89                 }
90             }
91
92             @Override
93             public Writer append(char c) throws IOException {
94                 ensureOpen();
95                 return this;
96             }
97
98             @Override
99             public Writer append(CharSequence csq) throws IOException {
100                 ensureOpen();
101                 return this;
102             }
103
104             @Override
105             public Writer append(CharSequence csq, int start, int end) throws IOException {
106                 ensureOpen();
107                 if (csq != null) {
108                     Objects.checkFromToIndex(start, end, csq.length());
109                 }
110                 return this;
111             }
112
113             @Override
114             public void write(int c) throws IOException {
115                 ensureOpen();
116             }
117
118             @Override
119             public void write(char[] cbuf, int off, int len) throws IOException {
120                 Objects.checkFromIndexSize(off, len, cbuf.length);
121                 ensureOpen();
122             }
123
124             @Override
125             public void write(String str) throws IOException {
126                 Objects.requireNonNull(str);
127                 ensureOpen();
128             }
129
130             @Override
131             public void write(String str, int off, int len) throws IOException {
132                 Objects.checkFromIndexSize(off, len, str.length());
133                 ensureOpen();
134             }
135
136             @Override
137             public void flush() throws IOException {
138                 ensureOpen();
139             }
140
141             @Override
142             public void close() throws IOException {
143                 closed = true;
144             }
145         };
146     }
147
148     /**
149      * The object used to synchronize operations on this stream.  For
150      * efficiency, a character-stream object may use an object other than
151      * itself to protect critical sections.  A subclass should therefore use
152      * the object in this field rather than {@code this} or a synchronized
153      * method.
154      */

155     protected Object lock;
156
157     /**
158      * Creates a new character-stream writer whose critical sections will
159      * synchronize on the writer itself.
160      */

161     protected Writer() {
162         this.lock = this;
163     }
164
165     /**
166      * Creates a new character-stream writer whose critical sections will
167      * synchronize on the given object.
168      *
169      * @param  lock
170      *         Object to synchronize on
171      */

172     protected Writer(Object lock) {
173         if (lock == null) {
174             throw new NullPointerException();
175         }
176         this.lock = lock;
177     }
178
179     /**
180      * Writes a single character.  The character to be written is contained in
181      * the 16 low-order bits of the given integer value; the 16 high-order bits
182      * are ignored.
183      *
184      * <p> Subclasses that intend to support efficient single-character output
185      * should override this method.
186      *
187      * @param  c
188      *         int specifying a character to be written
189      *
190      * @throws  IOException
191      *          If an I/O error occurs
192      */

193     public void write(int c) throws IOException {
194         synchronized (lock) {
195             if (writeBuffer == null){
196                 writeBuffer = new char[WRITE_BUFFER_SIZE];
197             }
198             writeBuffer[0] = (char) c;
199             write(writeBuffer, 0, 1);
200         }
201     }
202
203     /**
204      * Writes an array of characters.
205      *
206      * @param  cbuf
207      *         Array of characters to be written
208      *
209      * @throws  IOException
210      *          If an I/O error occurs
211      */

212     public void write(char cbuf[]) throws IOException {
213         write(cbuf, 0, cbuf.length);
214     }
215
216     /**
217      * Writes a portion of an array of characters.
218      *
219      * @param  cbuf
220      *         Array of characters
221      *
222      * @param  off
223      *         Offset from which to start writing characters
224      *
225      * @param  len
226      *         Number of characters to write
227      *
228      * @throws  IndexOutOfBoundsException
229      *          Implementations should throw this exception
230      *          if {@code off} is negative, or {@code len} is negative,
231      *          or {@code off + len} is negative or greater than the length
232      *          of the given array
233      *
234      * @throws  IOException
235      *          If an I/O error occurs
236      */

237     public abstract void write(char cbuf[], int off, int len) throws IOException;
238
239     /**
240      * Writes a string.
241      *
242      * @param  str
243      *         String to be written
244      *
245      * @throws  IOException
246      *          If an I/O error occurs
247      */

248     public void write(String str) throws IOException {
249         write(str, 0, str.length());
250     }
251
252     /**
253      * Writes a portion of a string.
254      *
255      * @implSpec
256      * The implementation in this class throws an
257      * {@code IndexOutOfBoundsException} for the indicated conditions;
258      * overriding methods may choose to do otherwise.
259      *
260      * @param  str
261      *         A String
262      *
263      * @param  off
264      *         Offset from which to start writing characters
265      *
266      * @param  len
267      *         Number of characters to write
268      *
269      * @throws  IndexOutOfBoundsException
270      *          Implementations should throw this exception
271      *          if {@code off} is negative, or {@code len} is negative,
272      *          or {@code off + len} is negative or greater than the length
273      *          of the given string
274      *
275      * @throws  IOException
276      *          If an I/O error occurs
277      */

278     public void write(String str, int off, int len) throws IOException {
279         synchronized (lock) {
280             char cbuf[];
281             if (len <= WRITE_BUFFER_SIZE) {
282                 if (writeBuffer == null) {
283                     writeBuffer = new char[WRITE_BUFFER_SIZE];
284                 }
285                 cbuf = writeBuffer;
286             } else {    // Don't permanently allocate very large buffers.
287                 cbuf = new char[len];
288             }
289             str.getChars(off, (off + len), cbuf, 0);
290             write(cbuf, 0, len);
291         }
292     }
293
294     /**
295      * Appends the specified character sequence to this writer.
296      *
297      * <p> An invocation of this method of the form {@code out.append(csq)}
298      * behaves in exactly the same way as the invocation
299      *
300      * <pre>
301      *     out.write(csq.toString()) </pre>
302      *
303      * <p> Depending on the specification of {@code toString} for the
304      * character sequence {@code csq}, the entire sequence may not be
305      * appended. For instance, invoking the {@code toString} method of a
306      * character buffer will return a subsequence whose content depends upon
307      * the buffer's position and limit.
308      *
309      * @param  csq
310      *         The character sequence to append.  If {@code csq} is
311      *         {@code null}, then the four characters {@code "null"} are
312      *         appended to this writer.
313      *
314      * @return  This writer
315      *
316      * @throws  IOException
317      *          If an I/O error occurs
318      *
319      * @since  1.5
320      */

321     public Writer append(CharSequence csq) throws IOException {
322         write(String.valueOf(csq));
323         return this;
324     }
325
326     /**
327      * Appends a subsequence of the specified character sequence to this writer.
328      * {@code Appendable}.
329      *
330      * <p> An invocation of this method of the form
331      * {@code out.append(csq, start, end)} when {@code csq}
332      * is not {@code null} behaves in exactly the
333      * same way as the invocation
334      *
335      * <pre>{@code
336      *     out.write(csq.subSequence(start, end).toString())
337      * }</pre>
338      *
339      * @param  csq
340      *         The character sequence from which a subsequence will be
341      *         appended.  If {@code csq} is {@code null}, then characters
342      *         will be appended as if {@code csq} contained the four
343      *         characters {@code "null"}.
344      *
345      * @param  start
346      *         The index of the first character in the subsequence
347      *
348      * @param  end
349      *         The index of the character following the last character in the
350      *         subsequence
351      *
352      * @return  This writer
353      *
354      * @throws  IndexOutOfBoundsException
355      *          If {@code start} or {@code end} are negative, {@code start}
356      *          is greater than {@code end}, or {@code end} is greater than
357      *          {@code csq.length()}
358      *
359      * @throws  IOException
360      *          If an I/O error occurs
361      *
362      * @since  1.5
363      */

364     public Writer append(CharSequence csq, int start, int end) throws IOException {
365         if (csq == null) csq = "null";
366         return append(csq.subSequence(start, end));
367     }
368
369     /**
370      * Appends the specified character to this writer.
371      *
372      * <p> An invocation of this method of the form {@code out.append(c)}
373      * behaves in exactly the same way as the invocation
374      *
375      * <pre>
376      *     out.write(c) </pre>
377      *
378      * @param  c
379      *         The 16-bit character to append
380      *
381      * @return  This writer
382      *
383      * @throws  IOException
384      *          If an I/O error occurs
385      *
386      * @since 1.5
387      */

388     public Writer append(char c) throws IOException {
389         write(c);
390         return this;
391     }
392
393     /**
394      * Flushes the stream.  If the stream has saved any characters from the
395      * various write() methods in a buffer, write them immediately to their
396      * intended destination.  Then, if that destination is another character or
397      * byte stream, flush it.  Thus one flush() invocation will flush all the
398      * buffers in a chain of Writers and OutputStreams.
399      *
400      * <p> If the intended destination of this stream is an abstraction provided
401      * by the underlying operating system, for example a file, then flushing the
402      * stream guarantees only that bytes previously written to the stream are
403      * passed to the operating system for writing; it does not guarantee that
404      * they are actually written to a physical device such as a disk drive.
405      *
406      * @throws  IOException
407      *          If an I/O error occurs
408      */

409     public abstract void flush() throws IOException;
410
411     /**
412      * Closes the stream, flushing it first. Once the stream has been closed,
413      * further write() or flush() invocations will cause an IOException to be
414      * thrown. Closing a previously closed stream has no effect.
415      *
416      * @throws  IOException
417      *          If an I/O error occurs
418      */

419     public abstract void close() throws IOException;
420
421 }
422