Skip to content

Commit b358a63

Browse files
robtimusgarydgregory
authored andcommitted
Added TaggedWriter, ClosedWriter and BrokenWriter. (#86)
1 parent 3bb84c2 commit b358a63

6 files changed

Lines changed: 539 additions & 0 deletions

File tree

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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.output;
18+
19+
import java.io.IOException;
20+
import java.io.Writer;
21+
22+
/**
23+
* Broken writer. This writer always throws an {@link IOException} from
24+
* all {@link Writer} methods.
25+
* <p>
26+
* This class is mostly useful for testing error handling in code that uses a
27+
* writer.
28+
*
29+
* @since 2.0
30+
*/
31+
public class BrokenWriter extends Writer {
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 writer that always throws the given exception.
40+
*
41+
* @param exception the exception to be thrown
42+
*/
43+
public BrokenWriter(final IOException exception) {
44+
this.exception = exception;
45+
}
46+
47+
/**
48+
* Creates a new writer that always throws an {@link IOException}
49+
*/
50+
public BrokenWriter() {
51+
this(new IOException("Broken writer"));
52+
}
53+
54+
/**
55+
* Throws the configured exception.
56+
*
57+
* @param cbuf ignored
58+
* @param off ignored
59+
* @param len ignored
60+
* @throws IOException always thrown
61+
*/
62+
@Override
63+
public void write(final char[] cbuf, final int off, final int len) throws IOException {
64+
throw exception;
65+
}
66+
67+
/**
68+
* Throws the configured exception.
69+
*
70+
* @throws IOException always thrown
71+
*/
72+
@Override
73+
public void flush() throws IOException {
74+
throw exception;
75+
}
76+
77+
/**
78+
* Throws the configured exception.
79+
*
80+
* @throws IOException always thrown
81+
*/
82+
@Override
83+
public void close() throws IOException {
84+
throw exception;
85+
}
86+
87+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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.output;
18+
19+
import java.io.IOException;
20+
import java.io.Writer;
21+
22+
/**
23+
* Closed writer. This writer throws an exception on all attempts to
24+
* write something to it.
25+
* <p>
26+
* Typically uses of this class include testing for corner cases in methods
27+
* that accept a writer and acting as a sentinel value instead of
28+
* a {@code null} writer.
29+
*
30+
* @since 2.7
31+
*/
32+
public class ClosedWriter extends Writer {
33+
34+
/**
35+
* A singleton.
36+
*/
37+
public static final ClosedWriter CLOSED_WRITER = new ClosedWriter();
38+
39+
/**
40+
* Throws an {@link IOException} to indicate that the writer is closed.
41+
*
42+
* @param cbuf ignored
43+
* @param off ignored
44+
* @param len ignored
45+
* @throws IOException always thrown
46+
*/
47+
@Override
48+
public void write(final char[] cbuf, final int off, final int len) throws IOException {
49+
throw new IOException("write(" + new String(cbuf) + ", " + off + ", " + len + ") failed: stream is closed");
50+
}
51+
52+
/**
53+
* Throws an {@link IOException} to indicate that the stream is closed.
54+
*
55+
* @throws IOException always thrown
56+
*/
57+
@Override
58+
public void flush() throws IOException {
59+
throw new IOException("flush() failed: stream is closed");
60+
}
61+
62+
@Override
63+
public void close() throws IOException {
64+
}
65+
}
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.output;
18+
19+
import java.io.IOException;
20+
import java.io.Serializable;
21+
import java.io.Writer;
22+
import java.util.UUID;
23+
24+
import org.apache.commons.io.TaggedIOException;
25+
26+
/**
27+
* A writer 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+
* writeToWriter(writer);
37+
* } catch (IOException e) {
38+
* if (writer.isCauseOf(e)) {
39+
* // The exception was caused by this writer.
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(Exception)} method can be
48+
* used to let higher levels of code handle the exception caused by this
49+
* writer while other processing errors are being taken care of at this
50+
* lower level.
51+
* <pre>
52+
* TaggedWriter writer = new TaggedWriter(...);
53+
* try {
54+
* writeToWriter(writer);
55+
* } catch (IOException e) {
56+
* writer.throwIfCauseOf(e);
57+
* // ... or process the exception that was caused by something else
58+
* }
59+
* </pre>
60+
*
61+
* @see TaggedIOException
62+
* @since 2.0
63+
*/
64+
public class TaggedWriter extends ProxyWriter {
65+
66+
/**
67+
* The unique tag associated with exceptions from writer.
68+
*/
69+
private final Serializable tag = UUID.randomUUID();
70+
71+
/**
72+
* Creates a tagging decorator for the given writer.
73+
*
74+
* @param proxy writer to be decorated
75+
*/
76+
public TaggedWriter(final Writer proxy) {
77+
super(proxy);
78+
}
79+
80+
/**
81+
* Tests if the given exception was caused by this writer.
82+
*
83+
* @param exception an exception
84+
* @return {@code true} if the exception was thrown by this writer,
85+
* {@code false} otherwise
86+
*/
87+
public boolean isCauseOf(final Exception exception) {
88+
return TaggedIOException.isTaggedWith(exception, tag);
89+
}
90+
91+
/**
92+
* Re-throws the original exception thrown by this writer. 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 writer.
97+
*
98+
* @param exception an exception
99+
* @throws IOException original exception, if any, thrown by this writer
100+
*/
101+
public void throwIfCauseOf(final Exception exception) throws IOException {
102+
TaggedIOException.throwCauseIfTaggedWith(exception, 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: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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.output;
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.Writer;
24+
25+
import org.junit.Before;
26+
import org.junit.Test;
27+
28+
/**
29+
* JUnit Test Case for {@link BrokenWriter}.
30+
*/
31+
public class BrokenWriterTest {
32+
33+
private IOException exception;
34+
35+
private Writer writer;
36+
37+
@Before
38+
public void setUp() {
39+
exception = new IOException("test exception");
40+
writer = new BrokenWriter(exception);
41+
}
42+
43+
@Test
44+
public void testWrite() {
45+
try {
46+
writer.write(1);
47+
fail("Expected exception not thrown.");
48+
} catch (final IOException e) {
49+
assertEquals(exception, e);
50+
}
51+
52+
try {
53+
writer.write(new char[1]);
54+
fail("Expected exception not thrown.");
55+
} catch (final IOException e) {
56+
assertEquals(exception, e);
57+
}
58+
59+
try {
60+
writer.write(new char[1], 0, 1);
61+
fail("Expected exception not thrown.");
62+
} catch (final IOException e) {
63+
assertEquals(exception, e);
64+
}
65+
}
66+
67+
@Test
68+
public void testFlush() {
69+
try {
70+
writer.flush();
71+
fail("Expected exception not thrown.");
72+
} catch (final IOException e) {
73+
assertEquals(exception, e);
74+
}
75+
}
76+
77+
@Test
78+
public void testClose() {
79+
try {
80+
writer.close();
81+
fail("Expected exception not thrown.");
82+
} catch (final IOException e) {
83+
assertEquals(exception, e);
84+
}
85+
}
86+
87+
}

0 commit comments

Comments
 (0)