Skip to content

Commit 2853baa

Browse files
committed
IO-192: Tagged input and output streams
Added static checker methods on TaggedIOException. This simplified the tagged stream classes and should make it easier to reuse just the TaggedIOException class. Made the tag object Serializable. Switched to using a unique id (UUID) object per tagged stream instead of the stream instance as the tag that binds thrown exceptions to the tagged stream. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/io/trunk@803310 13f79535-47bb-0310-9956-ffa450edef68
1 parent d3d266a commit 2853baa

6 files changed

Lines changed: 118 additions & 49 deletions

File tree

src/java/org/apache/commons/io/TaggedIOException.java

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,38 +17,104 @@
1717
package org.apache.commons.io;
1818

1919
import java.io.IOException;
20+
import java.io.Serializable;
2021

2122
/**
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.
23+
* An {@link IOException} decorator that adds a serializable tag to the
24+
* wrapped exception. Both the tag and the original exception can be used
25+
* to determine further processing when this exception is caught.
2526
*
26-
* @since Commons IO 1.5
27+
* @since Commons IO 2.0
2728
*/
2829
public class TaggedIOException extends IOExceptionWithCause {
2930

3031
/**
31-
* The object reference used to tag the exception.
32+
* Generated serial version UID.
3233
*/
33-
private final Object tag;
34+
private static final long serialVersionUID = -6994123481142850163L;
35+
36+
/**
37+
* Checks whether the given throwable is tagged with the given tag.
38+
* <p>
39+
* This check can only succeed if the throwable is a
40+
* {@link TaggedIOException} and the tag is {@link Serializable}, but
41+
* the argument types are intentionally more generic to make it easier
42+
* to use this method without type casts.
43+
* <p>
44+
* A typical use for this method is in a <code>catch</code> block to
45+
* determine how a caught exception should be handled:
46+
* <pre>
47+
* Serializable tag = ...;
48+
* try {
49+
* ...;
50+
* } catch (Throwable t) {
51+
* if (TaggedIOExcepton.isTaggedWith(t, tag)) {
52+
* // special processing for tagged exception
53+
* } else {
54+
* // handling of other kinds of exceptions
55+
* }
56+
* }
57+
* </pre>
58+
*
59+
* @param tag tag object
60+
*/
61+
public static boolean isTaggedWith(Throwable throwable, Object tag) {
62+
return tag != null
63+
&& throwable instanceof TaggedIOException
64+
&& tag.equals(((TaggedIOException) throwable).tag);
65+
}
66+
67+
/**
68+
* Throws the original {@link IOException} if the given throwable is
69+
* a {@link TaggedIOException} decorator the given tag. Does nothing
70+
* if the given throwable is of a different type or if it is tagged
71+
* with some other tag.
72+
* <p>
73+
* This method is typically used in a <code>catch</code> block to
74+
* selectively rethrow tagged exceptions.
75+
* <pre>
76+
* Serializable tag = ...;
77+
* try {
78+
* ...;
79+
* } catch (Throwable t) {
80+
* TaggedIOExcepton.throwCauseIfTagged(t, tag);
81+
* // handle other kinds of exceptions
82+
* }
83+
* </pre>
84+
*
85+
* @param throwable an exception
86+
* @param tag tag object
87+
* @throws IOException original exception from the tagged decorator, if any
88+
*/
89+
public static void throwCauseIfTaggedWith(Throwable throwable, Object tag)
90+
throws IOException {
91+
if (isTaggedWith(throwable, tag)) {
92+
throw ((TaggedIOException) throwable).getCause();
93+
}
94+
}
95+
96+
/**
97+
* The tag of this exception.
98+
*/
99+
private final Serializable tag;
34100

35101
/**
36102
* Creates a tagged wrapper for the given exception.
37103
*
38104
* @param original the exception to be tagged
39-
* @param tag tag object
105+
* @param tag tag of this exception
40106
*/
41-
public TaggedIOException(IOException original, Object tag) {
107+
public TaggedIOException(IOException original, Serializable tag) {
42108
super(original.getMessage(), original);
43109
this.tag = tag;
44110
}
45111

46112
/**
47-
* Returns the object reference used as the tag this exception.
113+
* Returns the serializable tag object.
48114
*
49115
* @return tag object
50116
*/
51-
public Object getTag() {
117+
public Serializable getTag() {
52118
return tag;
53119
}
54120

src/java/org/apache/commons/io/input/TaggedInputStream.java

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.io.IOException;
2020
import java.io.InputStream;
21+
import java.io.Serializable;
22+
import java.util.UUID;
2123

2224
import org.apache.commons.io.TaggedIOException;
2325

@@ -57,10 +59,15 @@
5759
* </pre>
5860
*
5961
* @see TaggedIOException
60-
* @since Commons IO 1.5
62+
* @since Commons IO 2.0
6163
*/
6264
public class TaggedInputStream extends ProxyInputStream {
6365

66+
/**
67+
* The unique tag associated with exceptions from stream.
68+
*/
69+
private final Serializable tag = UUID.randomUUID();
70+
6471
/**
6572
* Creates a tagging decorator for the given input stream.
6673
*
@@ -73,17 +80,12 @@ public TaggedInputStream(InputStream proxy) {
7380
/**
7481
* Tests if the given exception was caused by this stream.
7582
*
76-
* @param exception an exception
83+
* @param throwable an exception
7784
* @return <code>true</code> if the exception was thrown by this stream,
7885
* <code>false</code> otherwise
7986
*/
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+
public boolean isCauseOf(Throwable exception) {
88+
return TaggedIOException.isTaggedWith(exception, tag);
8789
}
8890

8991
/**
@@ -93,16 +95,11 @@ public boolean isCauseOf(IOException exception) {
9395
* original wrapped exception. Returns normally if the exception was
9496
* not thrown by this stream.
9597
*
96-
* @param exception an exception
98+
* @param throwable an exception
9799
* @throws IOException original exception, if any, thrown by this stream
98100
*/
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-
}
101+
public void throwIfCauseOf(Throwable throwable) throws IOException {
102+
TaggedIOException.throwCauseIfTaggedWith(throwable, tag);
106103
}
107104

108105
/**
@@ -113,7 +110,7 @@ public void throwIfCauseOf(Exception exception) throws IOException {
113110
*/
114111
@Override
115112
protected void handleIOException(IOException e) throws IOException {
116-
throw new TaggedIOException(e, this);
113+
throw new TaggedIOException(e, tag);
117114
}
118115

119116
}

src/java/org/apache/commons/io/output/TaggedOutputStream.java

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import java.io.IOException;
2020
import java.io.OutputStream;
21+
import java.io.Serializable;
22+
import java.util.UUID;
2123

2224
import org.apache.commons.io.TaggedIOException;
2325

@@ -57,10 +59,15 @@
5759
* </pre>
5860
*
5961
* @see TaggedIOException
60-
* @since Commons IO 1.5
62+
* @since Commons IO 2.0
6163
*/
6264
public class TaggedOutputStream extends ProxyOutputStream {
6365

66+
/**
67+
* The unique tag associated with exceptions from stream.
68+
*/
69+
private final Serializable tag = UUID.randomUUID();
70+
6471
/**
6572
* Creates a tagging decorator for the given output stream.
6673
*
@@ -77,13 +84,8 @@ public TaggedOutputStream(OutputStream proxy) {
7784
* @return <code>true</code> if the exception was thrown by this stream,
7885
* <code>false</code> otherwise
7986
*/
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+
public boolean isCauseOf(Exception exception) {
88+
return TaggedIOException.isTaggedWith(exception, tag);
8789
}
8890

8991
/**
@@ -97,12 +99,7 @@ public boolean isCauseOf(IOException exception) {
9799
* @throws IOException original exception, if any, thrown by this stream
98100
*/
99101
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-
}
102+
TaggedIOException.throwCauseIfTaggedWith(exception, tag);
106103
}
107104

108105
/**
@@ -113,7 +110,7 @@ public void throwIfCauseOf(Exception exception) throws IOException {
113110
*/
114111
@Override
115112
protected void handleIOException(IOException e) throws IOException {
116-
throw new TaggedIOException(e, this);
113+
throw new TaggedIOException(e, tag);
117114
}
118115

119116
}

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package org.apache.commons.io;
1818

