10BC8 IO-192: Tagged input and output streams · apache/commons-io@71fd532 · GitHub
Skip to content

Commit 71fd532

Browse files
committed
IO-192: Tagged input and output streams
Added the proposed TaggedIOException, TaggedInputStream and TaggedOutputStream classes and related unit tests. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/io/trunk@741562 13f79535-47bb-0310-9956-ffa450edef68
1 parent 7c80287 commit 71fd532

9 files changed

Lines changed: 679 additions & 0 deletions

File tree

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;
18+
19+
import java.io.IOException;
20+
21+
/**
22+
* An {@link IOException} wrapper that tags the wrapped exception with
23+
* a given object reference. Both the tag and the wrapped original exception
24+
* can be used to determine further processing when this exception is caught.
25+
*
26+
* @since Commons IO 1.5
27+
*/
28+
public class TaggedIOException extends IOExceptionWithCause {
29+
30+
/**
31+
* The object reference used to tag the exception.
32+
*/
33+
private final Object tag;
34+
35+
/**
36+
* Creates a tagged wrapper for the given exception.
37+
*
38+
* @param original the exception to be tagged
39+
* @param tag tag object
40+
*/
41+
public TaggedIOException(IOException original, Object tag) {
42+
super(original.getMessage(), original);
43+
this.tag = tag;
44+
}
45+
46+
/**
47+
* Returns the object reference used as the tag this exception.
48+
*
49+
* @return tag object
50+
*/
51+
public Object getTag() {
52+
return tag;
53+
}
54+
55+
/**
56+
* Returns the wrapped exception. The only difference to the overridden
57+
* {@link Throwable#getCause()} method is the narrower return type.
58+
*
59+
* @return wrapped exception
60+
*/
61+
public IOException getCause() {
62+
return (IOException) super.getCause();
63+
}
64+
65+
}
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
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.InputStream;
21+
22+
import org.apache.commons.io.TaggedIOException;
23+
24+
/**
25+
* An input stream decorator that tags potential exceptions so that the
26+
* stream that caused the exception can easily be identified. This is
27+
* done by using the {@link TaggedIOException} class to wrap all thrown
28+
* {@link IOException}s. See below for an example of using this class.
29+
* <pre>
30+
* TaggedInputStream stream = new TaggedInputStream(...);
31+
* try {
32+
* // Processing that may throw an IOException either from this stream
33+
* // or from some other IO activity like temporary files, etc.
34+
* processStream(stream);
35+
* } catch (IOException e) {
36+
* if (stream.isCauseOf(e)) {
37+
* // The exception was caused by this stream.
38+
* // Use e.getCause() to get the original exception.
39+
* } else {
40+
* // The exception was caused by something else.
41+
* }
42+
* }
43+
* </pre>
44+
* <p>
45+
* Alternatively, the {@link #throwIfCauseOf(Exception)} method can be
46+
* used to let higher levels of code handle the exception caused by this
47+
* stream while other processing errors are being taken care of at this
48+
* lower level.
49+
* <pre>
50+
* TaggedInputStream stream = new TaggedInputStream(...);
51+
* try {
52+
* processStream(stream);
53+
* } catch (IOException e) {
54+
* stream.throwIfCauseOf(e);
55+
* // ... or process the exception that was caused by something else
56+
* }
57+
* </pre>
58+
*
59+
* @see TaggedIOException
60+
* @since Commons IO 1.5
61+
*/
62+
public class TaggedInputStream extends ProxyInputStream {
63+
64+
/**
65+
* Creates a tagging decorator for the given input stream.
66+
*
67+
* @param proxy input stream to be decorated
68+
*/
69+
public TaggedInputStream(InputStream proxy) {
70+
super(proxy);
71+
}
72+
73+
/**
74+
* Tests if the given exception was caused by this stream.
75+
*
76+
* @param exception an exception
77+
* @return <code>true</code> if the exception was thrown by this stream,
78+
* <code>false</code> otherwise
79+
*/
80+
public boolean isCauseOf(IOException exception) {
81+
if (exception instanceof TaggedIOException) {
82+
TaggedIOException tagged = (TaggedIOException) exception;
83+
return this == tagged.getTag();
84+
} else {
85+
return false;
86+
}
87+
}
88+
89+
/**
90+
* Re-throws the original exception thrown by this stream. This method
91+
* first checks whether the given exception is a {@link TaggedIOException}
92+
* wrapper created by this decorator, and then unwraps and throws the
93+
* original wrapped exception. Returns normally if the exception was
94+
* not thrown by this stream.
95+
*
96+
* @param exception an exception
97+
* @throws IOException original exception, if any, thrown by this stream
98+
*/
99+
public void throwIfCauseOf(Exception exception) throws IOException {
100+
if (exception instanceof TaggedIOException) {
101+
TaggedIOException tagged = (TaggedIOException) exception;
102+
if (this == tagged.getTag()) {
103+
throw tagged.getCause();
104+
}
105+
}
106+
}
107+
108+
@Override
109+
public int available() throws IOException {
110+
try {
111+
return super.available();
112+
} catch (IOException e) {
113+
throw new TaggedIOException(e, this);
114+
}
115+
}
116+
117+
@Override
118+
public int read() throws IOException {
119+
try {
120+
return super.read();
121+
} catch (IOException e) {
122+
throw new TaggedIOException(e, this);
123+
}
124+
}
125+
126+
@Override
127+
public int read(byte[] bts, int st, int end) throws IOException {
128+
try {
129+
return super.read(bts, st, end);
130+
} catch (IOException e) {
131+
throw new TaggedIOException(e, this);
132+
}
133+
}
134+
135+
@Override
136+
public int read(byte[] bts) throws IOException {
137+
try {
138+
return super.read(bts);
139+
} catch (IOException e) {
140+
throw new TaggedIOException(e, this);
141+
}
142+
}
143+
144+
@Override
145+
public long skip(long ln) throws IOException {
146+
try {
147+
return super.skip(ln);
148+
} catch (IOException e) {
149+
throw new TaggedIOException(e, this);
150+
}
151+
}
152+
153+
@Override
154+
public void reset() throws IOException {
155+
try {
156+
super.reset();
157+
} catch (IOException e) {
158+
throw new TaggedIOException(e, this);
159+
}
160+
}
161+
162+
@Override
163+
public void close() throws IOException {
164+
try {
165+
super.close();
166+
} catch (IOException e) {
167+
throw new TaggedIOException(e, this);
168+
}
169+
}
170+
171+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
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.OutputStream;
21+
22+
import org.apache.commons.io.TaggedIOException;
23+
24+
/**
25+
* An output stream decorator that tags potential exceptions so that the
26+
* stream that caused the exception can easily be identified. This is
27+
* done by using the {@link TaggedIOException} class to wrap all thrown
28+
* {@link IOException}s. See below for an example of using this class.
29+
* <pre>
30+
* TaggedOutputStream stream = new TaggedOutputStream(...);
31+
* try {
32+
* // Processing that may throw an IOException either from this stream
33+
* // or from some other IO activity like temporary files, etc.
34+
* writeToStream(stream);
35+
* } catch (IOException e) {
36+
* if (stream.isCauseOf(e)) {
37+
* // The exception was caused by this stream.
38+
* // Use e.getCause() to get the original exception.
39+
* } else {
40+
* // The exception was caused by something else.
41+
* }
42+
* }
43+
* </pre>
44+
* <p>
45+
* Alternatively, the {@link #throwIfCauseOf(Exception)} method can be
46+
* used to let higher levels of code handle the exception caused by this
47+
* stream while other processing errors are being taken care of at this
48+
* lower level.
49+
* <pre>
50+
* TaggedOutputStream stream = new TaggedOutputStream(...);
51+
* try {
52+
* writeToStream(stream);
53+
* } catch (IOException e) {
54+
* stream.throwIfCauseOf(e);
55+
* // ... or process the exception that was caused by something else
56+
* }
57+
* </pre>
58+
*
59+
* @see TaggedIOException
60+
* @since Commons IO 1.5
61+
*/
62+
public class TaggedOutputStream extends ProxyOutputStream {
63+
64+
/**
65+
* Creates a tagging decorator for the given output stream.
66+
*
67+
* @param proxy output stream to be decorated
68+
*/
69+
public TaggedOutputStream(OutputStream proxy) {
70+
super(proxy);
71+
}
72+
73+
/**
74+
* Tests if the given exception was caused by this stream.
75+
*
76+
* @param exception an exception
77+
* @return <code>true</code> if the exception was thrown by this stream,
78+
* <code>false</code> otherwise
79+
*/
80+
public boolean isCauseOf(IOException exception) {
81+
if (exception instanceof TaggedIOException) {
82+
TaggedIOException tagged = (TaggedIOException) exception;
83+
return this == tagged.getTag();
84+
} else {
85+
return false;
86+
}
87+
}
88+
89+
/**
90+
* Re-throws the original exception thrown by this stream. This method
91+
* first checks whether the given exception is a {@link TaggedIOException}
92+
* wrapper created by this decorator, and then unwraps and throws the
93+
* original wrapped exception. Returns normally if the exception was
94+
* not thrown by this stream.
95+
*
96+
* @param exception an exception
97+
* @throws IOException original exception, if any, thrown by this stream
98+
*/
99+
public void throwIfCauseOf(Exception exception) throws IOException {
100+
if (exception instanceof TaggedIOException) {
101+
TaggedIOException tagged = (TaggedIOException) exception;
102+
if (this == tagged.getTag()) {
103+
throw tagged.getCause();
104+
}
105+
}
106+
}
107+
108+
@Override
109+
public void write(byte[] bts, int st, int end) throws IOException {
110+
try {
111+
super.write(bts, st, end);
112+
} catch (IOException e) {
113+
throw new TaggedIOException(e, this);
114+
}
115+
}
116+
117+
@Override
118+
public void write(byte[] bts) throws IOException {
119+
try {
120+
super.write(bts);
121+
} catch (IOException e) {
122+
throw new TaggedIOException(e, this);
123+
}
124+
}
125+
126+
@Override
127+
public void write(int idx) throws IOException {
128+
try {
129+
super.write(idx);
130+
} catch (IOException e) {
131+
throw new TaggedIOException(e, this);
132+
}
133+
}
134+
135+
@Override
136+
public void flush() throws IOException {
137+
try {
138+
super.flush();
139+
} catch (IOException e) {
140+
throw new TaggedIOException(e, this);
141+
}
142+
}
143+
144+
@Override
145+
public void close() throws IOException {
146+
try {
147+
super.close();
148+
} catch (IOException e) {
149+
throw new TaggedIOException(e, this);
150+
}
151+
}
152+
153+
}

src/test/org/apache/commons/io/PackageTestSuite.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public static Test suite() {
5757
suite.addTest(new TestSuite(IOUtilsWriteTestCase.class));
5858
suite.addTest(new TestSuite(LineIteratorTestCase.class));
5959
suite.addTest(new TestSuite(FileUtilsWaitForTestCase.class));
60+
suite.addTest(new TestSuite(TaggedIOExceptionTest.class));
6061
return suite;
6162
}
6263
}

0 commit comments

Comments
 (0)