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