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 up to {@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     * @throws IOException
125     *             if an error occurs while reading from this reader.
126     */
127    @Override
128    public int read(char[] buffer, int offset, int count) throws IOException {
129        synchronized (lock) {
130            return in.read(buffer, offset, count);
131        }
132    }
133
134    /**
135     * Indicates whether this reader is ready to be read without blocking. If
136     * the result is {@code true}, the next {@code read()} will not block. If
137     * the result is {@code false}, this reader may or may not block when
138     * {@code read()} is sent.
139     *
140     * @return {@code true} if this reader will not block when {@code read()}
141     *         is called, {@code false} if unknown or blocking will occur.
142     * @throws IOException
143     *             if the reader is closed or some other I/O error occurs.
144     */
145    @Override
146    public boolean ready() throws IOException {
147        synchronized (lock) {
148            return in.ready();
149        }
150    }
151
152    /**
153     * Resets this reader's position to the last marked location. Invocations of
154     * {@code read()} and {@code skip()} will occur from this new location. If
155     * this reader was not marked, the behavior depends on the implementation of
156     * {@code reset()} in the Reader subclass that is filtered by this reader.
157     * The default behavior for Reader is to throw an {@code IOException}.
158     *
159     * @throws IOException
160     *             if a problem occurred or the filtered reader does not support
161     *             {@code mark()} and {@code reset()}.
162     * @see #mark(int)
163     * @see #markSupported()
164     */
165    @Override
166    public void reset() throws IOException {
167        synchronized (lock) {
168            in.reset();
169        }
170    }
171
172    /**
173     * Skips {@code charCount} characters in this reader. Subsequent calls to {@code read}
174     * will not return these characters unless {@code reset} is used. The
175     * default implementation is to skip characters in the filtered reader.
176     *
177     * @return the number of characters actually skipped.
178     * @throws IOException
179     *             if the filtered reader is closed or some other I/O error
180     *             occurs.
181     * @see #mark(int)
182     * @see #markSupported()
183     * @see #reset()
184     */
185    @Override
186    public long skip(long charCount) throws IOException {
187        synchronized (lock) {
188            return in.skip(charCount);
189        }
190    }
191}
192