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