diff --git a/community/io/src/main/java/org/neo4j/io/IOUtils.java b/community/io/src/main/java/org/neo4j/io/IOUtils.java index d10ffe4362a1..b0a1a45ccb30 100644 --- a/community/io/src/main/java/org/neo4j/io/IOUtils.java +++ b/community/io/src/main/java/org/neo4j/io/IOUtils.java @@ -21,10 +21,8 @@ import java.io.IOException; import java.io.UncheckedIOException; -import java.lang.reflect.Constructor; import java.util.Collection; - -import org.neo4j.helpers.Exceptions; +import java.util.function.BiFunction; /** * IO helper methods. @@ -40,12 +38,12 @@ private IOUtils() * * @param closeables the closeables to close * @param the type of closeable - * @throws IOException + * @throws IOException if an exception was thrown by one of the close methods. * @see #closeAll(AutoCloseable[]) */ public static void closeAll( Collection closeables ) throws IOException { - closeAll( closeables.toArray( new AutoCloseable[0] ) ); + close( IOException::new, closeables.toArray( new AutoCloseable[0] ) ); } /** @@ -77,13 +75,7 @@ public static void closeAllUnchecked( T... closeables */ public static void closeAllSilently( Collection closeables ) { - try - { - closeAll( closeables ); - } - catch ( IOException ignored ) - { - } + close( ( msg, cause ) -> null, closeables.toArray( new AutoCloseable[0] ) ); } /** @@ -94,12 +86,12 @@ public static void closeAllSilently( Collection clo * * @param closeables the closeables to close * @param the type of closeable - * @throws IOException + * @throws IOException if an exception was thrown by one of the close methods. */ @SafeVarargs public static void closeAll( T... closeables ) throws IOException { - closeAll( IOException.class, closeables ); + close( IOException::new, closeables ); } /** @@ -111,64 +103,66 @@ public static void closeAll( T... closeables ) throws @SafeVarargs public static void closeAllSilently( T... closeables ) { - try - { - closeAll( closeables ); - } - catch ( IOException ignored ) - { - } + close( ( msg, cause ) -> null, closeables ); } /** - * Close all given closeables and if something goes wrong throw exception of the given type. - * Exception class should have a public constructor that accepts {@link String} and {@link Throwable} like - * {@link RuntimeException#RuntimeException(String, Throwable)} + * Close all ofthe given closeables, and if something goes wrong, use the given constructor to create a {@link Throwable} instance with the specific cause + * attached. The remaining closeables will still be closed, in that case, and if they in turn throw any exceptions then these will be attached as + * suppressed exceptions. * - * @param throwableClass exception type to throw in case of failure - * @param closeables the closeables to close - * @param the type of closeable - * @param the type of exception + * @param constructor The function used to construct the parent throwable that will have the first thrown exception attached as a cause, and any + * remaining exceptions attached as suppressed exceptions. If this function returns {@code null}, then the exception is ignored. + * @param closeables an iterator of all the things to close, in order. + * @param the type of things to close. + * @param the type of the parent exception. + * @throws E when any {@link AutoCloseable#close()} throws exception + */ + public static void close( BiFunction constructor, Collection closeables ) throws E + { + close( constructor, closeables.toArray( new AutoCloseable[0] ) ); + } + + /** + * Close all ofthe given closeables, and if something goes wrong, use the given constructor to create a {@link Throwable} instance with the specific cause + * attached. The remaining closeables will still be closed, in that case, and if they in turn throw any exceptions then these will be attached as + * suppressed exceptions. + * + * @param constructor The function used to construct the parent throwable that will have the first thrown exception attached as a cause, and any + * remaining exceptions attached as suppressed exceptions. If this function returns {@code null}, then the exception is ignored. + * @param closeables all the things to close, in order. + * @param the type of things to close. + * @param the type of the parent exception. * @throws E when any {@link AutoCloseable#close()} throws exception */ @SafeVarargs - public static void closeAll( Class throwableClass, - T... closeables ) throws E + public static void close( BiFunction constructor, T... closeables ) throws E { - Throwable closeThrowable = null; + E closeThrowable = null; for ( T closeable : closeables ) { - if ( closeable != null ) + try { - try + if ( closeable != null ) { closeable.close(); } - catch ( Throwable t ) + } + catch ( Exception e ) + { + if ( closeThrowable == null ) + { + closeThrowable = constructor.apply( "Exception closing multiple resources.", e ); + } + else { - closeThrowable = Exceptions.chain( closeThrowable, t ); + closeThrowable.addSuppressed( e ); } } } if ( closeThrowable != null ) { - throw newThrowable( throwableClass, "Exception closing multiple resources", closeThrowable ); - } - } - - private static E newThrowable( Class throwableClass, String message, Throwable cause ) - { - try - { - Constructor constructor = throwableClass.getConstructor( String.class, Throwable.class ); - return constructor.newInstance( message, cause ); - } - catch ( Throwable t ) - { - RuntimeException runtimeException = new RuntimeException( - "Unable to create exception to throw. Original message: " + message, t ); - runtimeException.addSuppressed( cause ); - throw runtimeException; + throw closeThrowable; } } } diff --git a/community/io/src/test/java/org/neo4j/io/IOUtilsTest.java b/community/io/src/test/java/org/neo4j/io/IOUtilsTest.java index f1b739e54752..61860c3c711a 100644 --- a/community/io/src/test/java/org/neo4j/io/IOUtilsTest.java +++ b/community/io/src/test/java/org/neo4j/io/IOUtilsTest.java @@ -68,4 +68,12 @@ public void closeAllAndRethrowException() throws Exception IOUtils.closeAll( goodClosable1, faultyClosable, goodClosable2 ); } + @Test + public void closeMustIgnoreNullResources() throws Exception + { + AutoCloseable a = () -> {}; + AutoCloseable b = null; + AutoCloseable c = () -> {}; + IOUtils.close( IOException::new, a, b, c ); + } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/aux/AuxiliaryTransactionStateCloseException.java b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/aux/AuxiliaryTransactionStateCloseException.java index 6b45f6b48ae6..3b000d48dee5 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/aux/AuxiliaryTransactionStateCloseException.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/txstate/aux/AuxiliaryTransactionStateCloseException.java @@ -21,7 +21,7 @@ public class AuxiliaryTransactionStateCloseException extends RuntimeException { - public AuxiliaryTransactionStateCloseException( String message, Exception cause ) + public AuxiliaryTransactionStateCloseException( String message, Throwable cause ) { super( message, cause ); } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/CloseableResourceManager.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/CloseableResourceManager.java index 04a363e9bc3d..ab761bf0d01e 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/CloseableResourceManager.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/CloseableResourceManager.java @@ -63,7 +63,7 @@ public final void closeAllCloseableResources() Collection resourcesToClose = closeableResources; closeableResources = null; - IOUtils.closeAll( ResourceCloseFailureException.class, resourcesToClose.toArray( new AutoCloseable[0] ) ); + IOUtils.close( ResourceCloseFailureException::new, resourcesToClose.toArray( new AutoCloseable[0] ) ); } } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelAuxTransactionStateManager.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelAuxTransactionStateManager.java index 50109281ecc7..2c0c8f1f94f1 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelAuxTransactionStateManager.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/api/KernelAuxTransactionStateManager.java @@ -36,7 +36,7 @@ public class KernelAuxTransactionStateManager implements AuxiliaryTransactionStateManager { - private volatile CopyOnWriteHashMap providers; + private volatile CopyOnWriteHashMap providers; public KernelAuxTransactionStateManager() { @@ -63,12 +63,12 @@ public AuxiliaryTransactionStateHolder openStateHolder() private static class AuxStateHolder implements AuxiliaryTransactionStateHolder, Function { - private final Map providers; - private final Map openedStates; + private final Map providers; + private final Map openedStates; AuxStateHolder( Map providers ) { - this.providers = providers; + this.providers = providers; openedStates = new HashMap<>(); } @@ -121,25 +121,8 @@ public void extractCommands( Collection extractedCommands ) thro @Override public void close() throws AuxiliaryTransactionStateCloseException { - AuxiliaryTransactionStateCloseException exception = null; - for ( AuxiliaryTransactionState state : openedStates.values() ) - { - try - { - state.close(); - } - catch ( Exception e ) - { - if ( exception == null ) - { - exception = new AuxiliaryTransactionStateCloseException( "Failure when closing auxiliary transaction state.", e ); - } - else - { - exception.addSuppressed( e ); - } - } - } + IOUtils.close( ( msg, cause ) -> new AuxiliaryTransactionStateCloseException( "Failure when closing auxiliary transaction state.", cause ), + openedStates.values() ); } } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/NodeValueClientFilter.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/NodeValueClientFilter.java index 862198a7ccb1..84da400b6602 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/NodeValueClientFilter.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/newapi/NodeValueClientFilter.java @@ -35,10 +35,10 @@ /** * This class filters acceptNode() calls from an index progressor, to assert that exact entries returned from the * progressor really match the exact property values. See also org.neo4j.kernel.impl.api.LookupFilter. - * + *

* It works by acting as a man-in-the-middle between outer {@link NodeValueClient client} and inner {@link IndexProgressor}. * Interaction goes like: - * + *

* Initialize: *


  * client
@@ -47,7 +47,7 @@
  *                                 filter <- initialize(progressor) -- progressor
  * client <- initialize(filter) -- filter
  * 
- * + *

* Progress: *


  * client -- next() ->       filter
@@ -61,7 +61,7 @@
  *        -- :true ->        filter -- :true ->           progressor
  * client <----------------------------------------------
  * 
- * + *

* Close: *


  * client -- close() -> filter
@@ -78,9 +78,7 @@ class NodeValueClientFilter implements NodeValueClient, IndexProgressor
     private final org.neo4j.internal.kernel.api.Read read;
     private IndexProgressor progressor;
 
-    NodeValueClientFilter(
-            NodeValueClient target,
-            NodeCursor node, PropertyCursor property, Read read, IndexQuery... filters )
+    NodeValueClientFilter( NodeValueClient target, NodeCursor node, PropertyCursor property, Read read, IndexQuery... filters )
     {
         this.target = target;
         this.node = node;
@@ -90,11 +88,7 @@ class NodeValueClientFilter implements NodeValueClient, IndexProgressor
     }
 
     @Override
-    public void initialize( IndexDescriptor descriptor,
-                            IndexProgressor progressor,
-                            IndexQuery[] query,
-                            IndexOrder indexOrder,
-                            boolean needsValues )
+    public void initialize( IndexDescriptor descriptor, IndexProgressor progressor, IndexQuery[] query, IndexOrder indexOrder, boolean needsValues )
     {
         this.progressor = progressor;
         target.initialize( descriptor, this, query, indexOrder, needsValues );
@@ -193,6 +187,6 @@ public boolean next()
     @Override
     public void close()
     {
-        IOUtils.closeAll( RuntimeException.class, node, property, progressor );
+        IOUtils.close( RuntimeException::new, node, property, progressor );
     }
 }
diff --git a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/ReflectiveProcedureCompiler.java b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/ReflectiveProcedureCompiler.java
index ae8346df367e..6d62497830a1 100644
--- a/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/ReflectiveProcedureCompiler.java
+++ b/community/kernel/src/main/java/org/neo4j/kernel/impl/proc/ReflectiveProcedureCompiler.java
@@ -735,9 +735,9 @@ public void close()
                     Resource resourceToClose = closeableResource;
                     closeableResource = null;
 
-                    IOUtils.closeAll( ResourceCloseFailureException.class,
+                    IOUtils.close( ResourceCloseFailureException::new,
                             () -> resourceTracker.unregisterCloseableResource( resourceToClose ),
-                            resourceToClose::close );
+                            resourceToClose );
                 }
             }
 
diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/catchup/storecopy/CloseablesListener.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/catchup/storecopy/CloseablesListener.java
index 818dd7b48266..4164d7fa09e8 100644
--- a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/catchup/storecopy/CloseablesListener.java
+++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/catchup/storecopy/CloseablesListener.java
@@ -47,7 +47,7 @@  T add( T closeable )
     @Override
     public void close()
     {
-        IOUtils.closeAll( RuntimeException.class, closeables.toArray( new AutoCloseable[closeables.size()] ) );
+        IOUtils.close( RuntimeException::new, closeables );
     }
 
     @Override