17dd252788645e940eada959bdde927426e2531c9Paul Duffin/* 27dd252788645e940eada959bdde927426e2531c9Paul Duffin * Copyright (C) 2012 The Guava Authors 37dd252788645e940eada959bdde927426e2531c9Paul Duffin * 47dd252788645e940eada959bdde927426e2531c9Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License"); 57dd252788645e940eada959bdde927426e2531c9Paul Duffin * you may not use this file except in compliance with the License. 67dd252788645e940eada959bdde927426e2531c9Paul Duffin * You may obtain a copy of the License at 77dd252788645e940eada959bdde927426e2531c9Paul Duffin * 87dd252788645e940eada959bdde927426e2531c9Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0 97dd252788645e940eada959bdde927426e2531c9Paul Duffin * 107dd252788645e940eada959bdde927426e2531c9Paul Duffin * Unless required by applicable law or agreed to in writing, software 117dd252788645e940eada959bdde927426e2531c9Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS, 127dd252788645e940eada959bdde927426e2531c9Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137dd252788645e940eada959bdde927426e2531c9Paul Duffin * See the License for the specific language governing permissions and 147dd252788645e940eada959bdde927426e2531c9Paul Duffin * limitations under the License. 157dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 167dd252788645e940eada959bdde927426e2531c9Paul Duffin 177dd252788645e940eada959bdde927426e2531c9Paul Duffinpackage com.google.common.io; 187dd252788645e940eada959bdde927426e2531c9Paul Duffin 197dd252788645e940eada959bdde927426e2531c9Paul Duffinimport static com.google.common.base.Preconditions.checkNotNull; 207dd252788645e940eada959bdde927426e2531c9Paul Duffin 217dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.annotations.Beta; 227dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.annotations.VisibleForTesting; 237dd252788645e940eada959bdde927426e2531c9Paul Duffinimport com.google.common.base.Throwables; 247dd252788645e940eada959bdde927426e2531c9Paul Duffin 257dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.io.Closeable; 267dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.io.IOException; 277dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.lang.reflect.Method; 287dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.LinkedList; 297dd252788645e940eada959bdde927426e2531c9Paul Duffinimport java.util.logging.Level; 307dd252788645e940eada959bdde927426e2531c9Paul Duffin 310888a09821a98ac0680fad765217302858e70fa4Paul Duffinimport javax.annotation.Nullable; 320888a09821a98ac0680fad765217302858e70fa4Paul Duffin 337dd252788645e940eada959bdde927426e2531c9Paul Duffin/** 347dd252788645e940eada959bdde927426e2531c9Paul Duffin * A {@link Closeable} that collects {@code Closeable} resources and closes them all when it is 357dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@linkplain #close closed}. This is intended to approximately emulate the behavior of Java 7's 367dd252788645e940eada959bdde927426e2531c9Paul Duffin * <a href="http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html"> 377dd252788645e940eada959bdde927426e2531c9Paul Duffin * try-with-resources</a> statement in JDK6-compatible code. Running on Java 7, code using this 387dd252788645e940eada959bdde927426e2531c9Paul Duffin * should be approximately equivalent in behavior to the same code written with try-with-resources. 397dd252788645e940eada959bdde927426e2531c9Paul Duffin * Running on Java 6, exceptions that cannot be thrown must be logged rather than being added to the 407dd252788645e940eada959bdde927426e2531c9Paul Duffin * thrown exception as a suppressed exception. 417dd252788645e940eada959bdde927426e2531c9Paul Duffin * 420888a09821a98ac0680fad765217302858e70fa4Paul Duffin * <p>This class is intended to be used in the following pattern: 437dd252788645e940eada959bdde927426e2531c9Paul Duffin * 440888a09821a98ac0680fad765217302858e70fa4Paul Duffin * <pre> {@code 450888a09821a98ac0680fad765217302858e70fa4Paul Duffin * Closer closer = Closer.create(); 460888a09821a98ac0680fad765217302858e70fa4Paul Duffin * try { 470888a09821a98ac0680fad765217302858e70fa4Paul Duffin * InputStream in = closer.register(openInputStream()); 480888a09821a98ac0680fad765217302858e70fa4Paul Duffin * OutputStream out = closer.register(openOutputStream()); 490888a09821a98ac0680fad765217302858e70fa4Paul Duffin * // do stuff 500888a09821a98ac0680fad765217302858e70fa4Paul Duffin * } catch (Throwable e) { 510888a09821a98ac0680fad765217302858e70fa4Paul Duffin * // ensure that any checked exception types other than IOException that could be thrown are 520888a09821a98ac0680fad765217302858e70fa4Paul Duffin * // provided here, e.g. throw closer.rethrow(e, CheckedException.class); 530888a09821a98ac0680fad765217302858e70fa4Paul Duffin * throw closer.rethrow(e); 540888a09821a98ac0680fad765217302858e70fa4Paul Duffin * } finally { 550888a09821a98ac0680fad765217302858e70fa4Paul Duffin * closer.close(); 560888a09821a98ac0680fad765217302858e70fa4Paul Duffin * }}</pre> 577dd252788645e940eada959bdde927426e2531c9Paul Duffin * 587dd252788645e940eada959bdde927426e2531c9Paul Duffin * <p>Note that this try-catch-finally block is not equivalent to a try-catch-finally block using 597dd252788645e940eada959bdde927426e2531c9Paul Duffin * try-with-resources. To get the equivalent of that, you must wrap the above code in <i>another</i> 607dd252788645e940eada959bdde927426e2531c9Paul Duffin * try block in order to catch any exception that may be thrown (including from the call to 617dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@code close()}). 627dd252788645e940eada959bdde927426e2531c9Paul Duffin * 637dd252788645e940eada959bdde927426e2531c9Paul Duffin * <p>This pattern ensures the following: 640888a09821a98ac0680fad765217302858e70fa4Paul Duffin * 657dd252788645e940eada959bdde927426e2531c9Paul Duffin * <ul> 667dd252788645e940eada959bdde927426e2531c9Paul Duffin * <li>Each {@code Closeable} resource that is successfully registered will be closed later.</li> 677dd252788645e940eada959bdde927426e2531c9Paul Duffin * <li>If a {@code Throwable} is thrown in the try block, no exceptions that occur when attempting 687dd252788645e940eada959bdde927426e2531c9Paul Duffin * to close resources will be thrown from the finally block. The throwable from the try block will 697dd252788645e940eada959bdde927426e2531c9Paul Duffin * be thrown.</li> 707dd252788645e940eada959bdde927426e2531c9Paul Duffin * <li>If no exceptions or errors were thrown in the try block, the <i>first</i> exception thrown 717dd252788645e940eada959bdde927426e2531c9Paul Duffin * by an attempt to close a resource will be thrown.</li> 727dd252788645e940eada959bdde927426e2531c9Paul Duffin * <li>Any exception caught when attempting to close a resource that is <i>not</i> thrown 737dd252788645e940eada959bdde927426e2531c9Paul Duffin * (because another exception is already being thrown) is <i>suppressed</i>.</li> 747dd252788645e940eada959bdde927426e2531c9Paul Duffin * </ul> 757dd252788645e940eada959bdde927426e2531c9Paul Duffin * 760888a09821a98ac0680fad765217302858e70fa4Paul Duffin * <p>An exception that is suppressed is not thrown. The method of suppression used depends on the 777dd252788645e940eada959bdde927426e2531c9Paul Duffin * version of Java the code is running on: 787dd252788645e940eada959bdde927426e2531c9Paul Duffin * 797dd252788645e940eada959bdde927426e2531c9Paul Duffin * <ul> 807dd252788645e940eada959bdde927426e2531c9Paul Duffin * <li><b>Java 7+:</b> Exceptions are suppressed by adding them to the exception that <i>will</i> 817dd252788645e940eada959bdde927426e2531c9Paul Duffin * be thrown using {@code Throwable.addSuppressed(Throwable)}.</li> 827dd252788645e940eada959bdde927426e2531c9Paul Duffin * <li><b>Java 6:</b> Exceptions are suppressed by logging them instead.</li> 837dd252788645e940eada959bdde927426e2531c9Paul Duffin * </ul> 847dd252788645e940eada959bdde927426e2531c9Paul Duffin * 857dd252788645e940eada959bdde927426e2531c9Paul Duffin * @author Colin Decker 867dd252788645e940eada959bdde927426e2531c9Paul Duffin * @since 14.0 877dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 887dd252788645e940eada959bdde927426e2531c9Paul Duffin// Coffee's for {@link Closer closers} only. 897dd252788645e940eada959bdde927426e2531c9Paul Duffin@Beta 907dd252788645e940eada959bdde927426e2531c9Paul Duffinpublic final class Closer implements Closeable { 917dd252788645e940eada959bdde927426e2531c9Paul Duffin 927dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 937dd252788645e940eada959bdde927426e2531c9Paul Duffin * The suppressor implementation to use for the current Java version. 947dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 950888a09821a98ac0680fad765217302858e70fa4Paul Duffin private static final Suppressor SUPPRESSOR = SuppressingSuppressor.isAvailable() 960888a09821a98ac0680fad765217302858e70fa4Paul Duffin ? SuppressingSuppressor.INSTANCE 977dd252788645e940eada959bdde927426e2531c9Paul Duffin : LoggingSuppressor.INSTANCE; 987dd252788645e940eada959bdde927426e2531c9Paul Duffin 997dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 1007dd252788645e940eada959bdde927426e2531c9Paul Duffin * Creates a new {@link Closer}. 1017dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 1027dd252788645e940eada959bdde927426e2531c9Paul Duffin public static Closer create() { 1037dd252788645e940eada959bdde927426e2531c9Paul Duffin return new Closer(SUPPRESSOR); 1047dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1057dd252788645e940eada959bdde927426e2531c9Paul Duffin 1060888a09821a98ac0680fad765217302858e70fa4Paul Duffin @VisibleForTesting final Suppressor suppressor; 1077dd252788645e940eada959bdde927426e2531c9Paul Duffin 1087dd252788645e940eada959bdde927426e2531c9Paul Duffin // only need space for 2 elements in most cases, so try to use the smallest array possible 1097dd252788645e940eada959bdde927426e2531c9Paul Duffin private final LinkedList<Closeable> stack = new LinkedList<Closeable>(); 1107dd252788645e940eada959bdde927426e2531c9Paul Duffin private Throwable thrown; 1117dd252788645e940eada959bdde927426e2531c9Paul Duffin 1120888a09821a98ac0680fad765217302858e70fa4Paul Duffin @VisibleForTesting Closer(Suppressor suppressor) { 1137dd252788645e940eada959bdde927426e2531c9Paul Duffin this.suppressor = checkNotNull(suppressor); // checkNotNull to satisfy null tests 1147dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1157dd252788645e940eada959bdde927426e2531c9Paul Duffin 1167dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 1177dd252788645e940eada959bdde927426e2531c9Paul Duffin * Registers the given {@code closeable} to be closed when this {@code Closer} is 1187dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@linkplain #close closed}. 1197dd252788645e940eada959bdde927426e2531c9Paul Duffin * 1207dd252788645e940eada959bdde927426e2531c9Paul Duffin * @return the given {@code closeable} 1217dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 1227dd252788645e940eada959bdde927426e2531c9Paul Duffin // close. this word no longer has any meaning to me. 1230888a09821a98ac0680fad765217302858e70fa4Paul Duffin public <C extends Closeable> C register(@Nullable C closeable) { 1240888a09821a98ac0680fad765217302858e70fa4Paul Duffin if (closeable != null) { 1250888a09821a98ac0680fad765217302858e70fa4Paul Duffin stack.addFirst(closeable); 1260888a09821a98ac0680fad765217302858e70fa4Paul Duffin } 1270888a09821a98ac0680fad765217302858e70fa4Paul Duffin 1287dd252788645e940eada959bdde927426e2531c9Paul Duffin return closeable; 1297dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1307dd252788645e940eada959bdde927426e2531c9Paul Duffin 1317dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 1327dd252788645e940eada959bdde927426e2531c9Paul Duffin * Stores the given throwable and rethrows it. It will be rethrown as is if it is an 1337dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@code IOException}, {@code RuntimeException} or {@code Error}. Otherwise, it will be rethrown 1347dd252788645e940eada959bdde927426e2531c9Paul Duffin * wrapped in a {@code RuntimeException}. <b>Note:</b> Be sure to declare all of the checked 1357dd252788645e940eada959bdde927426e2531c9Paul Duffin * exception types your try block can throw when calling an overload of this method so as to avoid 1367dd252788645e940eada959bdde927426e2531c9Paul Duffin * losing the original exception type. 1377dd252788645e940eada959bdde927426e2531c9Paul Duffin * 1387dd252788645e940eada959bdde927426e2531c9Paul Duffin * <p>This method always throws, and as such should be called as 1397dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@code throw closer.rethrow(e);} to ensure the compiler knows that it will throw. 1407dd252788645e940eada959bdde927426e2531c9Paul Duffin * 1417dd252788645e940eada959bdde927426e2531c9Paul Duffin * @return this method does not return; it always throws 1427dd252788645e940eada959bdde927426e2531c9Paul Duffin * @throws IOException when the given throwable is an IOException 1437dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 1447dd252788645e940eada959bdde927426e2531c9Paul Duffin public RuntimeException rethrow(Throwable e) throws IOException { 1450888a09821a98ac0680fad765217302858e70fa4Paul Duffin checkNotNull(e); 1467dd252788645e940eada959bdde927426e2531c9Paul Duffin thrown = e; 1477dd252788645e940eada959bdde927426e2531c9Paul Duffin Throwables.propagateIfPossible(e, IOException.class); 1480888a09821a98ac0680fad765217302858e70fa4Paul Duffin throw new RuntimeException(e); 1497dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1507dd252788645e940eada959bdde927426e2531c9Paul Duffin 1517dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 1527dd252788645e940eada959bdde927426e2531c9Paul Duffin * Stores the given throwable and rethrows it. It will be rethrown as is if it is an 1537dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@code IOException}, {@code RuntimeException}, {@code Error} or a checked exception of the 1547dd252788645e940eada959bdde927426e2531c9Paul Duffin * given type. Otherwise, it will be rethrown wrapped in a {@code RuntimeException}. <b>Note:</b> 1557dd252788645e940eada959bdde927426e2531c9Paul Duffin * Be sure to declare all of the checked exception types your try block can throw when calling an 1567dd252788645e940eada959bdde927426e2531c9Paul Duffin * overload of this method so as to avoid losing the original exception type. 1577dd252788645e940eada959bdde927426e2531c9Paul Duffin * 1587dd252788645e940eada959bdde927426e2531c9Paul Duffin * <p>This method always throws, and as such should be called as 1597dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it will throw. 1607dd252788645e940eada959bdde927426e2531c9Paul Duffin * 1617dd252788645e940eada959bdde927426e2531c9Paul Duffin * @return this method does not return; it always throws 1627dd252788645e940eada959bdde927426e2531c9Paul Duffin * @throws IOException when the given throwable is an IOException 1637dd252788645e940eada959bdde927426e2531c9Paul Duffin * @throws X when the given throwable is of the declared type X 1647dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 1650888a09821a98ac0680fad765217302858e70fa4Paul Duffin public <X extends Exception> RuntimeException rethrow(Throwable e, 1660888a09821a98ac0680fad765217302858e70fa4Paul Duffin Class<X> declaredType) throws IOException, X { 1670888a09821a98ac0680fad765217302858e70fa4Paul Duffin checkNotNull(e); 1687dd252788645e940eada959bdde927426e2531c9Paul Duffin thrown = e; 1697dd252788645e940eada959bdde927426e2531c9Paul Duffin Throwables.propagateIfPossible(e, IOException.class); 1707dd252788645e940eada959bdde927426e2531c9Paul Duffin Throwables.propagateIfPossible(e, declaredType); 1710888a09821a98ac0680fad765217302858e70fa4Paul Duffin throw new RuntimeException(e); 1727dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1737dd252788645e940eada959bdde927426e2531c9Paul Duffin 1747dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 1757dd252788645e940eada959bdde927426e2531c9Paul Duffin * Stores the given throwable and rethrows it. It will be rethrown as is if it is an 1767dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@code IOException}, {@code RuntimeException}, {@code Error} or a checked exception of either 1777dd252788645e940eada959bdde927426e2531c9Paul Duffin * of the given types. Otherwise, it will be rethrown wrapped in a {@code RuntimeException}. 1787dd252788645e940eada959bdde927426e2531c9Paul Duffin * <b>Note:</b> Be sure to declare all of the checked exception types your try block can throw 1797dd252788645e940eada959bdde927426e2531c9Paul Duffin * when calling an overload of this method so as to avoid losing the original exception type. 1807dd252788645e940eada959bdde927426e2531c9Paul Duffin * 1817dd252788645e940eada959bdde927426e2531c9Paul Duffin * <p>This method always throws, and as such should be called as 1827dd252788645e940eada959bdde927426e2531c9Paul Duffin * {@code throw closer.rethrow(e, ...);} to ensure the compiler knows that it will throw. 1837dd252788645e940eada959bdde927426e2531c9Paul Duffin * 1847dd252788645e940eada959bdde927426e2531c9Paul Duffin * @return this method does not return; it always throws 1857dd252788645e940eada959bdde927426e2531c9Paul Duffin * @throws IOException when the given throwable is an IOException 1867dd252788645e940eada959bdde927426e2531c9Paul Duffin * @throws X1 when the given throwable is of the declared type X1 1877dd252788645e940eada959bdde927426e2531c9Paul Duffin * @throws X2 when the given throwable is of the declared type X2 1887dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 1897dd252788645e940eada959bdde927426e2531c9Paul Duffin public <X1 extends Exception, X2 extends Exception> RuntimeException rethrow( 1907dd252788645e940eada959bdde927426e2531c9Paul Duffin Throwable e, Class<X1> declaredType1, Class<X2> declaredType2) throws IOException, X1, X2 { 1910888a09821a98ac0680fad765217302858e70fa4Paul Duffin checkNotNull(e); 1927dd252788645e940eada959bdde927426e2531c9Paul Duffin thrown = e; 1937dd252788645e940eada959bdde927426e2531c9Paul Duffin Throwables.propagateIfPossible(e, IOException.class); 1947dd252788645e940eada959bdde927426e2531c9Paul Duffin Throwables.propagateIfPossible(e, declaredType1, declaredType2); 1950888a09821a98ac0680fad765217302858e70fa4Paul Duffin throw new RuntimeException(e); 1967dd252788645e940eada959bdde927426e2531c9Paul Duffin } 1977dd252788645e940eada959bdde927426e2531c9Paul Duffin 1987dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 1997dd252788645e940eada959bdde927426e2531c9Paul Duffin * Closes all {@code Closeable} instances that have been added to this {@code Closer}. If an 2007dd252788645e940eada959bdde927426e2531c9Paul Duffin * exception was thrown in the try block and passed to one of the {@code exceptionThrown} methods, 2017dd252788645e940eada959bdde927426e2531c9Paul Duffin * any exceptions thrown when attempting to close a closeable will be suppressed. Otherwise, the 2027dd252788645e940eada959bdde927426e2531c9Paul Duffin * <i>first</i> exception to be thrown from an attempt to close a closeable will be thrown and any 2037dd252788645e940eada959bdde927426e2531c9Paul Duffin * additional exceptions that are thrown after that will be suppressed. 2047dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 2050888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override 2067dd252788645e940eada959bdde927426e2531c9Paul Duffin public void close() throws IOException { 2077dd252788645e940eada959bdde927426e2531c9Paul Duffin Throwable throwable = thrown; 2087dd252788645e940eada959bdde927426e2531c9Paul Duffin 2097dd252788645e940eada959bdde927426e2531c9Paul Duffin // close closeables in LIFO order 2107dd252788645e940eada959bdde927426e2531c9Paul Duffin while (!stack.isEmpty()) { 2117dd252788645e940eada959bdde927426e2531c9Paul Duffin Closeable closeable = stack.removeFirst(); 2127dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 2137dd252788645e940eada959bdde927426e2531c9Paul Duffin closeable.close(); 2147dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (Throwable e) { 2157dd252788645e940eada959bdde927426e2531c9Paul Duffin if (throwable == null) { 2167dd252788645e940eada959bdde927426e2531c9Paul Duffin throwable = e; 2177dd252788645e940eada959bdde927426e2531c9Paul Duffin } else { 2187dd252788645e940eada959bdde927426e2531c9Paul Duffin suppressor.suppress(closeable, throwable, e); 2197dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2207dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2217dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2227dd252788645e940eada959bdde927426e2531c9Paul Duffin 2237dd252788645e940eada959bdde927426e2531c9Paul Duffin if (thrown == null && throwable != null) { 2247dd252788645e940eada959bdde927426e2531c9Paul Duffin Throwables.propagateIfPossible(throwable, IOException.class); 2257dd252788645e940eada959bdde927426e2531c9Paul Duffin throw new AssertionError(throwable); // not possible 2267dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2277dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2287dd252788645e940eada959bdde927426e2531c9Paul Duffin 2297dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 2307dd252788645e940eada959bdde927426e2531c9Paul Duffin * Suppression strategy interface. 2317dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 2320888a09821a98ac0680fad765217302858e70fa4Paul Duffin @VisibleForTesting interface Suppressor { 2337dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 2347dd252788645e940eada959bdde927426e2531c9Paul Duffin * Suppresses the given exception ({@code suppressed}) which was thrown when attempting to close 2357dd252788645e940eada959bdde927426e2531c9Paul Duffin * the given closeable. {@code thrown} is the exception that is actually being thrown from the 2367dd252788645e940eada959bdde927426e2531c9Paul Duffin * method. Implementations of this method should not throw under any circumstances. 2377dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 2387dd252788645e940eada959bdde927426e2531c9Paul Duffin void suppress(Closeable closeable, Throwable thrown, Throwable suppressed); 2397dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2407dd252788645e940eada959bdde927426e2531c9Paul Duffin 2417dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 2427dd252788645e940eada959bdde927426e2531c9Paul Duffin * Suppresses exceptions by logging them. 2437dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 2440888a09821a98ac0680fad765217302858e70fa4Paul Duffin @VisibleForTesting static final class LoggingSuppressor implements Suppressor { 2457dd252788645e940eada959bdde927426e2531c9Paul Duffin 2467dd252788645e940eada959bdde927426e2531c9Paul Duffin static final LoggingSuppressor INSTANCE = new LoggingSuppressor(); 2477dd252788645e940eada959bdde927426e2531c9Paul Duffin 2480888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override 2497dd252788645e940eada959bdde927426e2531c9Paul Duffin public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) { 2507dd252788645e940eada959bdde927426e2531c9Paul Duffin // log to the same place as Closeables 2517dd252788645e940eada959bdde927426e2531c9Paul Duffin Closeables.logger.log(Level.WARNING, 2527dd252788645e940eada959bdde927426e2531c9Paul Duffin "Suppressing exception thrown when closing " + closeable, suppressed); 2537dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2547dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2557dd252788645e940eada959bdde927426e2531c9Paul Duffin 2567dd252788645e940eada959bdde927426e2531c9Paul Duffin /** 2577dd252788645e940eada959bdde927426e2531c9Paul Duffin * Suppresses exceptions by adding them to the exception that will be thrown using JDK7's 2587dd252788645e940eada959bdde927426e2531c9Paul Duffin * addSuppressed(Throwable) mechanism. 2597dd252788645e940eada959bdde927426e2531c9Paul Duffin */ 2600888a09821a98ac0680fad765217302858e70fa4Paul Duffin @VisibleForTesting static final class SuppressingSuppressor implements Suppressor { 2617dd252788645e940eada959bdde927426e2531c9Paul Duffin 2627dd252788645e940eada959bdde927426e2531c9Paul Duffin static final SuppressingSuppressor INSTANCE = new SuppressingSuppressor(); 2637dd252788645e940eada959bdde927426e2531c9Paul Duffin 2647dd252788645e940eada959bdde927426e2531c9Paul Duffin static boolean isAvailable() { 2657dd252788645e940eada959bdde927426e2531c9Paul Duffin return addSuppressed != null; 2667dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2677dd252788645e940eada959bdde927426e2531c9Paul Duffin 2687dd252788645e940eada959bdde927426e2531c9Paul Duffin static final Method addSuppressed = getAddSuppressed(); 2697dd252788645e940eada959bdde927426e2531c9Paul Duffin 2707dd252788645e940eada959bdde927426e2531c9Paul Duffin private static Method getAddSuppressed() { 2717dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 2727dd252788645e940eada959bdde927426e2531c9Paul Duffin return Throwable.class.getMethod("addSuppressed", Throwable.class); 2737dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (Throwable e) { 2747dd252788645e940eada959bdde927426e2531c9Paul Duffin return null; 2757dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2767dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2777dd252788645e940eada959bdde927426e2531c9Paul Duffin 2780888a09821a98ac0680fad765217302858e70fa4Paul Duffin @Override 2797dd252788645e940eada959bdde927426e2531c9Paul Duffin public void suppress(Closeable closeable, Throwable thrown, Throwable suppressed) { 2807dd252788645e940eada959bdde927426e2531c9Paul Duffin // ensure no exceptions from addSuppressed 2817dd252788645e940eada959bdde927426e2531c9Paul Duffin if (thrown == suppressed) { 2827dd252788645e940eada959bdde927426e2531c9Paul Duffin return; 2837dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2847dd252788645e940eada959bdde927426e2531c9Paul Duffin try { 2857dd252788645e940eada959bdde927426e2531c9Paul Duffin addSuppressed.invoke(thrown, suppressed); 2867dd252788645e940eada959bdde927426e2531c9Paul Duffin } catch (Throwable e) { 2877dd252788645e940eada959bdde927426e2531c9Paul Duffin // if, somehow, IllegalAccessException or another exception is thrown, fall back to logging 2887dd252788645e940eada959bdde927426e2531c9Paul Duffin LoggingSuppressor.INSTANCE.suppress(closeable, thrown, suppressed); 2897dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2907dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2917dd252788645e940eada959bdde927426e2531c9Paul Duffin } 2927dd252788645e940eada959bdde927426e2531c9Paul Duffin} 293