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.tika.io; 18 19 import java.io.IOException; 20 import java.io.InputStream; 21 22 /** 23 * An input stream decorator that tags potential exceptions so that the 24 * stream that caused the exception can easily be identified. This is 25 * done by using the {@link TaggedIOException} class to wrap all thrown 26 * {@link IOException}s. See below for an example of using this class. 27 * <pre> 28 * TaggedInputStream stream = new TaggedInputStream(...); 29 * try { 30 * // Processing that may throw an IOException either from this stream 31 * // or from some other IO activity like temporary files, etc. 32 * processStream(stream); 33 * } catch (IOException e) { 34 * if (stream.isCauseOf(e)) { 35 * // The exception was caused by this stream. 36 * // Use e.getCause() to get the original exception. 37 * } else { 38 * // The exception was caused by something else. 39 * } 40 * } 41 * </pre> 42 * <p> 43 * Alternatively, the {@link #throwIfCauseOf(Exception)} method can be 44 * used to let higher levels of code handle the exception caused by this 45 * stream while other processing errors are being taken care of at this 46 * lower level. 47 * <pre> 48 * TaggedInputStream stream = new TaggedInputStream(...); 49 * try { 50 * processStream(stream); 51 * } catch (IOException e) { 52 * stream.throwIfCauseOf(e); 53 * // ... or process the exception that was caused by something else 54 * } 55 * </pre> 56 * 57 * @see TaggedIOException 58 */ 59 public class TaggedInputStream extends ProxyInputStream { 60 61 /** 62 * Creates a tagging decorator for the given input stream. 63 * 64 * @param proxy input stream to be decorated 65 */ 66 public TaggedInputStream(InputStream proxy) { 67 super(proxy); 68 } 69 70 /** 71 * Tests if the given exception was caused by this stream. 72 * 73 * @param exception an exception 74 * @return <code>true</code> if the exception was thrown by this stream, 75 * <code>false</code> otherwise 76 */ 77 public boolean isCauseOf(IOException exception) { 78 if (exception instanceof TaggedIOException) { 79 TaggedIOException tagged = (TaggedIOException) exception; 80 return this == tagged.getTag(); 81 } else { 82 return false; 83 } 84 } 85 86 /** 87 * Re-throws the original exception thrown by this stream. This method 88 * first checks whether the given exception is a {@link TaggedIOException} 89 * wrapper created by this decorator, and then unwraps and throws the 90 * original wrapped exception. Returns normally if the exception was 91 * not thrown by this stream. 92 * 93 * @param exception an exception 94 * @throws IOException original exception, if any, thrown by this stream 95 */ 96 public void throwIfCauseOf(Exception exception) throws IOException { 97 if (exception instanceof TaggedIOException) { 98 TaggedIOException tagged = (TaggedIOException) exception; 99 if (this == tagged.getTag()) { 100 throw tagged.getCause(); 101 } 102 } 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, this); 114 } 115 116 }