View Javadoc
1   /*
2    * Copyright 2022 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty5.util.internal;
17  
18  import io.netty5.util.ReferenceCounted;
19  import io.netty5.util.Resource;
20  import io.netty5.util.internal.logging.InternalLogger;
21  
22  /**
23   * Utility class for disposing of {@linkplain Resource resources} without propagating any exception that
24   * {@link Resource#close()} might throw.
25   */
26  public final class SilentDispose {
27      /**
28       * Attempt to dispose of whatever the given object is.
29       * <p>
30       * This method works similarly to {@link Resource#dispose(Object)}, except any exception thrown will be logged
31       * instead of propagated.
32       * <p>
33       * If the object is {@link AutoCloseable}, such as anything that implements {@link Resource},
34       * then it will be closed.
35       * If the object is {@link ReferenceCounted}, then it will be released once.
36       * <p>
37       * Any exceptions caused by this will be logged using the given logger.
38       * The exception will be logged at log-level {@link io.netty5.util.internal.logging.InternalLogLevel#WARN WARN}.
39       *
40       * @param obj The object to dispose of.
41       * @param logger The logger to use for recording any exceptions thrown by the disposal.
42       */
43      public static void dispose(Object obj, InternalLogger logger) {
44          try {
45              Resource.dispose(obj);
46          } catch (Throwable throwable) {
47              logger.warn("Failed to dispose object: {}.", obj, throwable);
48          }
49      }
50  
51      /**
52       * Attempt to dispose of whatever the given object is, but only if it is disposable.
53       * <p>
54       * This method works similarly to {@link #dispose(Object, InternalLogger)}, except the object is only disposed of
55       * if it is {@linkplain Resource#isAccessible(Object, boolean) accessible}.
56       * <p>
57       * Any exceptions caused by the disposal of the object will be logged using the given logger.
58       * The exception will be logged at log-level {@link io.netty5.util.internal.logging.InternalLogLevel#WARN WARN}.
59       *
60       * @param obj The object to dispose of.
61       * @param logger The logger to use for recording any exceptions thrown by the disposal.
62       */
63      public static void trySilentDispose(Object obj, InternalLogger logger) {
64          if (Resource.isAccessible(obj, false)) {
65              dispose(obj, logger);
66          }
67      }
68  
69      /**
70       * Attempt to dispose of whatever the given object is, but only if it is disposable.
71       * <p>
72       * This method works similarly to {@link Resource#dispose(Object)}, except the object is only disposed of if it is
73       * {@linkplain Resource#isAccessible(Object, boolean) accessible}.
74       * <p>
75       * Any exceptions caused the disposal will be allowed to propagate from this method, which is in contrast to how
76       * {@link #dispose(Object, InternalLogger)} and {@link #trySilentDispose(Object, InternalLogger)} works.
77       *
78       * @param obj The object to dispose of.
79       */
80      public static void tryPropagatingDispose(Object obj) {
81          if (Resource.isAccessible(obj, false)) {
82              Resource.dispose(obj);
83          }
84      }
85  
86      /**
87       * Return an {@link AutoCloseable} for the given object, which can be used to dispose of it using a
88       * try-with-resources clause.
89       * <p>
90       * The benefit of this approach is that exceptions are correctly handled if both the try-body, and the resource
91       * disposal, throws.
92       * <p>
93       * This is not a silent operation, in that exceptions from resource disposal will propagate.
94       * However, the try-with-resources clause will guarantee that resource disposal exceptions won't shadow any
95       * exceptions from the try-body
96       *
97       * @param obj The object to dispose of.
98       * @return An {@link AutoCloseable} that will dispose of the given object when closed.
99       */
100     public static AutoCloseable autoClosing(Object obj) {
101         if (obj instanceof AutoCloseable) {
102             return (AutoCloseable) obj;
103         }
104         if (obj instanceof ReferenceCounted) {
105             return () -> ((ReferenceCounted) obj).release();
106         }
107         // It is safe to use null in try-with-resources. We can use that for uncloseable/unreleasable things.
108         return null;
109     }
110 
111     private SilentDispose() {
112     }
113 }