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 }