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