    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    }