1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.io;
19
20/**
21 * The base class for all writers. A writer is a means of writing data to a
22 * target in a character-wise manner. Most output streams expect the
23 * {@link #flush()} method to be called before closing the stream, to ensure all
24 * data is actually written out.
25 * <p>
26 * This abstract class does not provide a fully working implementation, so it
27 * needs to be subclassed, and at least the {@link #write(char[], int, int)},
28 * {@link #close()} and {@link #flush()} methods needs to be overridden.
29 * Overriding some of the non-abstract methods is also often advised, since it
30 * might result in higher efficiency.
31 * <p>
32 * Many specialized readers for purposes like reading from a file already exist
33 * in this package.
34 *
35 * @see Reader
36 */
37public abstract class Writer implements Appendable, Closeable, Flushable {
38
39    static final String TOKEN_NULL = "null"; //$NON-NLS-1$
40
41    /**
42     * The object used to synchronize access to the writer.
43     */
44    protected Object lock;
45
46    /**
47     * Constructs a new {@code Writer} with {@code this} as the object used to
48     * synchronize critical sections.
49     */
50    protected Writer() {
51        super();
52        lock = this;
53    }
54
55    /**
56     * Constructs a new {@code Writer} with {@code lock} used to synchronize
57     * critical sections.
58     *
59     * @param lock
60     *            the {@code Object} used to synchronize critical sections.
61     * @throws NullPointerException
62     *             if {@code lock} is {@code null}.
63     */
64    protected Writer(Object lock) {
65        if (lock == null) {
66            throw new NullPointerException();
67        }
68        this.lock = lock;
69    }
70
71    /**
72     * Closes this writer. Implementations of this method should free any
73     * resources associated with the writer.
74     *
75     * @throws IOException
76     *             if an error occurs while closing this writer.
77     */
78    public abstract void close() throws IOException;
79
80    /**
81     * Flushes this writer. Implementations of this method should ensure that
82     * all buffered characters are written to the target.
83     *
84     * @throws IOException
85     *             if an error occurs while flushing this writer.
86     */
87    public abstract void flush() throws IOException;
88
89    /**
90     * Writes the entire character buffer {@code buf} to the target.
91     *
92     * @param buf
93     *            the non-null array containing characters to write.
94     * @throws IOException
95     *             if this writer is closed or another I/O error occurs.
96     */
97    public void write(char[] buf) throws IOException {
98        // BEGIN android-note
99        // changed array notation to be consistent with the rest of harmony
100        // END android-note
101        write(buf, 0, buf.length);
102    }
103
104    /**
105     * Writes {@code count} characters starting at {@code offset} in {@code buf}
106     * to the target.
107     *
108     * @param buf
109     *            the non-null character array to write.
110     * @param offset
111     *            the index of the first character in {@code buf} to write.
112     * @param count
113     *            the maximum number of characters to write.
114     * @throws IndexOutOfBoundsException
115     *             if {@code offset < 0} or {@code count < 0}, or if {@code
116     *             offset + count} is greater than the size of {@code buf}.
117     * @throws IOException
118     *             if this writer is closed or another I/O error occurs.
119     */
120    public abstract void write(char[] buf, int offset, int count)
121            throws IOException;
122    // BEGIN android-note
123    // changed array notation to be consistent with the rest of harmony
124    // END android-note
125
126    /**
127     * Writes one character to the target. Only the two least significant bytes
128     * of the integer {@code oneChar} are written.
129     *
130     * @param oneChar
131     *            the character to write to the target.
132     * @throws IOException
133     *             if this writer is closed or another I/O error occurs.
134     */
135    public void write(int oneChar) throws IOException {
136        synchronized (lock) {
137            char oneCharArray[] = new char[1];
138            oneCharArray[0] = (char) oneChar;
139            write(oneCharArray);
140        }
141    }
142
143    /**
144     * Writes the characters from the specified string to the target.
145     *
146     * @param str
147     *            the non-null string containing the characters to write.
148     * @throws IOException
149     *             if this writer is closed or another I/O error occurs.
150     */
151    public void write(String str) throws IOException {
152        write(str, 0, str.length());
153    }
154
155    /**
156     * Writes {@code count} characters from {@code str} starting at {@code
157     * offset} to the target.
158     *
159     * @param str
160     *            the non-null string containing the characters to write.
161     * @param offset
162     *            the index of the first character in {@code str} to write.
163     * @param count
164     *            the number of characters from {@code str} to write.
165     * @throws IOException
166     *             if this writer is closed or another I/O error occurs.
167     * @throws IndexOutOfBoundsException
168     *             if {@code offset < 0} or {@code count < 0}, or if {@code
169     *             offset + count} is greater than the length of {@code str}.
170     */
171    public void write(String str, int offset, int count) throws IOException {
172        if (count < 0) { // other cases tested by getChars()
173            throw new StringIndexOutOfBoundsException();
174        }
175        char buf[] = new char[count];
176        str.getChars(offset, offset + count, buf, 0);
177
178        synchronized (lock) {
179            write(buf, 0, buf.length);
180        }
181    }
182
183    /**
184     * Appends the character {@code c} to the target. This method works the same
185     * way as {@link #write(int)}.
186     *
187     * @param c
188     *            the character to append to the target stream.
189     * @return this writer.
190     * @throws IOException
191     *             if this writer is closed or another I/O error occurs.
192     */
193    public Writer append(char c) throws IOException {
194        write(c);
195        return this;
196    }
197
198    /**
199     * Appends the character sequence {@code csq} to the target. This method
200     * works the same way as {@code Writer.write(csq.toString())}. If {@code
201     * csq} is {@code null}, then the string "null" is written to the target
202     * stream.
203     *
204     * @param csq
205     *            the character sequence appended to the target.
206     * @return this writer.
207     * @throws IOException
208     *             if this writer is closed or another I/O error occurs.
209     */
210    public Writer append(CharSequence csq) throws IOException {
211        if (null == csq) {
212            write(TOKEN_NULL);
213        } else {
214            write(csq.toString());
215        }
216        return this;
217    }
218
219    /**
220     * Appends a subsequence of the character sequence {@code csq} to the
221     * target. This method works the same way as {@code
222     * Writer.writer(csq.subsequence(start, end).toString())}. If {@code
223     * csq} is {@code null}, then the specified subsequence of the string "null"
224     * will be written to the target.
225     *
226     * @param csq
227     *            the character sequence appended to the target.
228     * @param start
229     *            the index of the first char in the character sequence appended
230     *            to the target.
231     * @param end
232     *            the index of the character following the last character of the
233     *            subsequence appended to the target.
234     * @return this writer.
235     * @throws IOException
236     *             if this writer is closed or another I/O error occurs.
237     * @throws IndexOutOfBoundsException
238     *             if {@code start > end}, {@code start < 0}, {@code end < 0} or
239     *             either {@code start} or {@code end} are greater or equal than
240     *             the length of {@code csq}.
241     */
242    public Writer append(CharSequence csq, int start, int end)
243            throws IOException {
244        if (null == csq) {
245            write(TOKEN_NULL.substring(start, end));
246        } else {
247            write(csq.subSequence(start, end).toString());
248        }
249        return this;
250    }
251
252    /**
253     * Returns true if this writer has encountered and suppressed an error. Used
254     * by PrintWriters as an alternative to checked exceptions.
255     */
256    boolean checkError() {
257        return false;
258    }
259}
260