1 /* 2 * Copyright 2021 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 /** 19 * A resource that has a life-time, and can be {@linkplain #close() closed}. 20 * Resources are initially {@linkplain #isAccessible() accessible}, but closing them makes them inaccessible. 21 */ 22 public interface Resource<T extends Resource<T>> extends AutoCloseable { 23 /** 24 * Send this object instance to another Thread, transferring the ownership to the recipient. 25 * <p> 26 * The object must be in a state where it can be sent, which includes at least being 27 * {@linkplain #isAccessible() accessible}. 28 * <p> 29 * When sent, this instance will immediately become inaccessible, as if by {@linkplain #close() closing} it. 30 * All attempts at accessing an object that has been sent, even if that object has not yet been received, should 31 * cause an exception to be thrown. 32 * <p> 33 * Calling {@link #close()} on an object that has been sent will have no effect, so this method is safe to call 34 * within a try-with-resources statement. 35 */ 36 Send<T> send(); 37 38 /** 39 * Close the resource, making it inaccessible. 40 * <p> 41 * Note, this method is not thread-safe unless otherwise specified. 42 * 43 * @throws IllegalStateException If this {@code Resource} has already been closed. 44 */ 45 @Override 46 void close(); 47 48 /** 49 * Check if this object is accessible. 50 * 51 * @return {@code true} if this object is still valid and can be accessed, 52 * otherwise {@code false} if, for instance, this object has been dropped/deallocated, 53 * or been {@linkplain #send() sent} elsewhere. 54 */ 55 boolean isAccessible(); 56 57 /** 58 * Record the current access location for debugging purposes. 59 * This information may be included if the resource throws a life-cycle related exception, or if it leaks. 60 * If this resource has already been closed, then this method has no effect. 61 * 62 * @param hint An optional hint about this access and its context. May be {@code null}. 63 * @return This resource instance. 64 */ 65 @SuppressWarnings("unchecked") 66 default T touch(Object hint) { 67 return (T) this; 68 } 69 70 /** 71 * Attempt to dispose of whatever the given object is. 72 * <p> 73 * If the object is {@link AutoCloseable}, such as anything that implements {@link Resource}, 74 * then it will be closed. 75 * If the object is {@link ReferenceCounted}, then it will be released once. 76 * <p> 77 * Any exceptions caused by this will be left to bubble up, and checked exceptions will be wrapped in a 78 * {@link RuntimeException}. 79 * 80 * @param obj The object to dispose of. 81 */ 82 static void dispose(Object obj) { 83 if (obj instanceof AutoCloseable) { 84 try { 85 ((AutoCloseable) obj).close(); 86 } catch (RuntimeException re) { 87 throw re; 88 } catch (Exception e) { 89 throw new RuntimeException("Exception from closing object", e); 90 } 91 } else if (ReferenceCountUtil.isReferenceCounted(obj)) { 92 ReferenceCountUtil.release(obj); 93 } 94 } 95 96 /** 97 * Check if an object is accessible. This returns {@code true} if the object is a {@linkplain Resource resource} 98 * that {@linkplain Resource#isAccessible() is accessible}, or if the object is 99 * {@linkplain ReferenceCounted reference counted} and has a positive 100 * {@linkplain ReferenceCounted#refCnt() reference count}. 101 * <p> 102 * If the object is neither of these types, then the expected default value is returned. 103 * 104 * @param obj The object to check. 105 * @param expectedDefault The value to return if the object is neither a resource, nor reference counted. 106 * @return If the object is accessible. 107 */ 108 static boolean isAccessible(Object obj, boolean expectedDefault) { 109 if (obj instanceof Resource) { 110 return ((Resource<?>) obj).isAccessible(); 111 } 112 if (obj instanceof ReferenceCounted) { 113 return ((ReferenceCounted) obj).refCnt() > 0; 114 } 115 return expectedDefault; 116 } 117 118 /** 119 * Record the current access location for debugging purposes. 120 * This information may be included if the resource throws a life-cycle related exception, or if it leaks. 121 * If this resource has already been closed, then this method has no effect. 122 * <p> 123 * If the given object is not a resource, or not reference counted, then this method has no effect. 124 * 125 * @param obj The object to annotate. 126 * @param hint An optional hint about this access and its context. May be {@code null}. 127 */ 128 static void touch(Object obj, Object hint) { 129 if (obj instanceof Resource) { 130 ((Resource<?>) obj).touch(hint); 131 } else if (obj instanceof ReferenceCounted) { 132 ((ReferenceCounted) obj).touch(hint); 133 } 134 } 135 }