001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 * 
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 * 
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.io.input;
018
019import static org.apache.commons.io.IOUtils.EOF;
020
021import java.io.FilterReader;
022import java.io.IOException;
023import java.io.Reader;
024import java.nio.CharBuffer;
025
026/**
027 * A Proxy stream which acts as expected, that is it passes the method 
028 * calls on to the proxied stream and doesn't change which methods are 
029 * being called. 
030 * <p>
031 * It is an alternative base class to FilterReader
032 * to increase reusability, because FilterReader changes the 
033 * methods being called, such as read(char[]) to read(char[], int, int).
034 * 
035 * @version $Id: ProxyReader.java 1586350 2014-04-10 15:57:20Z ggregory $
036 */
037public abstract class ProxyReader extends FilterReader {
038
039    /**
040     * Constructs a new ProxyReader.
041     * 
042     * @param proxy  the Reader to delegate to
043     */
044    public ProxyReader(final Reader proxy) {
045        super(proxy);
046        // the proxy is stored in a protected superclass variable named 'in'
047    }
048
049    /**
050     * Invokes the delegate's <code>read()</code> method.
051     * @return the character read or -1 if the end of stream
052     * @throws IOException if an I/O error occurs
053     */
054    @Override
055    public int read() throws IOException {
056        try {
057            beforeRead(1);
058            final int c = in.read();
059            afterRead(c != EOF ? 1 : EOF);
060            return c;
061        } catch (final IOException e) {
062            handleIOException(e);
063            return EOF;
064        }
065    }
066
067    /**
068     * Invokes the delegate's <code>read(char[])</code> method.
069     * @param chr the buffer to read the characters into
070     * @return the number of characters read or -1 if the end of stream
071     * @throws IOException if an I/O error occurs
072     */
073    @Override
074    public int read(final char[] chr) throws IOException {
075        try {
076            beforeRead(chr != null ? chr.length : 0);
077            final int n = in.read(chr);
078            afterRead(n);
079            return n;
080        } catch (final IOException e) {
081            handleIOException(e);
082            return EOF;
083        }
084    }
085
086    /**
087     * Invokes the delegate's <code>read(char[], int, int)</code> method.
088     * @param chr the buffer to read the characters into
089     * @param st The start offset
090     * @param len The number of bytes to read
091     * @return the number of characters read or -1 if the end of stream
092     * @throws IOException if an I/O error occurs
093     */
094    @Override
095    public int read(final char[] chr, final int st, final int len) throws IOException {
096        try {
097            beforeRead(len);
098            final int n = in.read(chr, st, len);
099            afterRead(n);
100            return n;
101        } catch (final IOException e) {
102            handleIOException(e);
103            return EOF;
104        }
105    }
106
107    /**
108     * Invokes the delegate's <code>read(CharBuffer)</code> method.
109     * @param target the char buffer to read the characters into
110     * @return the number of characters read or -1 if the end of stream
111     * @throws IOException if an I/O error occurs
112     * @since 2.0
113     */
114    @Override
115    public int read(final CharBuffer target) throws IOException {
116        try {
117            beforeRead(target != null ? target.length() : 0);
118            final int n = in.read(target);
119            afterRead(n);
120            return n;
121        } catch (final IOException e) {
122            handleIOException(e);
123            return EOF;
124        }
125    }
126
127    /**
128     * Invokes the delegate's <code>skip(long)</code> method.
129     * @param ln the number of bytes to skip
130     * @return the number of bytes to skipped or EOF if the end of stream
131     * @throws IOException if an I/O error occurs
132     */
133    @Override
134    public long skip(final long ln) throws IOException {
135        try {
136            return in.skip(ln);
137        } catch (final IOException e) {
138            handleIOException(e);
139            return 0;
140        }
141    }
142
143    /**
144     * Invokes the delegate's <code>ready()</code> method.
145     * @return true if the stream is ready to be read
146     * @throws IOException if an I/O error occurs
147     */
148    @Override
149    public boolean ready() throws IOException {
150        try {
151            return in.ready();
152        } catch (final IOException e) {
153            handleIOException(e);
154            return false;
155        }
156    }
157
158    /**
159     * Invokes the delegate's <code>close()</code> method.
160     * @throws IOException if an I/O error occurs
161     */
162    @Override
163    public void close() throws IOException {
164        try {
165            in.close();
166        } catch (final IOException e) {
167            handleIOException(e);
168        }
169    }
170
171    /**
172     * Invokes the delegate's <code>mark(int)</code> method.
173     * @param idx read ahead limit
174     * @throws IOException if an I/O error occurs
175     */
176    @Override
177    public synchronized void mark(final int idx) throws IOException {
178        try {
179            in.mark(idx);
180        } catch (final IOException e) {
181            handleIOException(e);
182        }
183    }
184
185    /**
186     * Invokes the delegate's <code>reset()</code> method.
187     * @throws IOException if an I/O error occurs
188     */
189    @Override
190    public synchronized void reset() throws IOException {
191        try {
192            in.reset();
193        } catch (final IOException e) {
194            handleIOException(e);
195        }
196    }
197
198    /**
199     * Invokes the delegate's <code>markSupported()</code> method.
200     * @return true if mark is supported, otherwise false
201     */
202    @Override
203    public boolean markSupported() {
204        return in.markSupported();
205    }
206
207    /**
208     * Invoked by the read methods before the call is proxied. The number
209     * of chars that the caller wanted to read (1 for the {@link #read()}
210     * method, buffer length for {@link #read(char[])}, etc.) is given as
211     * an argument.
212     * <p>
213     * Subclasses can override this method to add common pre-processing
214     * functionality without having to override all the read methods.
215     * The default implementation does nothing.
216     * <p>
217     * Note this method is <em>not</em> called from {@link #skip(long)} or
218     * {@link #reset()}. You need to explicitly override those methods if
219     * you want to add pre-processing steps also to them.
220     *
221     * @since 2.0
222     * @param n number of chars that the caller asked to be read
223     * @throws IOException if the pre-processing fails
224     */
225    protected void beforeRead(final int n) throws IOException {
226    }
227
228    /**
229     * Invoked by the read methods after the proxied call has returned
230     * successfully. The number of chars returned to the caller (or -1 if
231     * the end of stream was reached) is given as an argument.
232     * <p>
233     * Subclasses can override this method to add common post-processing
234     * functionality without having to override all the read methods.
235     * The default implementation does nothing.
236     * <p>
237     * Note this method is <em>not</em> called from {@link #skip(long)} or
238     * {@link #reset()}. You need to explicitly override those methods if
239     * you want to add post-processing steps also to them.
240     *
241     * @since 2.0
242     * @param n number of chars read, or -1 if the end of stream was reached
243     * @throws IOException if the post-processing fails
244     */
245    protected void afterRead(final int n) throws IOException {
246    }
247
248    /**
249     * Handle any IOExceptions thrown.
250     * <p>
251     * This method provides a point to implement custom exception
252     * handling. The default behaviour is to re-throw the exception.
253     * @param e The IOException thrown
254     * @throws IOException if an I/O error occurs
255     * @since 2.0
256     */
257    protected void handleIOException(final IOException e) throws IOException {
258        throw e;
259    }
260
261}