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 * Wraps an existing {@link Reader} and performs some transformation on the
22 * input data while it is being read. Transformations can be anything from a
23 * simple byte-wise filtering input data to an on-the-fly compression or
24 * decompression of the underlying reader. Readers that wrap another reader and
25 * provide some additional functionality on top of it usually inherit from this
26 * class.
27 *
28 * @see FilterWriter
29 */
30public abstract class FilterReader extends Reader {
31
32    /**
33     * The target Reader which is being filtered.
34     */
35    protected Reader in;
36
37    /**
38     * Constructs a new FilterReader on the Reader {@code in}.
39     *
40     * @param in
41     *            The non-null Reader to filter reads on.
42     */
43    protected FilterReader(Reader in) {
44        super(in);
45        this.in = in;
46    }
47
48    /**
49     * Closes this reader. This implementation closes the filtered reader.
50     *
51     * @throws IOException
52     *             if an error occurs while closing this reader.
53     */
54    @Override
55    public void close() throws IOException {
56        synchronized (lock) {
57            in.close();
58        }
59    }
60
61    /**
62     * Sets a mark position in this reader. The parameter {@code readlimit}
63     * indicates how many bytes can be read before the mark is invalidated.
64     * Sending {@code reset()} will reposition this reader back to the marked
65     * position, provided that {@code readlimit} has not been surpassed.
66     * <p>
67     * This implementation sets a mark in the filtered reader.
68     *
69     * @param readlimit
70     *            the number of bytes that can be read from this reader before
71     *            the mark is invalidated.
72     * @throws IOException
73     *             if an error occurs while marking this reader.
74     * @see #markSupported()
75     * @see #reset()
76     */
77    @Override
78    public synchronized void mark(int readlimit) throws IOException {
79        synchronized (lock) {
80            in.mark(readlimit);
81        }
82    }
83
84    /**
85     * Indicates whether this reader supports {@code mark()} and {@code reset()}.
86     * This implementation returns whether the filtered reader supports marking.
87     *
88     * @return {@code true} if {@code mark()} and {@code reset()} are supported
89     *         by the filtered reader, {@code false} otherwise.
90     * @see #mark(int)
91     * @see #reset()
92     * @see #skip(long)
93     */
94    @Override
95    public boolean markSupported() {
96        synchronized (lock) {
97            return in.markSupported();
98        }
99    }
100
101    /**
102     * Reads a single character from the filtered reader and returns it as an
103     * integer with the two higher-order bytes set to 0. Returns -1 if the end
104     * of the filtered reader has been reached.
105     *
106     * @return The character read or -1 if the end of the filtered reader has
107     *         been reached.
108     * @throws IOException
109     *             if an error occurs while reading from this reader.
110     */
111    @Override
112    public int read() throws IOException {
113        synchronized (lock) {
114            return in.read();
115        }
116    }
117
118    /**
119     * Reads at most {@code count} characters from the filtered reader and stores them
120     * in the byte array {@code buffer} starting at {@code offset}. Returns the
121     * number of characters actually read or -1 if no characters were read and
122     * the end of the filtered reader was encountered.
123     *
124     * @param buffer
125     *            the char array in which to store the characters read.
126     * @param offset
127     *            the initial position in {@code buffer} to store the characters
128     *            read from this reader.
129     * @param count
130     *            the maximum number of characters to store in {@code buffer}.
131     * @return the number of characters actually read or -1 if the end of the
132     *         filtered reader has been reached while reading.
133     * @throws IOException
134     *             if an error occurs while reading from this reader.
135     */
136    @Override
137    public int read(char[] buffer, int offset, int count) throws IOException {
138        synchronized (lock) {
139            return in.read(buffer, offset, count);
140        }
141    }
142
143    /**
144     * Indicates whether this reader is ready to be read without blocking. If
145     * the result is {@code true}, the next {@code read()} will not block. If
146     * the result is {@code false}, this reader may or may not block when
147     * {@code read()} is sent.
148     *
149     * @return {@code true} if this reader will not block when {@code read()}
150     *         is called, {@code false} if unknown or blocking will occur.
151     * @throws IOException
152     *             if the reader is closed or some other I/O error occurs.
153     */
154    @Override
155    public boolean ready() throws IOException {
156        synchronized (lock) {
157            return in.ready();
158        }
159    }
160
161    /**
162     * Resets this reader's position to the last marked location. Invocations of
163     * {@code read()} and {@code skip()} will occur from this new location. If
164     * this reader was not marked, the behavior depends on the implementation of
165     * {@code reset()} in the Reader subclass that is filtered by this reader.
166     * The default behavior for Reader is to throw an {@code IOException}.
167     *
168     * @throws IOException
169     *             if a problem occurred or the filtered reader does not support
170     *             {@code mark()} and {@code reset()}.
171     * @see #mark(int)
172     * @see #markSupported()
173     */
174    @Override
175    public void reset() throws IOException {
176        synchronized (lock) {
177            in.reset();
178        }
179    }
180
181    /**
182     * Skips {@code charCount} characters in this reader. Subsequent calls to {@code read}
183     * will not return these characters unless {@code reset} is used. The
184     * default implementation is to skip characters in the filtered reader.
185     *
186     * @return the number of characters actually skipped.
187     * @throws IOException
188     *             if the filtered reader is closed or some other I/O error
189     *             occurs.
190     * @see #mark(int)
191     * @see #markSupported()
192     * @see #reset()
193     */
194    @Override
195    public long skip(long charCount) throws IOException {
196        synchronized (lock) {
197            return in.skip(charCount);
198        }
199    }
200}
201