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 Commons IO 1.3
061: * @version $Revision: 463529 $
062: */
063: public class NullReader extends Reader {
064:
065: private long size;
066: private long position;
067: private long mark = -1;
068: private long readlimit;
069: private boolean eof;
070: private boolean throwEofException;
071: private 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,
095: boolean throwEofException) {
096: this .size = size;
097: this .markSupported = markSupported;
098: this .throwEofException = throwEofException;
099: }
100:
101: /**
102: * Return the current position.
103: *
104: * @return the current position.
105: */
106: public long getPosition() {
107: return position;
108: }
109:
110: /**
111: * Return the size this {@link Reader} emulates.
112: *
113: * @return The size of the reader to emulate.
114: */
115: public long getSize() {
116: return size;
117: }
118:
119: /**
120: * Close this Reader - resets the internal state to
121: * the initial values.
122: *
123: * @throws IOException If an error occurs.
124: */
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: public synchronized void mark(int readlimit) {
139: if (!markSupported) {
140: throw new UnsupportedOperationException(
141: "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: public boolean markSupported() {
153: return markSupported;
154: }
155:
156: /**
157: * Read a character.
158: *
159: * @return Either The character value returned by <code>processChar()</code>
160: * or <code>-1</code> if the end of file has been reached and
161: * <code>throwEofException</code> is set to <code>false</code>.
162: * @throws EOFException if the end of file is reached and
163: * <code>throwEofException</code> is set to <code>true</code>.
164: * @throws IOException if trying to read past the end of file.
165: */
166: public int read() throws IOException {
167: if (eof) {
168: throw new IOException("Read after end of file");
169: }
170: if (position == size) {
171: return doEndOfFile();
172: }
173: position++;
174: return processChar();
175: }
176:
177: /**
178: * Read some characters into the specified array.
179: *
180: * @param chars The character array to read into
181: * @return The number of characters read or <code>-1</code>
182: * if the end of file has been reached and
183: * <code>throwEofException</code> is set to <code>false</code>.
184: * @throws EOFException if the end of file is reached and
185: * <code>throwEofException</code> is set to <code>true</code>.
186: * @throws IOException if trying to read past the end of file.
187: */
188: public int read(char[] chars) throws IOException {
189: return read(chars, 0, chars.length);
190: }
191:
192: /**
193: * Read the specified number characters into an array.
194: *
195: * @param chars The character array to read into.
196: * @param offset The offset to start reading characters into.
197: * @param length The number of characters to read.
198: * @return The number of characters read or <code>-1</code>
199: * if the end of file has been reached and
200: * <code>throwEofException</code> is set to <code>false</code>.
201: * @throws EOFException if the end of file is reached and
202: * <code>throwEofException</code> is set to <code>true</code>.
203: * @throws IOException if trying to read past the end of file.
204: */
205: public int read(char[] chars, int offset, int length)
206: throws IOException {
207: if (eof) {
208: throw new IOException("Read after end of file");
209: }
210: if (position == size) {
211: return doEndOfFile();
212: }
213: position += length;
214: int returnLength = length;
215: if (position > size) {
216: returnLength = length - (int) (position - size);
217: position = size;
218: }
219: processChars(chars, offset, returnLength);
220: return returnLength;
221: }
222:
223: /**
224: * Reset the stream to the point when mark was last called.
225: *
226: * @throws UnsupportedOperationException if mark is not supported.
227: * @throws IOException If no position has been marked
228: * or the read limit has been exceed since the last position was
229: * marked.
230: */
231: public synchronized void reset() throws IOException {
232: if (!markSupported) {
233: throw new UnsupportedOperationException(
234: "Mark not supported");
235: }
236: if (mark < 0) {
237: throw new IOException("No position has been marked");
238: }
239: if (position > (mark + readlimit)) {
240: throw new IOException("Marked position [" + mark
241: + "] is no longer valid - passed the read limit ["
242: + readlimit + "]");
243: }
244: position = mark;
245: eof = false;
246: }
247:
248: /**
249: * Skip a specified number of characters.
250: *
251: * @param numberOfChars The number of characters to skip.
252: * @return The number of characters skipped or <code>-1</code>
253: * if the end of file has been reached and
254: * <code>throwEofException</code> is set to <code>false</code>.
255: * @throws EOFException if the end of file is reached and
256: * <code>throwEofException</code> is set to <code>true</code>.
257: * @throws IOException if trying to read past the end of file.
258: */
259: public long skip(long numberOfChars) throws IOException {
260: if (eof) {
261: throw new IOException("Skip after end of file");
262: }
263: if (position == size) {
264: return doEndOfFile();
265: }
266: position += numberOfChars;
267: long returnLength = numberOfChars;
268: if (position > size) {
269: returnLength = numberOfChars - (position - size);
270: position = size;
271: }
272: return returnLength;
273: }
274:
275: /**
276: * Return a character value for the <code>read()</code> method.
277: * <p>
278: * This implementation returns zero.
279: *
280: * @return This implementation always returns zero.
281: */
282: protected int processChar() {
283: // do nothing - overridable by subclass
284: return 0;
285: }
286:
287: /**
288: * Process the characters for the <code>read(char[], offset, length)</code>
289: * method.
290: * <p>
291: * This implementation leaves the character array unchanged.
292: *
293: * @param chars The character array
294: * @param offset The offset to start at.
295: * @param length The number of characters.
296: */
297: protected void processChars(char[] chars, int offset, int length) {
298: // do nothing - overridable by subclass
299: }
300:
301: /**
302: * Handle End of File.
303: *
304: * @return <code>-1</code> if <code>throwEofException</code> is
305: * set to <code>false</code>
306: * @throws EOFException if <code>throwEofException</code> is set
307: * to <code>true</code>.
308: */
309: private int doEndOfFile() throws EOFException {
310: eof = true;
311: if (throwEofException) {
312: throw new EOFException();
313: }
314: return -1;
315: }
316:
317: }
|