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