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 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} if the throwable has the specified tag, 062 * otherwise {@code false} 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 }