001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.io;
018
019 import java.io.IOException;
020 import java.io.Serializable;
021
022 /**
023 * An {@link IOException} decorator that adds a serializable tag to the
024 * wrapped exception. Both the tag and the original exception can be used
025 * to determine further processing when this exception is caught.
026 *
027 * @since Commons IO 2.0
028 */
029 public class TaggedIOException extends IOExceptionWithCause {
030
031 /**
032 * Generated serial version UID.
033 */
034 private static final long serialVersionUID = -6994123481142850163L;
035
036 /**
037 * Checks whether the given throwable is tagged with the given tag.
038 * <p>
039 * This check can only succeed if the throwable is a
040 * {@link TaggedIOException} and the tag is {@link Serializable}, but
041 * the argument types are intentionally more generic to make it easier
042 * to use this method without type casts.
043 * <p>
044 * A typical use for this method is in a <code>catch</code> block to
045 * determine how a caught exception should be handled:
046 * <pre>
047 * Serializable tag = ...;
048 * try {
049 * ...;
050 * } catch (Throwable t) {
051 * if (TaggedIOExcepton.isTaggedWith(t, tag)) {
052 * // special processing for tagged exception
053 * } else {
054 * // handling of other kinds of exceptions
055 * }
056 * }
057 * </pre>
058 *
059 * @param throwable The Throwable object to check
060 * @param tag tag object
061 * @return <code>true</code> if the throwable has the specified tag,
062 * otherwise <code>false</code>
063 */
064 public static boolean isTaggedWith(Throwable throwable, Object tag) {
065 return tag != null
066 && throwable instanceof TaggedIOException
067 && tag.equals(((TaggedIOException) throwable).tag);
068 }
069
070 /**
071 * Throws the original {@link IOException} if the given throwable is
072 * a {@link TaggedIOException} decorator the given tag. Does nothing
073 * if the given throwable is of a different type or if it is tagged
074 * with some other tag.
075 * <p>
076 * This method is typically used in a <code>catch</code> block to
077 * selectively rethrow tagged exceptions.
078 * <pre>
079 * Serializable tag = ...;
080 * try {
081 * ...;
082 * } catch (Throwable t) {
083 * TaggedIOExcepton.throwCauseIfTagged(t, tag);
084 * // handle other kinds of exceptions
085 * }
086 * </pre>
087 *
088 * @param throwable an exception
089 * @param tag tag object
090 * @throws IOException original exception from the tagged decorator, if any
091 */
092 public static void throwCauseIfTaggedWith(Throwable throwable, Object tag)
093 throws IOException {
094 if (isTaggedWith(throwable, tag)) {
095 throw ((TaggedIOException) throwable).getCause();
096 }
097 }
098
099 /**
100 * The tag of this exception.
101 */
102 private final Serializable tag;
103
104 /**
105 * Creates a tagged wrapper for the given exception.
106 *
107 * @param original the exception to be tagged
108 * @param tag tag of this exception
109 */
110 public TaggedIOException(IOException original, Serializable tag) {
111 super(original.getMessage(), original);
112 this.tag = tag;
113 }
114
115 /**
116 * Returns the serializable tag object.
117 *
118 * @return tag object
119 */
120 public Serializable getTag() {
121 return tag;
122 }
123
124 /**
125 * Returns the wrapped exception. The only difference to the overridden
126 * {@link Throwable#getCause()} method is the narrower return type.
127 *
128 * @return wrapped exception
129 */
130 @Override
131 public IOException getCause() {
132 return (IOException) super.getCause();
133 }
134
135 }