You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ol...@apache.org on 2014/10/28 00:09:49 UTC

svn commit: r1634731 - in /commons/proper/io/trunk/src: main/java/org/apache/commons/io/input/BoundedReader.java test/java/org/apache/commons/io/input/BoundedReaderTest.java

Author: olamy
Date: Mon Oct 27 23:09:49 2014
New Revision: 1634731

URL: http://svn.apache.org/r1634731
Log:
[IO-457] Add BoundedReader
Submitted by Kristian Rosenvold


Added:
    commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/BoundedReader.java   (with props)
    commons/proper/io/trunk/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java   (with props)

Added: commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/BoundedReader.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/BoundedReader.java?rev=1634731&view=auto
==============================================================================
--- commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/BoundedReader.java (added)
+++ commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/BoundedReader.java Mon Oct 27 23:09:49 2014
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.io.input;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * A reader that imposes a limit to the number of characters that can be read from
+ * an underlying reader, returning eof when this limit is reached -regardless of state of
+ * underlying reader.
+ *
+ * One use case is to avoid overrunning the readAheadLimit supplied to
+ * java.io.Reader#mark(int), since reading too many characters removes the
+ * ability to do a successful reset.
+ *
+ * @since 2.5
+ */
+public class BoundedReader
+    extends Reader {
+
+    private static final int INVALID = -1;
+
+	private final Reader target;
+
+	int charsRead = 0;
+
+    int markedAt = INVALID;
+
+	int readAheadLimit; // Internally, this value will never exceed the allowed size
+
+    private final int maxCharsFromTargetReader;
+
+    /**
+     * Constructs a bounded reader
+     * @param target The target stream that will be used
+     * @param maxCharsFromTargetReader The maximum number of characters that can be read from target
+     * @throws IOException if mark fails
+     */
+	public BoundedReader( Reader target, int maxCharsFromTargetReader ) throws IOException {
+		this.target = target;
+        this.maxCharsFromTargetReader = maxCharsFromTargetReader;
+	}
+
+    /**
+     * Closes the target
+     * @throws IOException
+     */
+	@Override
+	public void close() throws IOException {
+		target.close();
+	}
+
+    /**
+     * Resets the target to the latest mark, @see java.io.Reader#reset()
+     * @throws IOException
+     */
+	@Override
+	public void reset() throws IOException {
+		charsRead = markedAt;
+		target.reset();
+	}
+
+    /**
+     * marks the target stream, @see java.io.Reader#mark(int).
+     *
+     * @param readAheadLimit The number of characters that can be read while
+     *                       still retaining the ability to do #reset().
+     *                       Note that this parameter is not validated with respect to
+     *                       maxCharsFromTargetReader. There is no way to pass
+     *                       past maxCharsFromTargetReader, even if this value is
+     *                       greater.
+     */
+	@Override
+	public void mark(int readAheadLimit) throws IOException {
+		this.readAheadLimit = readAheadLimit -charsRead;
+
+        markedAt = charsRead;
+
+		target.mark(readAheadLimit);
+	}
+
+    /**
+     * Reads a single character, @see java.io.Reader#read()
+     * @return -1 on eof or the character read
+     * @throws IOException If an I/O error occurs
+     */
+	@Override
+	public int read() throws IOException {
+
+		if ( charsRead >= maxCharsFromTargetReader) {
+			return -1;
+		}
+
+        if ( markedAt >= 0 && (charsRead  -markedAt) >= readAheadLimit) {
+			return -1;
+		}
+		charsRead++;
+		return target.read();
+	}
+
+    /**
+     * Reads into an array, @see java.io.Reader#read(char[], int, int)
+     * @param cbuf The buffer to fill
+     * @param off The offset
+     * @param len The number of chars to read
+     * @return the number of chars read
+     * @throws IOException
+     */
+	@Override
+	public int read(char[] cbuf, int off, int len) throws IOException {
+		int c;
+		for (int i = 0; i < len; i++){
+			c = read();
+			if (c == -1) return i;
+			cbuf[off + i] = (char) c;
+		}
+		return len;
+	}
+}

