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 import java.io.Serializable;
21
22 /**
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.
26 *
27 * @since 2.0
28 */
29 @SuppressWarnings("deprecation") // needs to extend deprecated IOExceptionWithCause to preserve binary compatibility
30 public class TaggedIOException extends IOExceptionWithCause {
31
32 /**
33 * Generated serial version UID.
34 */
35 private static final long serialVersionUID = -6994123481142850163L;
36
37 /**
38 * Checks whether the given throwable is tagged with the given tag.
39 * <p>
40 * This check can only succeed if the throwable is a
41 * {@link TaggedIOException} and the tag is {@link Serializable}, but
42 * the argument types are intentionally more generic to make it easier
43 * to use this method without type casts.
44 * <p>
45 * A typical use for this method is in a {@code catch} block to
46 * determine how a caught exception should be handled:
47 * <pre>
48 * Serializable tag = ...;
49 * try {
50 * ...;
51 * } catch (Throwable t) {
52 * if (TaggedIOException.isTaggedWith(t, tag)) {
53 * // special processing for tagged exception
54 * } else {
55 * // handling of other kinds of exceptions
56 * }
57 * }
58 * </pre>
59 *
60 * @param throwable The Throwable object to check
61 * @param tag tag object
62 * @return {@code true} if the throwable has the specified tag,
63 * otherwise {@code false}
64 */
65 public static boolean isTaggedWith(final Throwable throwable, final Object tag) {
66 return tag != null
67 && throwable instanceof TaggedIOException
68 && tag.equals(((TaggedIOException) throwable).tag);
69 }
70
71 /**
72 * Throws the original {@link IOException} if the given throwable is
73 * a {@link TaggedIOException} decorator the given tag. Does nothing
74 * if the given throwable is of a different type or if it is tagged
75 * with some other tag.
76 * <p>
77 * This method is typically used in a {@code catch} block to
78 * selectively rethrow tagged exceptions.
79 * <pre>
80 * Serializable tag = ...;
81 * try {
82 * ...;
83 * } catch (Throwable t) {
84 * TaggedIOException.throwCauseIfTagged(t, tag);
85 * // handle other kinds of exceptions
86 * }
87 * </pre>
88 *
89 * @param throwable an exception
90 * @param tag tag object
91 * @throws IOException original exception from the tagged decorator, if any
92 */
93 public static void throwCauseIfTaggedWith(final Throwable throwable, final Object tag)
94 throws IOException {
95 if (isTaggedWith(throwable, tag)) {
96 throw ((TaggedIOException) throwable).getCause();
97 }
98 }
99
100 /**
101 * The tag of this exception.
102 */
103 private final Serializable tag;
104
105 /**
106 * Constructs a tagged wrapper for the given exception.
107 *
108 * @param original the exception to be tagged
109 * @param tag tag of this exception
110 */
111 public TaggedIOException(final IOException original, final Serializable tag) {
112 super(original.getMessage(), original);
113 this.tag = tag;
114 }
115
116 /**
117 * Returns the wrapped exception. The only difference to the overridden
118 * {@link Throwable#getCause()} method is the narrower return type.
119 *
120 * @return wrapped exception
121 */
122 @Override
123 public synchronized IOException getCause() {
124 return (IOException) super.getCause();
125 }
126
127 /**
128 * Returns the serializable tag object.
129 *
130 * @return tag object
131 */
132 public Serializable getTag() {
133 return tag;
134 }
135
136 }