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 }