1919
import java.io.IOException;
20+
import java.io.Serializable;
21+
import java.util.UUID;
2022

2123
import junit.framework.TestCase;
2224

@@ -26,10 +28,11 @@
2628
public class TaggedIOExceptionTest extends TestCase {
2729

2830
public void testTaggedIOException() {
29-
Object tag = new Object();
31+
Serializable tag = UUID.randomUUID();
3032
IOException exception = new IOException("Test exception");
3133
TaggedIOException tagged = new TaggedIOException(exception, tag);
32-
assertEquals(tag, tagged.getTag());
34+
assertTrue(TaggedIOException.isTaggedWith(tagged, tag));
35+
assertFalse(TaggedIOException.isTaggedWith(tagged, UUID.randomUUID()));
3336
assertEquals(exception, tagged.getCause());
3437
assertEquals(exception.getMessage(), tagged.getMessage());
3538
}

src/test/org/apache/commons/io/input/TaggedInputStreamTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.ByteArrayInputStream;
2020
import java.io.IOException;
2121
import java.io.InputStream;
22+
import java.util.UUID;
2223

2324
import org.apache.commons.io.TaggedIOException;
2425

@@ -114,7 +115,8 @@ public void testOtherException() {
114115
TaggedInputStream stream = new TaggedInputStream(closed);
115116

116117
assertFalse(stream.isCauseOf(exception));
117-
assertFalse(stream.isCauseOf(new TaggedIOException(exception, closed)));
118+
assertFalse(stream.isCauseOf(
119+
new TaggedIOException(exception, UUID.randomUUID())));
118120

119121
try {
120122
stream.throwIfCauseOf(exception);
@@ -123,7 +125,8 @@ public void testOtherException() {
123125
}
124126

125127
try {
126-
stream.throwIfCauseOf(new TaggedIOException(exception, closed));
128+
stream.throwIfCauseOf(
129+
new TaggedIOException(exception, UUID.randomUUID()));
127130
} catch (IOException e) {
128131
fail("Unexpected exception thrown");
129132
}

src/test/org/apache/commons/io/output/TaggedOutputStreamTest.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.io.IOException;
2020
import java.io.OutputStream;
21+
import java.util.UUID;
2122

2223
import org.apache.commons.io.TaggedIOException;
2324

@@ -100,7 +101,8 @@ public void testOtherException() {
100101
TaggedOutputStream stream = new TaggedOutputStream(closed);
101102

102103
assertFalse(stream.isCauseOf(exception));
103-
assertFalse(stream.isCauseOf(new TaggedIOException(exception, closed)));
104+
assertFalse(stream.isCauseOf(
105+
new TaggedIOException(exception, UUID.randomUUID())));
104106

105107
try {
106108
stream.throwIfCauseOf(exception);
@@ -109,7 +111,8 @@ public void testOtherException() {
109111
}
110112

111113
try {
112-
stream.throwIfCauseOf(new TaggedIOException(exception, closed));
114+
stream.throwIfCauseOf(
115+
new TaggedIOException(exception, UUID.randomUUID()));
113116
} catch (IOException e) {
114117
fail("Unexpected exception thrown");
115118
}

0 commit comments

Comments
 (0)