1 /*
2 * Copyright 2013 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;
17
18 import io.netty5.util.internal.ObjectUtil;
19 import io.netty5.util.internal.logging.InternalLogger;
20 import io.netty5.util.internal.logging.InternalLoggerFactory;
21
22 /**
23 * Collection of method to handle objects that may implement {@link ReferenceCounted}.
24 */
25 public final class ReferenceCountUtil {
26
27 private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountUtil.class);
28
29 static {
30 ResourceLeakDetector.addExclusions(ReferenceCountUtil.class, "touch");
31 }
32
33 /**
34 * Tests whether the given object implements the {@link ReferenceCounted} interface.
35 *
36 * @param obj The object to test.
37 * @return {@code true} if the given object is reference counted.
38 */
39 public static boolean isReferenceCounted(Object obj) {
40 return obj instanceof ReferenceCounted;
41 }
42
43 /**
44 * Try to call {@link ReferenceCounted#retain()} if the specified message implements {@link ReferenceCounted}.
45 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
46 */
47 @SuppressWarnings("unchecked")
48 public static <T> T retain(T msg) {
49 if (msg instanceof ReferenceCounted) {
50 return (T) ((ReferenceCounted) msg).retain();
51 }
52 return msg;
53 }
54
55 /**
56 * Try to call {@link ReferenceCounted#retain(int)} if the specified message implements {@link ReferenceCounted}.
57 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
58 */
59 @SuppressWarnings("unchecked")
60 public static <T> T retain(T msg, int increment) {
61 ObjectUtil.checkPositive(increment, "increment");
62 if (msg instanceof ReferenceCounted) {
63 return (T) ((ReferenceCounted) msg).retain(increment);
64 }
65 return msg;
66 }
67
68 /**
69 * Tries to call {@link ReferenceCounted#touch()} if the specified message implements {@link ReferenceCounted}.
70 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
71 */
72 @SuppressWarnings("unchecked")
73 public static <T> T touch(T msg) {
74 if (msg instanceof ReferenceCounted) {
75 return (T) ((ReferenceCounted) msg).touch();
76 }
77 return msg;
78 }
79
80 /**
81 * Tries to call {@link ReferenceCounted#touch(Object)} if the specified message implements
82 * {@link ReferenceCounted}. If the specified message doesn't implement {@link ReferenceCounted},
83 * this method does nothing.
84 */
85 @SuppressWarnings("unchecked")
86 public static <T> T touch(T msg, Object hint) {
87 if (msg instanceof ReferenceCounted) {
88 return (T) ((ReferenceCounted) msg).touch(hint);
89 }
90 return msg;
91 }
92
93 /**
94 * Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}.
95 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
96 */
97 public static boolean release(Object msg) {
98 if (msg instanceof ReferenceCounted) {
99 return ((ReferenceCounted) msg).release();
100 }
101 return false;
102 }
103
104 /**
105 * Try to call {@link ReferenceCounted#release(int)} if the specified message implements {@link ReferenceCounted}.
106 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
107 */
108 public static boolean release(Object msg, int decrement) {
109 ObjectUtil.checkPositive(decrement, "decrement");
110 if (msg instanceof ReferenceCounted) {
111 return ((ReferenceCounted) msg).release(decrement);
112 }
113 return false;
114 }
115
116 /**
117 * Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}.
118 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
119 * Unlike {@link #release(Object)} this method catches an exception raised by {@link ReferenceCounted#release()}
120 * and logs it, rather than rethrowing it to the caller. It is usually recommended to use {@link #release(Object)}
121 * instead, unless you absolutely need to swallow an exception.
122 */
123 public static void safeRelease(Object msg) {
124 try {
125 release(msg);
126 } catch (Throwable t) {
127 logger.warn("Failed to release a message: {}", msg, t);
128 }
129 }
130
131 /**
132 * Try to call {@link ReferenceCounted#release(int)} if the specified message implements {@link ReferenceCounted}.
133 * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
134 * Unlike {@link #release(Object)} this method catches an exception raised by {@link ReferenceCounted#release(int)}
135 * and logs it, rather than rethrowing it to the caller. It is usually recommended to use
136 * {@link #release(Object, int)} instead, unless you absolutely need to swallow an exception.
137 */
138 public static void safeRelease(Object msg, int decrement) {
139 try {
140 ObjectUtil.checkPositive(decrement, "decrement");
141 release(msg, decrement);
142 } catch (Throwable t) {
143 if (logger.isWarnEnabled()) {
144 logger.warn("Failed to release a message: {} (decrement: {})", msg, decrement, t);
145 }
146 }
147 }
148
149 /**
150 * Returns reference count of a {@link ReferenceCounted} object. If object is not type of
151 * {@link ReferenceCounted}, {@code -1} is returned.
152 */
153 public static int refCnt(Object msg) {
154 return msg instanceof ReferenceCounted ? ((ReferenceCounted) msg).refCnt() : -1;
155 }
156
157 private ReferenceCountUtil() { }
158 }