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[], int, int), 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, int, int)},
  71      * {@code flush()}, {@code write(int)}, {@code write(char[])}, and
  72      * {@code write(char[], int, int)} 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 }