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 }