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