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 jdk.internal.misc.InternalLock;
 30 
 31 import java.util.Objects;
 32 
 33 /**
 34  * Abstract class for writing to character streams.  The only methods that a
 35  * subclass must implement are write(char[], int, int), flush(), and close().
 36  * Most subclasses, however, will override some of the methods defined here in
 37  * order to provide higher efficiency, additional functionality, or both.
 38  *
 39  * @see   BufferedWriter
 40  * @see   CharArrayWriter
 41  * @see   FilterWriter
 42  * @see   OutputStreamWriter
 43  * @see   FileWriter
 44  * @see   PipedWriter
 45  * @see   PrintWriter
 46  * @see   StringWriter
 47  * @see Reader
 48  *
 49  * @author      Mark Reinhold
 50  * @since       1.1
 51  */
 52 
 53 public abstract class Writer implements Appendable, Closeable, Flushable {
 54 
 55     /**
 56      * Returns a new {@code Writer} which discards all characters.  The
 57      * returned stream is initially open.  The stream is closed by calling
 58      * the {@code close()} method.  Subsequent calls to {@code close()} have
 59      * no effect.
 60      *
 61      * <p> While the stream is open, the {@code append(char)}, {@code
 62      * append(CharSequence)}, {@code append(CharSequence, int, int)},
 63      * {@code flush()}, {@code write(int)}, {@code write(char[])}, and
 64      * {@code write(char[], int, int)} methods do nothing. After the stream
 65      * has been closed, these methods all throw {@code IOException}.
 66      *
 67      * <p> The {@link #lock object} used to synchronize operations on the
 68      * returned {@code Writer} is not specified.
 69      *
 70      * @return a {@code Writer} which discards all characters
 71      *
 72      * @since 11
 73      */
 74     public static Writer nullWriter() {
 75         return new Writer() {
 76             private volatile boolean closed;
 77 
 78             private void ensureOpen() throws IOException {
 79                 if (closed) {
 80                     throw new IOException("Stream closed");
 81                 }
 82             }
 83 
 84             @Override
 85             public Writer append(char c) throws IOException {
 86                 ensureOpen();
 87                 return this;
 88             }
 89 
 90             @Override
 91             public Writer append(CharSequence csq) throws IOException {
 92                 ensureOpen();
 93                 return this;
 94             }
 95 
 96             @Override
 97             public Writer append(CharSequence csq, int start, int end) throws IOException {
 98                 ensureOpen();
 99                 if (csq != null) {
100                     Objects.checkFromToIndex(start, end, csq.length());
101                 }
102                 return this;
103             }
104 
105             @Override
106             public void write(int c) throws IOException {
107                 ensureOpen();
108             }
109 
110             @Override
111             public void write(char[] cbuf, int off, int len) throws IOException {
112                 Objects.checkFromIndexSize(off, len, cbuf.length);
113                 ensureOpen();
114             }
115 
116             @Override
117             public void write(String str) throws IOException {
118                 Objects.requireNonNull(str);
119                 ensureOpen();
120             }
121 
122             @Override
123             public void write(String str, int off, int len) throws IOException {
124                 Objects.checkFromIndexSize(off, len, str.length());
125                 ensureOpen();
126             }
127 
128             @Override
129             public void flush() throws IOException {
130                 ensureOpen();
131             }
132 
133             @Override
134             public void close() throws IOException {
135                 closed = true;
136             }
137         };
138     }
139 
140     /**
141      * The object used to synchronize operations on this stream.  For
142      * efficiency, a character-stream object may use an object other than
143      * itself to protect critical sections.  A subclass should therefore use
144      * the object in this field rather than {@code this} or a synchronized
145      * method.
146      */
147     protected Object lock;
148 
149     /**
150      * Creates a new character-stream writer whose critical sections will
151      * synchronize on the writer itself.
152      */
153     protected Writer() {
154         // use InternalLock for trusted classes
155         Class<?> clazz = getClass();
156         if (clazz == OutputStreamWriter.class
157                 || clazz == BufferedWriter.class
158                 || clazz == FileWriter.class
159                 || clazz == PrintWriter.class
160                 || clazz == sun.nio.cs.StreamEncoder.class) {
161             this.lock = new InternalLock();
162         } else {
163             this.lock = this;
164         }
165     }
166 
167     /**
168      * Creates a new character-stream writer whose critical sections will
169      * synchronize on the given object.
170      *
171      * @param  lock
172      *         Object to synchronize on
173      */
174     protected Writer(Object lock) {
175         this.lock = Objects.requireNonNull(lock);
176     }
177 
178     /**
179      * Writes a single character.  The character to be written is contained in
180      * the 16 low-order bits of the given integer value; the 16 high-order bits
181      * are ignored.
182      *
183      * <p> Subclasses that intend to support efficient single-character output
184      * should override this method.
185      *
186      * @param  c
187      *         int specifying a character to be written
188      *
189      * @throws  IOException
190      *          If an I/O error occurs
191      */
192     public void write(int c) throws IOException {
193         var writeBuffer = new char[1];
194         writeBuffer[0] = (char) c;
195         write(writeBuffer, 0, 1);
196     }
197 
198     /**
199      * Writes an array of characters.
200      *
201      * @param  cbuf
202      *         Array of characters to be written
203      *
204      * @throws  IOException
205      *          If an I/O error occurs
206      */
207     public void write(char[] cbuf) throws IOException {
208         write(cbuf, 0, cbuf.length);
209     }
210 
211     /**
212      * Writes a portion of an array of characters.
213      *
214      * @param  cbuf
215      *         Array of characters
216      *
217      * @param  off
218      *         Offset from which to start writing characters
219      *
220      * @param  len
221      *         Number of characters to write
222      *
223      * @throws  IndexOutOfBoundsException
224      *          Implementations should throw this exception
225      *          if {@code off} is negative, or {@code len} is negative,
226      *          or {@code off + len} is negative or greater than the length
227      *          of the given array
228      *
229      * @throws  IOException
230      *          If an I/O error occurs
231      */
232     public abstract void write(char[] cbuf, int off, int len) throws IOException;
233 
234     /**
235      * Writes a string.
236      *
237      * @param  str
238      *         String to be written
239      *
240      * @throws  IOException
241      *          If an I/O error occurs
242      */
243     public void write(String str) throws IOException {
244         write(str, 0, str.length());
245     }
246 
247     /**
248      * Writes a portion of a string.
249      *
250      * @implSpec
251      * The implementation in this class throws an
252      * {@code IndexOutOfBoundsException} for the indicated conditions;
253      * overriding methods may choose to do otherwise.
254      *
255      * @param  str
256      *         A String
257      *
258      * @param  off
259      *         Offset from which to start writing characters
260      *
261      * @param  len
262      *         Number of characters to write
263      *
264      * @throws  IndexOutOfBoundsException
265      *          Implementations should throw this exception
266      *          if {@code off} is negative, or {@code len} is negative,
267      *          or {@code off + len} is negative or greater than the length
268      *          of the given string
269      *
270      * @throws  IOException
271      *          If an I/O error occurs
272      */
273     public void write(String str, int off, int len) throws IOException {
274         Objects.checkFromIndexSize(off, len, str.length());
275         char cbuf[] = new char[len];
276         str.getChars(off, (off + len), cbuf, 0);
277         write(cbuf, 0, len);
278     }
279 
280     /**
281      * Appends the specified character sequence to this writer.
282      *
283      * <p> An invocation of this method of the form {@code out.append(csq)}
284      * behaves in exactly the same way as the invocation
285      *
286      * <pre>
287      *     out.write(csq.toString()) </pre>
288      *
289      * <p> Depending on the specification of {@code toString} for the
290      * character sequence {@code csq}, the entire sequence may not be
291      * appended. For instance, invoking the {@code toString} method of a
292      * character buffer will return a subsequence whose content depends upon
293      * the buffer's position and limit.
294      *
295      * @param  csq
296      *         The character sequence to append.  If {@code csq} is
297      *         {@code null}, then the four characters {@code "null"} are
298      *         appended to this writer.
299      *
300      * @return  This writer
301      *
302      * @throws  IOException
303      *          If an I/O error occurs
304      *
305      * @since  1.5
306      */
307     public Writer append(CharSequence csq) throws IOException {
308         write(String.valueOf(csq));
309         return this;
310     }
311 
312     /**
313      * Appends a subsequence of the specified character sequence to this writer.
314      * {@code Appendable}.
315      *
316      * <p> An invocation of this method of the form
317      * {@code out.append(csq, start, end)} when {@code csq}
318      * is not {@code null} behaves in exactly the
319      * same way as the invocation
320      *
321      * <pre>{@code
322      *     out.write(csq.subSequence(start, end).toString())
323      * }</pre>
324      *
325      * @param  csq
326      *         The character sequence from which a subsequence will be
327      *         appended.  If {@code csq} is {@code null}, then characters
328      *         will be appended as if {@code csq} contained the four
329      *         characters {@code "null"}.
330      *
331      * @param  start
332      *         The index of the first character in the subsequence
333      *
334      * @param  end
335      *         The index of the character following the last character in the
336      *         subsequence
337      *
338      * @return  This writer
339      *
340      * @throws  IndexOutOfBoundsException
341      *          If {@code start} or {@code end} are negative, {@code start}
342      *          is greater than {@code end}, or {@code end} is greater than
343      *          {@code csq.length()}
344      *
345      * @throws  IOException
346      *          If an I/O error occurs
347      *
348      * @since  1.5
349      */
350     public Writer append(CharSequence csq, int start, int end) throws IOException {
351         if (csq == null) csq = "null";
352         return append(csq.subSequence(start, end));
353     }
354 
355     /**
356      * Appends the specified character to this writer.
357      *
358      * <p> An invocation of this method of the form {@code out.append(c)}
359      * behaves in exactly the same way as the invocation
360      *
361      * <pre>
362      *     out.write(c) </pre>
363      *
364      * @param  c
365      *         The 16-bit character to append
366      *
367      * @return  This writer
368      *
369      * @throws  IOException
370      *          If an I/O error occurs
371      *
372      * @since 1.5
373      */
374     public Writer append(char c) throws IOException {
375         write(c);
376         return this;
377     }
378 
379     /**
380      * Flushes the stream.  If the stream has saved any characters from the
381      * various write() methods in a buffer, write them immediately to their
382      * intended destination.  Then, if that destination is another character or
383      * byte stream, flush it.  Thus one flush() invocation will flush all the
384      * buffers in a chain of Writers and OutputStreams.
385      *
386      * <p> If the intended destination of this stream is an abstraction provided
387      * by the underlying operating system, for example a file, then flushing the
388      * stream guarantees only that bytes previously written to the stream are
389      * passed to the operating system for writing; it does not guarantee that
390      * they are actually written to a physical device such as a disk drive.
391      *
392      * @throws  IOException
393      *          If an I/O error occurs
394      */
395     public abstract void flush() throws IOException;
396 
397     /**
398      * Closes the stream, flushing it first. Once the stream has been closed,
399      * further write() or flush() invocations will cause an IOException to be
400      * thrown. Closing a previously closed stream has no effect.
401      *
402      * @throws  IOException
403      *          If an I/O error occurs
404      */
405     public abstract void close() throws IOException;
406 
407 }