View Javadoc
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 }