Skip to content

Commit 3615e14

Browse files
robtimusgarydgregory
authored andcommitted
Added TaggedReader, ClosedReader and BrokenReader. (#85)
* Added TaggedReader, ClosedReader and BrokenReader. * Fixed the since version of TaggedReader * Marked parameters as final. * Replaced an incorrect tab with spaces.
1 parent b79b6ea commit 3615e14

4 files changed

Lines changed: 483 additions & 0 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.commons.io.input;
18+
19+
import java.io.IOException;
20+
import java.io.Reader;
21+
22+
/**
23+
* Broken reader. This reader always throws an {@link IOException} from
24+
* all the {@link Reader} methods where the exception is declared.
25+
* <p>
26+
* This class is mostly useful for testing error handling in code that uses a
27+
* reader.
28+
*
29+
* @since 2.7
30+
*/
31+
public class BrokenReader extends Reader {
32+
33+
/**
34+
* The exception that is thrown by all methods of this class.
35+
*/
36+
private final IOException exception;
37+
38+
/**
39+
* Creates a new reader that always throws the given exception.
40+
*
41+
* @param exception the exception to be thrown
42+
*/
43+
public BrokenReader(final IOException exception) {
44+
this.exception = exception;
45+
}
46+
47+
/**
48+
* Creates a new reader that always throws an {@link IOException}
49+
*/
50+
public BrokenReader() {
51+
this(new IOException("Broken reader"));
52+
}
53+
54+
/**
55+
* Throws the configured exception.
56+
*
57+
* @param cbuf ignored
58+
* @param off ignored
59+
* @param len ignored
60+
* @return nothing
61+
* @throws IOException always thrown
62+
*/
63+
@Override
64+
public int read(final char[] cbuf, final int off, final int len) throws IOException {
65+
throw exception;
66+
}
67+
68+
/**
69+
* Throws the configured exception.
70+
*
71+
* @param n ignored
72+
* @return nothing
73+
* @throws IOException always thrown
74+
*/
75+
@Override
76+
public long skip(final long n) throws IOException {
77+
throw exception;
78+
}
79+
80+
/**
81+
* Throws the configured exception.
82+
*
83+
* @return nothing
84+
* @throws IOException always thrown
85+
*/
86+
@Override
87+
public boolean ready() throws IOException {
88+
throw exception;
89+
}
90+
91+
/**
92+
* Throws the configured exception.
93+
*
94+
* @param readAheadLimit ignored
95+
* @throws IOException always thrown
96+
*/
97+
@Override
98+
public void mark(final int readAheadLimit) throws IOException {
99+
throw exception;
100+
}
101+
102+
/**
103+
* Throws the configured exception.
104+
*
105+
* @throws IOException always thrown
106+
*/
107+
@Override
108+
public synchronized void reset() throws IOException {
109+
throw exception;
110+
}
111+
112+
/**
113+
* Throws the configured exception.
114+
*
115+
* @throws IOException always thrown
116+
*/
117+
@Override
118+
public void close() throws IOException {
119+
throw exception;
120+
}
121+
122+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.commons.io.input;
18+
19+
import java.io.IOException;
20+
import java.io.Reader;
21+
import java.io.Serializable;
22+
import java.util.UUID;
23+
24+
import org.apache.commons.io.TaggedIOException;
25+
26+
/**
27+
* A reader decorator that tags potential exceptions so that the
28+
* reader that caused the exception can easily be identified. This is
29+
* done by using the {@link TaggedIOException} class to wrap all thrown
30+
* {@link IOException}s. See below for an example of using this class.
31+
* <pre>
32+
* TaggedReader reader = new TaggedReader(...);
33+
* try {
34+
* // Processing that may throw an IOException either from this reader
35+
* // or from some other IO activity like temporary files, etc.
36+
* processReader(reader);
37+
* } catch (IOException e) {
38+
* if (reader.isCauseOf(e)) {
39+
* // The exception was caused by this reader.
40+
* // Use e.getCause() to get the original exception.
41+
* } else {
42+
* // The exception was caused by something else.
43+
* }
44+
* }
45+
* </pre>
46+
* <p>
47+
* Alternatively, the {@link #throwIfCauseOf(Throwable)} method can be
48+
* used to let higher levels of code handle the exception caused by this
49+
* reader while other processing errors are being taken care of at this
50+
* lower level.
51+
* <pre>
52+
* TaggedReader reader = new TaggedReader(...);
53+
* try {
54+
* processReader(reader);
55+
* } catch (IOException e) {
56+
* reader.throwIfCauseOf(e);
57+
* // ... or process the exception that was caused by something else
58+
* }
59+
* </pre>
60+
*
61+
* @see TaggedIOException
62+
* @since 2.7
63+
*/
64+
public class TaggedReader extends ProxyReader {
65+
66+
/**
67+
* The unique tag associated with exceptions from reader.
68+
*/
69+
private final Serializable tag = UUID.randomUUID();
70+
71+
/**
72+
* Creates a tagging decorator for the given reader.
73+
*
74+
* @param proxy reader to be decorated
75+
*/
76+
public TaggedReader(final Reader proxy) {
77+
super(proxy);
78+
}
79+
80+
/**
81+
* Tests if the given exception was caused by this reader.
82+
*
83+
* @param exception an exception
84+
* @return {@code true} if the exception was thrown by this reader,
85+
* {@code false} otherwise
86+
*/
87+
public boolean isCauseOf(final Throwable exception) {
88+
return TaggedIOException.isTaggedWith(exception, tag);
89+
}
90+
91+
/**
92+
* Re-throws the original exception thrown by this reader. This method
93+
* first checks whether the given exception is a {@link TaggedIOException}
94+
* wrapper created by this decorator, and then unwraps and throws the
95+
* original wrapped exception. Returns normally if the exception was
96+
* not thrown by this reader.
97+
*
98+
* @param throwable an exception
99+
* @throws IOException original exception, if any, thrown by this reader
100+
*/
101+
public void throwIfCauseOf(final Throwable throwable) throws IOException {
102+
TaggedIOException.throwCauseIfTaggedWith(throwable, tag);
103+
}
104+
105+
/**
106+
* Tags any IOExceptions thrown, wrapping and re-throwing.
107+
*
108+
* @param e The IOException thrown
109+
* @throws IOException if an I/O error occurs
110+
*/
111+
@Override
112+
protected void handleIOException(final IOException e) throws IOException {
113+
throw new TaggedIOException(e, tag);
114+
}
115+
116+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.commons.io.input;
18+
19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.fail;
21+
22+
import java.io.IOException;
23+
import java.io.Reader;
24+
25+
import org.junit.Before;
26+
import org.junit.Test;
27+
28+
/**
29+
* JUnit Test Case for {@link BrokenReader}.
30+
*/
31+
@SuppressWarnings("ResultOfMethodCallIgnored")
32+
public class BrokenReaderTest {
33+
34+
private IOException exception;
35+
36+
private Reader reader;
37+
38+
@Before
39+
public void setUp() {
40+
exception = new IOException("test exception");
41+
reader = new BrokenReader(exception);
42+
}
43+
44+
@Test
45+
public void testRead() {
46+
try {
47+
reader.read();
48+
fail("Expected exception not thrown.");
49+
} catch (final IOException e) {
50+
assertEquals(exception, e);
51+
}
52+
53+
try {
54+
reader.read(new char[1]);
55+
fail("Expected exception not thrown.");
56+
} catch (final IOException e) {
57+
assertEquals(exception, e);
58+
}
59+
60+
try {
61+
reader.read(new char[1], 0, 1);
62+
fail("Expected exception not thrown.");
63+
} catch (final IOException e) {
64+
assertEquals(exception, e);
65+
}
66+
}
67+
68+
@Test
69+
public void testSkip() {
70+
try {
71+
reader.skip(1);
72+
fail("Expected exception not thrown.");
73+
} catch (final IOException e) {
74+
assertEquals(exception, e);
75+
}
76+
}
77+
78+
@Test
79+
public void testReady() {
80+
try {
81+
reader.ready();
82+
fail("Expected exception not thrown.");
83+
} catch (final IOException e) {
84+
assertEquals(exception, e);
85+
}
86+
}
87+
88+
@Test
89+
public void testMark() {
90+
try {
91+
reader.mark(1);
92+
fail("Expected exception not thrown.");
93+
} catch (final IOException e) {
94+
assertEquals(exception, e);
95+
}
96+
}
97+
98+
@Test
99+
public void testReset() {
100+
try {
101+
reader.reset();
102+
fail("Expected exception not thrown.");
103+
} catch (final IOException e) {
104+
assertEquals(exception, e);
105+
}
106+
}
107+
108+
@Test
109+
public void testClose() {
110+
try {
111+
reader.close();
112+
fail("Expected exception not thrown.");
113+
} catch (final IOException e) {
114+
assertEquals(exception, e);
115+
}
116+
}
117+
118+
}

0 commit comments

Comments
 (0)