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.EOFException; 020 import java.io.IOException; 021 import java.io.Reader; 022 023 /** 024 * A functional, light weight {@link Reader} that emulates 025 * a reader of a specified size. 026 * <p> 027 * This implementation provides a light weight 028 * object for testing with an {@link Reader} 029 * where the contents don't matter. 030 * <p> 031 * One use case would be for testing the handling of 032 * large {@link Reader} as it can emulate that 033 * scenario without the overhead of actually processing 034 * large numbers of characters - significantly speeding up 035 * test execution times. 036 * <p> 037 * This implementation returns a space from the method that 038 * reads a character and leaves the array unchanged in the read 039 * methods that are passed a character array. 040 * If alternative data is required the <code>processChar()</code> and 041 * <code>processChars()</code> methods can be implemented to generate 042 * data, for example: 043 * 044 * <pre> 045 * public class TestReader extends NullReader { 046 * public TestReader(int size) { 047 * super(size); 048 * } 049 * protected char processChar() { 050 * return ... // return required value here 051 * } 052 * protected void processChars(char[] chars, int offset, int length) { 053 * for (int i = offset; i < length; i++) { 054 * chars[i] = ... // set array value here 055 * } 056 * } 057 * } 058 * </pre> 059 * 060 * @since 1.3 061 * @version $Id: NullReader.java 1304052 2012-03-22 20:55:29Z ggregory $ 062 */ 063 public class NullReader extends Reader { 064 065 private final long size; 066 private long position; 067 private long mark = -1; 068 private long readlimit; 069 private boolean eof; 070 private final boolean throwEofException; 071 private final boolean markSupported; 072 073 /** 074 * Create a {@link Reader} that emulates a specified size 075 * which supports marking and does not throw EOFException. 076 * 077 * @param size The size of the reader to emulate. 078 */ 079 public NullReader(long size) { 080 this(size, true, false); 081 } 082 083 /** 084 * Create a {@link Reader} that emulates a specified 085 * size with option settings. 086 * 087 * @param size The size of the reader to emulate. 088 * @param markSupported Whether this instance will support 089 * the <code>mark()</code> functionality. 090 * @param throwEofException Whether this implementation 091 * will throw an {@link EOFException} or return -1 when the 092 * end of file is reached. 093 */ 094 public NullReader(long size, boolean markSupported, boolean throwEofException) { 095 this.size = size; 096 this.markSupported = markSupported; 097 this.throwEofException = throwEofException; 098 } 099 100 /** 101 * Return the current position. 102 * 103 * @return the current position. 104 */ 105 public long getPosition() { 106 return position; 107 } 108 109 /** 110 * Return the size this {@link Reader} emulates. 111 * 112 * @return The size of the reader to emulate. 113 */ 114 public long getSize() { 115 return size; 116 } 117 118 /** 119 * Close this Reader - resets the internal state to 120 * the initial values. 121 * 122 * @throws IOException If an error occurs. 123 */ 124 @Override 125 public void close() throws IOException { 126 eof = false; 127 position = 0; 128 mark = -1; 129 } 130 131 /** 132 * Mark the current position. 133 * 134 * @param readlimit The number of characters before this marked position 135 * is invalid. 136 * @throws UnsupportedOperationException if mark is not supported. 137 */ 138 @Override 139 public synchronized void mark(int readlimit) { 140 if (!markSupported) { 141 throw new UnsupportedOperationException("Mark not supported"); 142 } 143 mark = position; 144 this.readlimit = readlimit; 145 } 146 147 /** 148 * Indicates whether <i>mark</i> is supported. 149 * 150 * @return Whether <i>mark</i> is supported or not. 151 */ 152 @Override 153 public boolean markSupported() { 154 return markSupported; 155 } 156 157 /** 158 * Read a character. 159 * 160 * @return Either The character value returned by <code>processChar()</code> 161 * or <code>-1</code> if the end of file has been reached and 162 * <code>throwEofException</code> is set to <code>false</code>. 163 * @throws EOFException if the end of file is reached and 164 * <code>throwEofException</code> is set to <code>true</code>. 165 * @throws IOException if trying to read past the end of file. 166 */ 167 @Override 168 public int read() throws IOException { 169 if (eof) { 170 throw new IOException("Read after end of file"); 171 } 172 if (position == size) { 173 return doEndOfFile(); 174 } 175 position++; 176 return processChar(); 177 } 178 179 /** 180 * Read some characters into the specified array. 181 * 182 * @param chars The character array to read into 183 * @return The number of characters read or <code>-1</code> 184 * if the end of file has been reached and 185 * <code>throwEofException</code> is set to <code>false</code>. 186 * @throws EOFException if the end of file is reached and 187 * <code>throwEofException</code> is set to <code>true</code>. 188 * @throws IOException if trying to read past the end of file. 189 */ 190 @Override 191 public int read(char[] chars) throws IOException { 192 return read(chars, 0, chars.length); 193 } 194 195 /** 196 * Read the specified number characters into an array. 197 * 198 * @param chars The character array to read into. 199 * @param offset The offset to start reading characters into. 200 * @param length The number of characters to read. 201 * @return The number of characters read or <code>-1</code> 202 * if the end of file has been reached and 203 * <code>throwEofException</code> is set to <code>false</code>. 204 * @throws EOFException if the end of file is reached and 205 * <code>throwEofException</code> is set to <code>true</code>. 206 * @throws IOException if trying to read past the end of file. 207 */ 208 @Override 209 public int read(char[] chars, int offset, int length) throws IOException { 210 if (eof) { 211 throw new IOException("Read after end of file"); 212 } 213 if (position == size) { 214 return doEndOfFile(); 215 } 216 position += length; 217 int returnLength = length; 218 if (position > size) { 219 returnLength = length - (int)(position - size); 220 position = size; 221 } 222 processChars(chars, offset, returnLength); 223 return returnLength; 224 } 225 226 /** 227 * Reset the stream to the point when mark was last called. 228 * 229 * @throws UnsupportedOperationException if mark is not supported. 230 * @throws IOException If no position has been marked 231 * or the read limit has been exceed since the last position was 232 * marked. 233 */ 234 @Override 235 public synchronized void reset() throws IOException { 236 if (!markSupported) { 237 throw new UnsupportedOperationException("Mark not supported"); 238 } 239 if (mark < 0) { 240 throw new IOException("No position has been marked"); 241 } 242 if (position > mark + readlimit) { 243 throw new IOException("Marked position [" + mark + 244 "] is no longer valid - passed the read limit [" + 245 readlimit + "]"); 246 } 247 position = mark; 248 eof = false; 249 } 250 251 /** 252 * Skip a specified number of characters. 253 * 254 * @param numberOfChars The number of characters to skip. 255 * @return The number of characters skipped or <code>-1</code> 256 * if the end of file has been reached and 257 * <code>throwEofException</code> is set to <code>false</code>. 258 * @throws EOFException if the end of file is reached and 259 * <code>throwEofException</code> is set to <code>true</code>. 260 * @throws IOException if trying to read past the end of file. 261 */ 262 @Override 263 public long skip(long numberOfChars) throws IOException { 264 if (eof) { 265 throw new IOException("Skip after end of file"); 266 } 267 if (position == size) { 268 return doEndOfFile(); 269 } 270 position += numberOfChars; 271 long returnLength = numberOfChars; 272 if (position > size) { 273 returnLength = numberOfChars - (position - size); 274 position = size; 275 } 276 return returnLength; 277 } 278 279 /** 280 * Return a character value for the <code>read()</code> method. 281 * <p> 282 * This implementation returns zero. 283 * 284 * @return This implementation always returns zero. 285 */ 286 protected int processChar() { 287 // do nothing - overridable by subclass 288 return 0; 289 } 290 291 /** 292 * Process the characters for the <code>read(char[], offset, length)</code> 293 * method. 294 * <p> 295 * This implementation leaves the character array unchanged. 296 * 297 * @param chars The character array 298 * @param offset The offset to start at. 299 * @param length The number of characters. 300 */ 301 protected void processChars(char[] chars, int offset, int length) { 302 // do nothing - overridable by subclass 303 } 304 305 /** 306 * Handle End of File. 307 * 308 * @return <code>-1</code> if <code>throwEofException</code> is 309 * set to <code>false</code> 310 * @throws EOFException if <code>throwEofException</code> is set 311 * to <code>true</code>. 312 */ 313 private int doEndOfFile() throws EOFException { 314 eof = true; 315 if (throwEofException) { 316 throw new EOFException(); 317 } 318 return -1; 319 } 320 321 }