diff --git a/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java b/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java index e946b54e055..ba5aa04b609 100644 --- a/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java +++ b/src/main/java/org/apache/commons/io/input/AutoCloseInputStream.java @@ -32,18 +32,36 @@ * stream as soon as possible even if the client application (by not explicitly * closing the stream when no longer needed) or the underlying stream (by not * releasing resources once the last byte has been read) do not do that. + *

+ * Since there is no safe way to always close the stream when reaching the end and + * respecting mark/reset contract, it's possible to force disabled mark support. + * This is highly recommended when you don't know how the stream is going to be used + * (mark is not disabled by default for retro compatibility reasons). * * @since 1.4 */ public class AutoCloseInputStream extends ProxyInputStream { + private boolean markEnabled = true; + /** * Creates an automatically closing proxy for the given input stream. * * @param in underlying input stream */ public AutoCloseInputStream(final InputStream in) { + this(in, true); + } + + /** + * Creates an automatically closing proxy for the given input stream. + * + * @param in underlying input stream + */ + public AutoCloseInputStream(final InputStream in, boolean markEnabled) { super(in); + + this.markEnabled = markEnabled; } /** @@ -79,6 +97,33 @@ protected void afterRead(final int n) throws IOException { } } + @Override + public synchronized void mark(int readlimit) { + if (this.markEnabled) { + super.mark(readlimit); + } + } + + @Override + public synchronized void reset() throws IOException { + if (this.markEnabled) { + super.reset(); + } else { + // Behave as standard InputStream not supporting mark/reset + throw new IOException("mark/reset not supported"); + } + } + + @Override + public boolean markSupported() { + if (this.markEnabled) { + return super.markSupported(); + } else { + // Behave as standard InputStream not supporting mark/reset + return false; + } + } + /** * Ensures that the stream is closed before it gets garbage-collected. * As mentioned in {@link #close()}, this is a no-op if the stream has diff --git a/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java b/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java deleted file mode 100644 index 09c4e9f5b9d..00000000000 --- a/src/test/java/org/apache/commons/io/input/AutoCloseInputStreamTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.junit.Before; -import org.junit.Test; - -/** - * JUnit Test Case for {@link AutoCloseInputStream}. - */ -public class AutoCloseInputStreamTest { - - private byte[] data; - - private InputStream stream; - - private boolean closed; - - @Before - public void setUp() { - data = new byte[] { 'x', 'y', 'z' }; - stream = new AutoCloseInputStream(new ByteArrayInputStream(data) { - @Override - public void close() { - closed = true; - } - }); - closed = false; - } - - @Test - public void testClose() throws IOException { - stream.close(); - assertTrue("closed", closed); - assertEquals("read()", -1, stream.read()); - } - - - @Test - public void testRead() throws IOException { - for (final byte element : data) { - assertEquals("read()", element, stream.read()); - assertFalse("closed", closed); - } - assertEquals("read()", -1, stream.read()); - assertTrue("closed", closed); - } - - @Test - public void testReadBuffer() throws IOException { - final byte[] b = new byte[data.length * 2]; - int total = 0; - for (int n = 0; n != -1; n = stream.read(b)) { - assertFalse("closed", closed); - for (int i = 0; i < n; i++) { - assertEquals("read(b)", data[total + i], b[i]); - } - total += n; - } - assertEquals("read(b)", data.length, total); - assertTrue("closed", closed); - assertEquals("read(b)", -1, stream.read(b)); - } - - @Test - public void testReadBufferOffsetLength() throws IOException { - final byte[] b = new byte[data.length * 2]; - int total = 0; - for (int n = 0; n != -1; n = stream.read(b, total, b.length - total)) { - assertFalse("closed", closed); - total += n; - } - assertEquals("read(b, off, len)", data.length, total); - for (int i = 0; i < data.length; i++) { - assertEquals("read(b, off, len)", data[i], b[i]); - } - assertTrue("closed", closed); - assertEquals("read(b, off, len)", -1, stream.read(b, 0, b.length)); - } - -} diff --git a/src/test/java/org/apache/commons/io/input/MarkEnabledAutoCloseInputStreamTest.java b/src/test/java/org/apache/commons/io/input/MarkEnabledAutoCloseInputStreamTest.java new file mode 100644 index 00000000000..3e31ea65a23 --- /dev/null +++ b/src/test/java/org/apache/commons/io/input/MarkEnabledAutoCloseInputStreamTest.java @@ -0,0 +1,54 @@ +/* + * 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 org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * JUnit Test Case for {@link AutoCloseInputStream} with enabled mark support (the default). + */ +public class MarkEnabledAutoCloseInputStreamTest extends AbstractAutoCloseInputStreamTest { + + public MarkEnabledAutoCloseInputStreamTest() { + super(true); + } + + @Test + public void testMark() throws IOException { + assertTrue(targetStream.markSupported()); + + // Make sure mark is disabled + assertTrue(stream.markSupported()); + + // Check that mark() does not fail + stream.mark(1); + assertTrue("not marked", marked); + + assertEquals('x', this.stream.read()); + + // Check that reset() works + stream.reset(); + assertTrue("not reseted", reseted); + + assertEquals('x', this.stream.read()); + } +}