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