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
20import java.nio.CharBuffer;
21import java.nio.ReadOnlyBufferException;
22
23/**
24 * The base class for all readers. A reader is a means of reading data from a
25 * source in a character-wise manner. Some readers also support marking a
26 * position in the input and returning to this position later.
27 * <p>
28 * This abstract class does not provide a fully working implementation, so it
29 * needs to be subclassed, and at least the {@link #read(char[], int, int)} and
30 * {@link #close()} methods needs to be overridden. Overriding some of the
31 * non-abstract methods is also often advised, since it might result in higher
32 * efficiency.
33 * <p>
34 * Many specialized readers for purposes like reading from a file already exist
35 * in this package.
36 *
37 * @see Writer
38 */
39public abstract class Reader implements Readable, Closeable {
40    /**
41     * The object used to synchronize access to the reader.
42     */
43    protected Object lock;
44
45    /**
46     * Constructs a new {@code Reader} with {@code this} as the object used to
47     * synchronize critical sections.
48     */
49    protected Reader() {
50        lock = this;
51    }
52
53    /**
54     * Constructs a new {@code Reader} with {@code lock} used to synchronize
55     * critical sections.
56     *
57     * @param lock
58     *            the {@code Object} used to synchronize critical sections.
59     * @throws NullPointerException
60     *             if {@code lock} is {@code null}.
61     */
62    protected Reader(Object lock) {
63        if (lock == null) {
64            throw new NullPointerException("lock == null");
65        }
66        this.lock = lock;
67    }
68
69    /**
70     * Closes this reader. Implementations of this method should free any
71     * resources associated with the reader.
72     *
73     * @throws IOException
74     *             if an error occurs while closing this reader.
75     */
76    public abstract void close() throws IOException;
77
78    /**
79     * Sets a mark position in this reader. The parameter {@code readLimit}
80     * indicates how many characters can be read before the mark is invalidated.
81     * Calling {@code reset()} will reposition the reader back to the marked
82     * position if {@code readLimit} has not been surpassed.
83     * <p>
84     * This default implementation simply throws an {@code IOException};
85     * subclasses must provide their own implementation.
86     *
87     * @param readLimit
88     *            the number of characters that can be read before the mark is
89     *            invalidated.
90     * @throws IllegalArgumentException
91     *             if {@code readLimit < 0}.
92     * @throws IOException
93     *             if an error occurs while setting a mark in this reader.
94     * @see #markSupported()
95     * @see #reset()
96     */
97    public void mark(int readLimit) throws IOException {
98        throw new IOException();
99    }
100
101    /**
102     * Indicates whether this reader supports the {@code mark()} and
103     * {@code reset()} methods. This default implementation returns
104     * {@code false}.
105     *
106     * @return always {@code false}.
107     */
108    public boolean markSupported() {
109        return false;
110    }
111
112    /**
113     * Reads a single character from this reader and returns it as an integer
114     * with the two higher-order bytes set to 0. Returns -1 if the end of the
115     * reader has been reached.
116     *
117     * @return the character read or -1 if the end of the reader has been
118     *         reached.
119     * @throws IOException
120     *             if this reader is closed or some other I/O error occurs.
121     */
122    public int read() throws IOException {
123        synchronized (lock) {
124            char[] charArray = new char[1];
125            if (read(charArray, 0, 1) != -1) {
126                return charArray[0];
127            }
128            return -1;
129        }
130    }
131
132    /**
133     * Reads characters from this reader and stores them in the character array
134     * {@code buffer} starting at offset 0. Returns the number of characters
135     * actually read or -1 if the end of the reader has been reached.
136     *
137     * @throws IOException
138     *             if this reader is closed or some other I/O error occurs.
139     */
140    public int read(char[] buffer) throws IOException {
141        return read(buffer, 0, buffer.length);
142    }
143
144    /**
145     * Reads up to {@code count} characters from this reader and stores them
146     * at {@code offset} in the character array {@code buffer}. Returns the number
147     * of characters actually read or -1 if the end of the reader has been
148     * reached.
149     *
150     * @throws IOException
151     *             if this reader is closed or some other I/O error occurs.
152     */
153    public abstract int read(char[] buffer, int offset, int count) throws IOException;
154
155    /**
156     * Indicates whether this reader is ready to be read without blocking.
157     * Returns {@code true} if this reader will not block when {@code read} is
158     * called, {@code false} if unknown or blocking will occur. This default
159     * implementation always returns {@code false}.
160     *
161     * @return always {@code false}.
162     * @throws IOException
163     *             if this reader is closed or some other I/O error occurs.
164     * @see #read()
165     * @see #read(char[])
166     * @see #read(char[], int, int)
167     */
168    public boolean ready() throws IOException {
169        return false;
170    }
171
172    /**
173     * Resets this reader's position to the last {@code mark()} location.
174     * Invocations of {@code read()} and {@code skip()} will occur from this new
175     * location. If this reader has not been marked, the behavior of
176     * {@code reset()} is implementation specific. This default
177     * implementation throws an {@code IOException}.
178     *
179     * @throws IOException
180     *             always thrown in this default implementation.
181     * @see #mark(int)
182     * @see #markSupported()
183     */
184    public void reset() throws IOException {
185        throw new IOException();
186    }
187
188    /**
189     * Skips {@code charCount} characters in this reader. Subsequent calls of
190     * {@code read} methods will not return these characters unless {@code
191     * reset} is used. This method may perform multiple reads to read {@code
192     * charCount} characters.
193     *
194     * @return the number of characters actually skipped.
195     * @throws IllegalArgumentException
196     *             if {@code charCount < 0}.
197     * @throws IOException
198     *             if this reader is closed or some other I/O error occurs.
199     * @see #mark(int)
200     * @see #markSupported()
201     * @see #reset()
202     */
203    public long skip(long charCount) throws IOException {
204        if (charCount < 0) {
205            throw new IllegalArgumentException("charCount < 0: " + charCount);
206        }
207        synchronized (lock) {
208            long skipped = 0;
209            int toRead = charCount < 512 ? (int) charCount : 512;
210            char[] charsSkipped = new char[toRead];
211            while (skipped < charCount) {
212                int read = read(charsSkipped, 0, toRead);
213                if (read == -1) {
214                    return skipped;
215                }
216                skipped += read;
217                if (read < toRead) {
218                    return skipped;
219                }
220                if (charCount - skipped < toRead) {
221                    toRead = (int) (charCount - skipped);
222                }
223            }
224            return skipped;
225        }
226    }
227
228    /**
229     * Reads characters and puts them into the {@code target} character buffer.
230     *
231     * @param target
232     *            the destination character buffer.
233     * @return the number of characters put into {@code target} or -1 if the end
234     *         of this reader has been reached before a character has been read.
235     * @throws IOException
236     *             if any I/O error occurs while reading from this reader.
237     * @throws NullPointerException
238     *             if {@code target} is {@code null}.
239     * @throws ReadOnlyBufferException
240     *             if {@code target} is read-only.
241     */
242    public int read(CharBuffer target) throws IOException {
243        int length = target.length();
244        char[] buf = new char[length];
245        length = Math.min(length, read(buf));
246        if (length > 0) {
247            target.put(buf, 0, length);
248        }
249        return length;
250    }
251}
252