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 }