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