/* * Copyright 2013 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package io.netty.util; import io.netty.util.internal.StringUtil; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; /** * Collection of method to handle objects that may implement {@link ReferenceCounted}. */ public final class ReferenceCountUtil { private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountUtil.class); /** * Try to call {@link ReferenceCounted#retain()} if the specified message implements {@link ReferenceCounted}. * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. */ @SuppressWarnings("unchecked") public static <T> T retain(T msg) { if (msg instanceof ReferenceCounted) { return (T) ((ReferenceCounted) msg).retain(); } return msg; } /** * Try to call {@link ReferenceCounted#retain()} if the specified message implements {@link ReferenceCounted}. * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. */ @SuppressWarnings("unchecked") public static <T> T retain(T msg, int increment) { if (msg instanceof ReferenceCounted) { return (T) ((ReferenceCounted) msg).retain(increment); } return msg; } /** * Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}. * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. */ public static boolean release(Object msg) { if (msg instanceof ReferenceCounted) { return ((ReferenceCounted) msg).release(); } return false; } /** * Try to call {@link ReferenceCounted#release(int)} if the specified message implements {@link ReferenceCounted}. * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. */ public static boolean release(Object msg, int decrement) { if (msg instanceof ReferenceCounted) { return ((ReferenceCounted) msg).release(decrement); } return false; } /** * Try to call {@link ReferenceCounted#release()} if the specified message implements {@link ReferenceCounted}. * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. * Unlike {@link #release(Object)} this method catches an exception raised by {@link ReferenceCounted#release()} * and logs it, rather than rethrowing it to the caller. It is usually recommended to use {@link #release(Object)} * instead, unless you absolutely need to swallow an exception. */ public static void safeRelease(Object msg) { try { release(msg); } catch (Throwable t) { logger.warn("Failed to release a message: {}", msg, t); } } /** * Try to call {@link ReferenceCounted#release(int)} if the specified message implements {@link ReferenceCounted}. * If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing. * Unlike {@link #release(Object)} this method catches an exception raised by {@link ReferenceCounted#release(int)} * and logs it, rather than rethrowing it to the caller. It is usually recommended to use * {@link #release(Object, int)} instead, unless you absolutely need to swallow an exception. */ public static void safeRelease(Object msg, int decrement) { try { release(msg, decrement); } catch (Throwable t) { if (logger.isWarnEnabled()) { logger.warn("Failed to release a message: {} (decrement: {})", msg, decrement, t); } } } /** * Schedules the specified object to be released when the caller thread terminates. Note that this operation is * intended to simplify reference counting of ephemeral objects during unit tests. Do not use it beyond the * intended use case. */ public static <T> T releaseLater(T msg) { return releaseLater(msg, 1); } /** * Schedules the specified object to be released when the caller thread terminates. Note that this operation is * intended to simplify reference counting of ephemeral objects during unit tests. Do not use it beyond the * intended use case. */ public static <T> T releaseLater(T msg, int decrement) { if (msg instanceof ReferenceCounted) { ThreadDeathWatcher.watch(Thread.currentThread(), new ReleasingTask((ReferenceCounted) msg, decrement)); } return msg; } /** * Releases the objects when the thread that called {@link #releaseLater(Object)} has been terminated. */ private static final class ReleasingTask implements Runnable { private final ReferenceCounted obj; private final int decrement; ReleasingTask(ReferenceCounted obj, int decrement) { this.obj = obj; this.decrement = decrement; } @Override public void run() { try { if (!obj.release(decrement)) { logger.warn("Non-zero refCnt: {}", this); } else { logger.debug("Released: {}", this); } } catch (Exception ex) { logger.warn("Failed to release an object: {}", obj, ex); } } @Override public String toString() { return StringUtil.simpleClassName(obj) + ".release(" + decrement + ") refCnt: " + obj.refCnt(); } } private ReferenceCountUtil() { } }