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
26package 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
50public 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}
326