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 }