    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.input;
    018
    019    import java.io.IOException;
    020    import java.io.InputStream;
    021    import java.io.Serializable;
    022    import java.util.UUID;
    023
    024    import org.apache.commons.io.TaggedIOException;
    025
    026    /**
    027     * An input stream decorator that tags potential exceptions so that the
    028     * stream that caused the exception can easily be identified. This is
    029     * done by using the {@link TaggedIOException} class to wrap all thrown
    030     * {@link IOException}s. See below for an example of using this class.
    031     * <pre>
    032     * TaggedInputStream stream = new TaggedInputStream(...);
    033     * try {
    034     *     // Processing that may throw an IOException either from this stream
    035     *     // or from some other IO activity like temporary files, etc.
    036     *     processStream(stream);
    037     * } catch (IOException e) {
    038     *     if (stream.isCauseOf(e)) {
    039     *         // The exception was caused by this stream.
    040     *         // Use e.getCause() to get the original exception.
    041     *     } else {
    042     *         // The exception was caused by something else.
    043     *     }
    044     * }
    045     * </pre>
    046     * <p>
    047     * Alternatively, the {@link #throwIfCauseOf(Throwable)} method can be
    048     * used to let higher levels of code handle the exception caused by this
    049     * stream while other processing errors are being taken care of at this
    050     * lower level.
    051     * <pre>
    052     * TaggedInputStream stream = new TaggedInputStream(...);
    053     * try {
    054     *     processStream(stream);
    055     * } catch (IOException e) {
    056     *     stream.throwIfCauseOf(e);
    057     *     // ... or process the exception that was caused by something else
    058     * }
    059     * </pre>
    060     *
    061     * @see TaggedIOException
    062     * @since Commons IO 2.0
    063     */
    064    public class TaggedInputStream extends ProxyInputStream {
    065
    066        /**
    067         * The unique tag associated with exceptions from stream.
    068         */
    069        private final Serializable tag = UUID.randomUUID();
    070
    071        /**
    072         * Creates a tagging decorator for the given input stream.
    073         *
    074         * @param proxy input stream to be decorated
    075         */
    076        public TaggedInputStream(InputStream proxy) {
    077            super(proxy);
    078        }
    079
    080        /**
    081         * Tests if the given exception was caused by this stream.
    082         *
    083         * @param exception an exception
    084         * @return <code>true</code> if the exception was thrown by this stream,
    085         *         <code>false</code> otherwise
    086         */
    087        public boolean isCauseOf(Throwable exception) {
    088            return TaggedIOException.isTaggedWith(exception, tag);
    089        }
    090
    091        /**
    092         * Re-throws the original exception thrown by this stream. This method
    093         * first checks whether the given exception is a {@link TaggedIOException}
    094         * wrapper created by this decorator, and then unwraps and throws the
    095         * original wrapped exception. Returns normally if the exception was
    096         * not thrown by this stream.
    097         *
    098         * @param throwable an exception
    099         * @throws IOException original exception, if any, thrown by this stream
    100         */
    101        public void throwIfCauseOf(Throwable throwable) throws IOException {
    102            TaggedIOException.throwCauseIfTaggedWith(throwable, tag);
    103        }
    104
    105        /**
    106         * Tags any IOExceptions thrown, wrapping and re-throwing.
    107         *
    108         * @param e The IOException thrown
    109         * @throws IOException if an I/O error occurs
    110         */
    111        @Override
    112        protected void handleIOException(IOException e) throws IOException {
    113            throw new TaggedIOException(e, tag);
    114        }
    115
    116    }