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 * https://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 026import org.apache.commons.io.IOUtils; 027 028/** 029 * A reader proxy which delegates to the wrapped reader. 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 * </p> 035 */ 036public abstract class ProxyReader extends FilterReader { 037 038 /** 039 * Constructs a new ProxyReader. 040 * 041 * @param delegate the Reader to delegate to. 042 */ 043 public ProxyReader(final Reader delegate) { 044 // the delegate is stored in a protected superclass variable named 'in' 045 super(delegate); 046 } 047 048 /** 049 * Invoked by the read methods after the proxied call has returned 050 * successfully. The number of chars returned to the caller (or -1 if 051 * the end of stream was reached) is given as an argument. 052 * <p> 053 * Subclasses can override this method to add common post-processing 054 * functionality without having to override all the read methods. 055 * The default implementation does nothing. 056 * </p> 057 * <p> 058 * Note this method is <em>not</em> called from {@link #skip(long)} or 059 * {@link #reset()}. You need to explicitly override those methods if 060 * you want to add post-processing steps also to them. 061 * </p> 062 * 063 * @param n number of chars read, or -1 if the end of stream was reached. 064 * @throws IOException if the post-processing fails. 065 * @since 2.0 066 */ 067 @SuppressWarnings("unused") // Possibly thrown from subclasses. 068 protected void afterRead(final int n) throws IOException { 069 // noop 070 } 071 072 /** 073 * Invoked by the read methods before the call is proxied. The number 074 * of chars that the caller wanted to read (1 for the {@link #read()} 075 * method, buffer length for {@link #read(char[])}, etc.) is given as 076 * an argument. 077 * <p> 078 * Subclasses can override this method to add common pre-processing 079 * functionality without having to override all the read methods. 080 * The default implementation does nothing. 081 * </p> 082 * <p> 083 * Note this method is <em>not</em> called from {@link #skip(long)} or 084 * {@link #reset()}. You need to explicitly override those methods if 085 * you want to add pre-processing steps also to them. 086 * </p> 087 * 088 * @param n number of chars that the caller asked to be read. 089 * @throws IOException if the pre-processing fails. 090 * @since 2.0 091 */ 092 @SuppressWarnings("unused") // Possibly thrown from subclasses. 093 protected void beforeRead(final int n) throws IOException { 094 // noop 095 } 096 097 /** 098 * Invokes the delegate's {@code close()} method. 099 * 100 * @throws IOException if an I/O error occurs. 101 */ 102 @Override 103 public void close() throws IOException { 104 try { 105 in.close(); 106 } catch (final IOException e) { 107 handleIOException(e); 108 } 109 } 110 111 /** 112 * Handle any IOExceptions thrown. 113 * <p> 114 * This method provides a point to implement custom exception 115 * handling. The default behavior is to re-throw the exception. 116 * </p> 117 * 118 * @param e The IOException thrown. 119 * @throws IOException if an I/O error occurs. 120 * @since 2.0 121 */ 122 protected void handleIOException(final IOException e) throws IOException { 123 throw e; 124 } 125 126 /** 127 * Invokes the delegate's {@code mark(int)} method. 128 * 129 * @param readAheadLimit read ahead limit. 130 * @throws IOException if an I/O error occurs. 131 */ 132 @Override 133 public synchronized void mark(final int readAheadLimit) throws IOException { 134 try { 135 in.mark(readAheadLimit); 136 } catch (final IOException e) { 137 handleIOException(e); 138 } 139 } 140 141 /** 142 * Invokes the delegate's {@code markSupported()} method. 143 * 144 * @return true if mark is supported, otherwise false. 145 */ 146 @Override 147 public boolean markSupported() { 148 return in.markSupported(); 149 } 150 151 /** 152 * Invokes the delegate's {@code read()} method. 153 * 154 * @return the character read or -1 if the end of stream. 155 * @throws IOException if an I/O error occurs. 156 */ 157 @Override 158 public int read() throws IOException { 159 try { 160 beforeRead(1); 161 final int c = in.read(); 162 afterRead(c != EOF ? 1 : EOF); 163 return c; 164 } catch (final IOException e) { 165 handleIOException(e); 166 return EOF; 167 } 168 } 169 170 /** 171 * Invokes the delegate's {@code read(char[])} method. 172 * 173 * @param chr the buffer to read the characters into. 174 * @return the number of characters read or -1 if the end of stream. 175 * @throws IOException if an I/O error occurs. 176 */ 177 @Override 178 public int read(final char[] chr) throws IOException { 179 try { 180 beforeRead(IOUtils.length(chr)); 181 final int n = in.read(chr); 182 afterRead(n); 183 return n; 184 } catch (final IOException e) { 185 handleIOException(e); 186 return EOF; 187 } 188 } 189 190 /** 191 * Invokes the delegate's {@code read(char[], int, int)} method. 192 * 193 * @param chr the buffer to read the characters into. 194 * @param st The start offset. 195 * @param len The number of bytes to read. 196 * @return the number of characters read or -1 if the end of stream. 197 * @throws IOException if an I/O error occurs. 198 */ 199 @Override 200 public int read(final char[] chr, final int st, final int len) throws IOException { 201 try { 202 beforeRead(len); 203 final int n = in.read(chr, st, len); 204 afterRead(n); 205 return n; 206 } catch (final IOException e) { 207 handleIOException(e); 208 return EOF; 209 } 210 } 211 212 /** 213 * Invokes the delegate's {@code read(CharBuffer)} method. 214 * 215 * @param target the char buffer to read the characters into. 216 * @return the number of characters read or -1 if the end of stream. 217 * @throws IOException if an I/O error occurs. 218 * @since 2.0 219 */ 220 @Override 221 public int read(final CharBuffer target) throws IOException { 222 try { 223 beforeRead(IOUtils.length(target)); 224 final int n = in.read(target); 225 afterRead(n); 226 return n; 227 } catch (final IOException e) { 228 handleIOException(e); 229 return EOF; 230 } 231 } 232 233 /** 234 * Invokes the delegate's {@code ready()} method. 235 * 236 * @return true if the stream is ready to be read. 237 * @throws IOException if an I/O error occurs. 238 */ 239 @Override 240 public boolean ready() throws IOException { 241 try { 242 return in.ready(); 243 } catch (final IOException e) { 244 handleIOException(e); 245 return false; 246 } 247 } 248 249 /** 250 * Invokes the delegate's {@code reset()} method. 251 * 252 * @throws IOException if an I/O error occurs. 253 */ 254 @Override 255 public synchronized void reset() throws IOException { 256 try { 257 in.reset(); 258 } catch (final IOException e) { 259 handleIOException(e); 260 } 261 } 262 263 /** 264 * Sets the underlying reader. 265 * <p> 266 * Use with caution. 267 * </p> 268 * 269 * @param in The input stream to set in {@code java.io.Reader#in}. 270 * @return {@code this} instance. 271 * @since 2.22.0 272 */ 273 public ProxyReader setReference(final Reader in) { 274 this.in = in; 275 return this; 276 } 277 278 279 /** 280 * Invokes the delegate's {@code skip(long)} method. 281 * 282 * @param ln the number of bytes to skip. 283 * @return the number of bytes to skipped or EOF if the end of stream. 284 * @throws IOException if an I/O error occurs. 285 */ 286 @Override 287 public long skip(final long ln) throws IOException { 288 try { 289 return in.skip(ln); 290 } catch (final IOException e) { 291 handleIOException(e); 292 return 0; 293 } 294 } 295 296 /** 297 * Unwraps this instance by returning the underlying {@link Reader}. 298 * <p> 299 * Use with caution. 300 * </p> 301 * 302 * @return the underlying {@link Reader}. 303 * @since 2.22.0 304 */ 305 public Reader unwrap() { 306 return in; 307 } 308 309}