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