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.buffer.api; 17 18 import io.netty5.buffer.api.internal.ResourceSupport; 19 import io.netty5.buffer.api.internal.Statics; 20 import io.netty5.util.Resource; 21 import io.netty5.util.Send; 22 23 import java.lang.invoke.VarHandle; 24 import java.util.Objects; 25 26 import static java.lang.invoke.MethodHandles.lookup; 27 28 /** 29 * The {@link BufferHolder} is an abstract class that simplifies the implementation of objects that themselves contain 30 * a {@link Buffer} instance. 31 * <p> 32 * The {@link BufferHolder} can only hold on to a single buffer, so objects and classes that need to hold on to multiple 33 * buffers will have to do their implementation from scratch, though they can use the code of the {@link BufferHolder} 34 * as inspiration. Alternatively, multiple buffers can be 35 * {@linkplain BufferAllocator#compose(Iterable) composed} into a single buffer, which can then be put 36 * in a buffer holder. 37 * <p> 38 * If you just want an object that is a reference to a buffer, then the {@link BufferRef} can be used for that purpose. 39 * If you have an advanced use case where you wish to implement {@link Resource}, and tightly control lifetimes, then 40 * {@link ResourceSupport} can be of help. 41 * 42 * @param <T> The concrete {@link BufferHolder} type. 43 */ 44 public abstract class BufferHolder<T extends Resource<T>> implements Resource<T> { 45 private static final VarHandle BUF = Statics.findVarHandle(lookup(), BufferHolder.class, "buf", Buffer.class); 46 private Buffer buf; 47 48 /** 49 * Create a new {@link BufferHolder} to hold the given {@linkplain Buffer buffer}. 50 * 51 * @param buf The {@linkplain Buffer buffer} to be held by this holder. 52 */ 53 protected BufferHolder(Buffer buf) { 54 this.buf = Objects.requireNonNull(buf, "The buffer cannot be null."); 55 } 56 57 /** 58 * Create a new {@link BufferHolder} to hold the {@linkplain Buffer buffer} received from the given {@link Send}. 59 * <p> 60 * The {@link BufferHolder} will then be holding exclusive ownership of the buffer. 61 * 62 * @param send The {@linkplain Buffer buffer} to be held by this holder. 63 */ 64 protected BufferHolder(Send<Buffer> send) { 65 buf = Objects.requireNonNull(send, "The Send-object cannot be null.").receive(); 66 } 67 68 @Override 69 public void close() { 70 buf.close(); 71 } 72 73 @SuppressWarnings("unchecked") 74 @Override 75 public Send<T> send() { 76 return buf.send().map((Class<T>) getClass(), this::receive); 77 } 78 79 /** 80 * Called when a {@linkplain #send() sent} {@link BufferHolder} is received by the recipient. 81 * The {@link BufferHolder} should return a new concrete instance, that wraps the given {@link Buffer} object. 82 * 83 * @param buf The {@link Buffer} that is {@linkplain Send#receive() received} by the recipient, 84 * and needs to be wrapped in a new {@link BufferHolder} instance. 85 * @return A new {@linkplain T buffer holder} instance, containing the given {@linkplain Buffer buffer}. 86 */ 87 protected abstract T receive(Buffer buf); 88 89 /** 90 * Replace the underlying referenced buffer with the given buffer. 91 * <p> 92 * This method is protected to permit advanced use cases of {@link BufferHolder} sub-class implementations. 93 * <p> 94 * <strong>Note:</strong> This method closes the current buffer, 95 * and takes exclusive ownership of the received buffer. 96 * <p> 97 * The buffer assignment is performed using a plain store. 98 * 99 * @param send The new {@link Buffer} instance that is replacing the currently held buffer. 100 */ 101 protected final void replaceBuffer(Send<Buffer> send) { 102 Buffer received = send.receive(); 103 buf.close(); 104 buf = received; 105 } 106 107 /** 108 * Replace the underlying referenced buffer with the given buffer. 109 * <p> 110 * This method is protected to permit advanced use cases of {@link BufferHolder} sub-class implementations. 111 * <p> 112 * <strong>Note:</strong> this method closes the current buffer, 113 * and takes exclusive ownership of the received buffer. 114 * <p> 115 * The buffer assignment is performed using a volatile store. 116 * 117 * @param send The {@link Send} with the new {@link Buffer} instance that is replacing the currently held buffer. 118 */ 119 protected final void replaceBufferVolatile(Send<Buffer> send) { 120 Buffer received = send.receive(); 121 var prev = (Buffer) BUF.getAndSet(this, received); 122 prev.close(); 123 } 124 125 /** 126 * Access the held {@link Buffer} instance. 127 * <p> 128 * The access is performed using a plain load. 129 * 130 * @return The {@link Buffer} instance being held by this {@linkplain T buffer holder}. 131 */ 132 protected final Buffer getBuffer() { 133 return buf; 134 } 135 136 /** 137 * Access the held {@link Buffer} instance. 138 * <p> 139 * The access is performed using a volatile load. 140 * 141 * @return The {@link Buffer} instance being held by this {@linkplain T buffer holder}. 142 */ 143 protected final Buffer getBufferVolatile() { 144 return (Buffer) BUF.getVolatile(this); 145 } 146 147 @Override 148 public boolean isAccessible() { 149 return buf.isAccessible(); 150 } 151 152 @SuppressWarnings("unchecked") 153 @Override 154 public T touch(Object hint) { 155 buf.touch(hint); 156 return (T) this; 157 } 158 159 /** 160 * This implementation of the {@code equals} operation is restricted to work only with instances of the same class. 161 * The reason for that is that Netty library already has a number of classes that extend {@link BufferHolder} and 162 * override {@code equals} method with an additional comparison logic, and we need the symmetric property of the 163 * {@code equals} operation to be preserved. 164 * 165 * @param other The reference object with which to compare. 166 * @return {@code true} if this object is the same as the obj argument; {@code false} otherwise. 167 */ 168 @Override 169 public boolean equals(Object other) { 170 if (this == other) { 171 return true; 172 } 173 if (other != null && getClass() == other.getClass()) { 174 return buf.equals(((BufferHolder<?>) other).buf); 175 } 176 return false; 177 } 178 179 @Override 180 public int hashCode() { 181 int result = getClass().hashCode(); 182 result *= 31 + buf.hashCode(); 183 return result; 184 } 185 }