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