Propchange: commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/BoundedReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/io/trunk/src/main/java/org/apache/commons/io/input/BoundedReader.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Added: commons/proper/io/trunk/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java
URL: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java?rev=1634731&view=auto
==============================================================================
--- commons/proper/io/trunk/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java (added)
+++ commons/proper/io/trunk/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java Mon Oct 27 23:09:49 2014
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.commons.io.input;
+
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class BoundedReaderTest
+{
+	private final Reader sr = new BufferedReader(new StringReader("01234567890"));
+    private final Reader shortReader = new BufferedReader(new StringReader("01"));
+
+	@Test
+	public void readTillEnd() throws IOException {
+		BoundedReader mr = new BoundedReader(sr, 3);
+		mr.read();
+		mr.read();
+		mr.read();
+		assertEquals(-1, mr.read());
+	}
+
+    @Test
+    public void shortReader() throws IOException {
+        BoundedReader mr = new BoundedReader(shortReader, 3);
+        mr.read();
+        mr.read();
+        assertEquals(-1, mr.read());
+    }
+
+	@Test
+	public void readMulti() throws IOException {
+		BoundedReader mr = new BoundedReader(sr, 3);
+		char[] cbuf = new char[4];
+		for (int i= 0; i < cbuf.length; i++) cbuf[i] = 'X';
+		final int read = mr.read(cbuf, 0, 4);
+		assertEquals( 3, read);
+		assertEquals('0', cbuf[0]);
+		assertEquals('1', cbuf[1]);
+		assertEquals('2', cbuf[2]);
+		assertEquals('X', cbuf[3]);
+	}
+
+	@Test
+	public void readMultiWithOffset() throws IOException {
+		BoundedReader mr = new BoundedReader(sr, 3);
+		char[] cbuf = new char[4];
+		for (int i= 0; i < cbuf.length; i++) cbuf[i] = 'X';
+		final int read = mr.read(cbuf, 1, 2);
+		assertEquals( 2, read);
+		assertEquals('X', cbuf[0]);
+		assertEquals('0', cbuf[1]);
+		assertEquals('1', cbuf[2]);
+		assertEquals('X', cbuf[3]);
+	}
+
+	@Test
+	public void markReset() throws IOException {
+		BoundedReader mr = new BoundedReader(sr,3 );
+        mr.mark(3);
+		mr.read();
+		mr.read();
+		mr.read();
+		mr.reset();
+		mr.read();
+		mr.read();
+		mr.read();
+		assertEquals(-1, mr.read());
+	}
+
+
+    @Test
+    public void markResetWithMarkOutsideBoundedReaderMax() throws IOException {
+        BoundedReader mr = new BoundedReader(sr,3 );
+        mr.mark(4);
+        mr.read();
+        mr.read();
+        mr.read();
+        assertEquals(-1, mr.read());
+    }
+
+    @Test
+    public void markResetWithMarkOutsideBoundedReaderMaxAndInitialOffset() throws IOException {
+        BoundedReader mr = new BoundedReader(sr,3 );
+        mr.read();
+        mr.mark(3);
+        mr.read();
+        mr.read();
+        assertEquals(-1, mr.read());
+    }
+
+    @Test
+    public void markResetFromOffset1() throws IOException {
+        BoundedReader mr = new BoundedReader(sr,3 );
+        mr.mark( 3 );
+        mr.read();
+        mr.read();
+        mr.read();
+        assertEquals(-1, mr.read());
+        mr.reset();
+        mr.mark( 1 );
+        mr.read();
+        assertEquals(-1, mr.read());
+    }
+
+    @Test
+    public void markResetMarkMore() throws IOException {
+        BoundedReader mr = new BoundedReader(sr,3 );
+        mr.mark(4);
+        mr.read();
+        mr.read();
+        mr.read();
+        mr.reset();
+        mr.read();
+        mr.read();
+        mr.read();
+        assertEquals(-1, mr.read());
+    }
+
+	@Test
+	public void skipTest() throws IOException {
+		BoundedReader mr = new BoundedReader(sr, 3);
+		mr.skip(2);
+		mr.read();
+		assertEquals(-1, mr.read());
+	}
+
+    @Test
+    public void closeTest()
+        throws IOException
+    {
+        final AtomicBoolean closed = new AtomicBoolean( false );
+        final Reader sr = new BufferedReader(new StringReader("01234567890")){
+            @Override
+            public void close()
+                throws IOException {
+                closed.set( true );
+                super.close();
+            }
+        };
+
+        BoundedReader mr = new BoundedReader( sr,3 );
+        mr.close();
+        assertTrue( closed.get());
+    }
+}
\ No newline at end of file

Propchange: commons/proper/io/trunk/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/io/trunk/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision