1 /* 2 * Copyright 2012 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.channel; 17 18 import io.netty5.channel.ChannelHandlerMask.Skip; 19 import io.netty5.util.Attribute; 20 import io.netty5.util.AttributeKey; 21 import io.netty5.util.concurrent.Future; 22 23 import java.net.SocketAddress; 24 25 /** 26 * Handles an I/O event or intercepts an I/O operation, and forwards it to its next handler in 27 * its {@link ChannelPipeline}. 28 * 29 * <h3>The context object</h3> 30 * <p> 31 * A {@link ChannelHandler} is provided with a {@link ChannelHandlerContext} 32 * object. A {@link ChannelHandler} is supposed to interact with the 33 * {@link ChannelPipeline} it belongs to via a context object. Using the 34 * context object, the {@link ChannelHandler} can pass events upstream or 35 * downstream, modify the pipeline dynamically, or store the information 36 * (using {@link AttributeKey}s) which is specific to the handler. 37 * 38 * <h3>State management</h3> 39 * 40 * A {@link ChannelHandler} often needs to store some stateful information. 41 * The simplest and recommended approach is to use member variables: 42 * <pre> 43 * public interface Message { 44 * // your methods here 45 * } 46 * 47 * public class DataServerHandler extends {@link SimpleChannelInboundHandler}<Message> { 48 * 49 * <b>private boolean loggedIn;</b> 50 * 51 * {@code @Override} 52 * public void messageReceived({@link ChannelHandlerContext} ctx, Message message) { 53 * if (message instanceof LoginMessage) { 54 * authenticate((LoginMessage) message); 55 * <b>loggedIn = true;</b> 56 * } else (message instanceof GetDataMessage) { 57 * if (<b>loggedIn</b>) { 58 * ctx.writeAndFlush(fetchSecret((GetDataMessage) message)); 59 * } else { 60 * fail(); 61 * } 62 * } 63 * } 64 * ... 65 * } 66 * </pre> 67 * Because the handler instance has a state variable which is dedicated to 68 * one connection, you have to create a new handler instance for each new 69 * channel to avoid a race condition where a unauthenticated client can get 70 * the confidential information: 71 * <pre> 72 * // Create a new handler instance per channel. 73 * // See {@link ChannelInitializer#initChannel(Channel)}. 74 * public class DataServerInitializer extends {@link ChannelInitializer}<{@link Channel}> { 75 * {@code @Override} 76 * public void initChannel({@link Channel} channel) { 77 * channel.pipeline().addLast("handler", <b>new DataServerHandler()</b>); 78 * } 79 * } 80 * 81 * </pre> 82 * 83 * <h4>Using {@link AttributeKey}s</h4> 84 * 85 * Although it's recommended to use member variables to store the state of a 86 * handler, for some reason you might not want to create many handler instances. 87 * In such a case, you can use {@link AttributeKey}s which is provided by 88 * {@link ChannelHandlerContext}: 89 * <pre> 90 * public interface Message { 91 * // your methods here 92 * } 93 * 94 * public class DataServerHandler extends {@link SimpleChannelInboundHandler}<Message> { 95 * private final {@link AttributeKey}<{@link Boolean}> auth = 96 * {@link AttributeKey#valueOf(String) AttributeKey.valueOf("auth")}; 97 * 98 * {@code @Override} 99 * public boolean isSharable() { 100 * return true; 101 * } 102 * {@code @Override} 103 * public void channelRead({@link ChannelHandlerContext} ctx, Message message) { 104 * {@link Attribute}<{@link Boolean}> attr = ctx.attr(auth); 105 * if (message instanceof LoginMessage) { 106 * authenticate((LoginMessage) o); 107 * <b>attr.set(true)</b>; 108 * } else (message instanceof GetDataMessage) { 109 * if (<b>Boolean.TRUE.equals(attr.get())</b>) { 110 * ctx.writeAndFlush(fetchSecret((GetDataMessage) o)); 111 * } else { 112 * fail(); 113 * } 114 * } 115 * } 116 * ... 117 * } 118 * </pre> 119 * Now that the state of the handler is attached to the {@link ChannelHandlerContext}, you can add the 120 * same handler instance to different pipelines: 121 * <pre> 122 * public class DataServerInitializer extends {@link ChannelInitializer}<{@link Channel}> { 123 * 124 * private static final DataServerHandler <b>SHARED</b> = new DataServerHandler(); 125 * 126 * {@code @Override} 127 * public void initChannel({@link Channel} channel) { 128 * channel.pipeline().addLast("handler", <b>SHARED</b>); 129 * } 130 * } 131 * </pre> 132 * 133 * 134 * <h4>The {@link #isSharable()} method</h4> 135 * <p> 136 * In the example above which used an {@link AttributeKey}, 137 * you might have noticed the {@link #isSharable()} method is override to return {@code true}. 138 * <p> 139 * If the {@link ChannelHandler#isSharable()} is returning{@code true}, 140 * it means you can create an instance of the handler just once and 141 * add it to one or more {@link ChannelPipeline}s multiple times without 142 * a race condition. 143 * <p> 144 * If this method is not implemented and return {@code false}, you have to create a new handler 145 * instance every time you add it to a pipeline because it has unshared state 146 * such as member variables. 147 * 148 * <h3>Additional resources worth reading</h3> 149 * <p> 150 * Please refer to the {@link ChannelHandler}, and 151 * {@link ChannelPipeline} to find out more about inbound and outbound operations, 152 * what fundamental differences they have, how they flow in a pipeline, and how to handle 153 * the operation in your application. 154 */ 155 public interface ChannelHandler { 156 157 /** 158 * Gets called after the {@link ChannelHandler} was added to the actual context and it's ready to handle events. 159 */ 160 default void handlerAdded(ChannelHandlerContext ctx) throws Exception { 161 // NOOP 162 } 163 164 /** 165 * Gets called after the {@link ChannelHandler} was removed from the actual context and it doesn't handle events 166 * anymore. 167 */ 168 default void handlerRemoved(ChannelHandlerContext ctx) throws Exception { 169 // NOOP 170 } 171 172 /** 173 * Returns {@code true} if this handler is sharable and thus can be added 174 * to more than one {@link ChannelPipeline}. By default, this method returns {@code false}. 175 * If this method returns {@code false}, you have to create a new handler 176 * instance every time you add it to a pipeline because it has unshared 177 * state such as member variables. 178 */ 179 default boolean isSharable() { 180 return false; 181 } 182 183 /** 184 * The {@link Channel} of the {@link ChannelHandlerContext} was registered with its {@link EventLoop} 185 */ 186 @Skip 187 default void channelRegistered(ChannelHandlerContext ctx) throws Exception { 188 ctx.fireChannelRegistered(); 189 } 190 191 /** 192 * The {@link Channel} of the {@link ChannelHandlerContext} was unregistered from its {@link EventLoop} 193 */ 194 @Skip 195 default void channelUnregistered(ChannelHandlerContext ctx) throws Exception { 196 ctx.fireChannelUnregistered(); 197 } 198 199 /** 200 * The {@link Channel} of the {@link ChannelHandlerContext} is now active 201 */ 202 @Skip 203 default void channelActive(ChannelHandlerContext ctx) throws Exception { 204 ctx.fireChannelActive(); 205 } 206 207 /** 208 * The {@link Channel} of the {@link ChannelHandlerContext} was registered is now inactive and reached its 209 * end of lifetime. 210 */ 211 @Skip 212 default void channelInactive(ChannelHandlerContext ctx) throws Exception { 213 ctx.fireChannelInactive(); 214 } 215 216 /** 217 * The {@link Channel} of the {@link ChannelHandlerContext} was shutdown in one direction. 218 * This might either be because the remote peer did cause a shutdown of one direction or the shutdown was requested 219 * explicit by us and was executed. 220 * 221 * @param ctx the {@link ChannelHandlerContext} for which we notify about the completed shutdown. 222 * @param direction the {@link ChannelShutdownDirection} of the completed shutdown. 223 */ 224 @Skip 225 default void channelShutdown(ChannelHandlerContext ctx, ChannelShutdownDirection direction) throws Exception { 226 ctx.fireChannelShutdown(direction); 227 } 228 229 /** 230 * Invoked when the current {@link Channel} has read a message from the peer. 231 */ 232 @Skip 233 default void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 234 ctx.fireChannelRead(msg); 235 } 236 237 /** 238 * Invoked when the last message read by the current read operation has been consumed by 239 * {@link #channelRead(ChannelHandlerContext, Object)}. If {@link ChannelOption#AUTO_READ} is off, no further 240 * attempt to read an inbound data from the current {@link Channel} will be made until 241 * {@link ChannelHandlerContext#read()} is called. 242 */ 243 @Skip 244 default void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 245 ctx.fireChannelReadComplete(); 246 } 247 248 /** 249 * Gets called if a custom inbound event happened. 250 */ 251 @Skip 252 default void channelInboundEvent(ChannelHandlerContext ctx, Object evt) throws Exception { 253 ctx.fireChannelInboundEvent(evt); 254 } 255 256 /** 257 * Gets called once the writable state of a {@link Channel} changed. You can check the state with 258 * {@link Channel#writableBytes()} or {@link Channel#isWritable()}. 259 */ 260 @Skip 261 default void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception { 262 ctx.fireChannelWritabilityChanged(); 263 } 264 265 /** 266 * Gets called if a {@link Throwable} was thrown when handling inbound events. 267 */ 268 @Skip 269 default void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 270 ctx.fireChannelExceptionCaught(cause); 271 } 272 273 /** 274 * Called once a bind operation is made. 275 * 276 * @param ctx the {@link ChannelHandlerContext} for which the bind operation is made 277 * @param localAddress the {@link SocketAddress} to which it should bound 278 * @return the {@link Future} which will be notified once the operation completes. 279 */ 280 @Skip 281 default Future<Void> bind(ChannelHandlerContext ctx, SocketAddress localAddress) { 282 return ctx.bind(localAddress); 283 } 284 285 /** 286 * Called once a connect operation is made. 287 * 288 * @param ctx the {@link ChannelHandlerContext} for which the connect operation is made 289 * @param remoteAddress the {@link SocketAddress} to which it should connect 290 * @param localAddress the {@link SocketAddress} which is used as source on connect 291 * @return the {@link Future} which will be notified once the operation completes. 292 */ 293 @Skip 294 default Future<Void> connect( 295 ChannelHandlerContext ctx, SocketAddress remoteAddress, 296 SocketAddress localAddress) { 297 return ctx.connect(remoteAddress, localAddress); 298 } 299 300 /** 301 * Called once a disconnect operation is made. 302 * 303 * @param ctx the {@link ChannelHandlerContext} for which the disconnect operation is made 304 * @return the {@link Future} which will be notified once the operation completes. 305 */ 306 @Skip 307 default Future<Void> disconnect(ChannelHandlerContext ctx) { 308 return ctx.disconnect(); 309 } 310 311 /** 312 * Called once a close operation is made. 313 * 314 * @param ctx the {@link ChannelHandlerContext} for which the close operation is made 315 * @return the {@link Future} which will be notified once the operation completes. 316 */ 317 @Skip 318 default Future<Void> close(ChannelHandlerContext ctx) { 319 return ctx.close(); 320 } 321 322 /** 323 * Called once a shutdown operation was requested and should be executed. 324 * 325 * @param ctx the {@link ChannelHandlerContext} for which the shutdown operation is made 326 * @param direction the {@link ChannelShutdownDirection} that is used. 327 * @return the {@link Future} which will be notified once the operation completes. 328 */ 329 @Skip 330 default Future<Void> shutdown(ChannelHandlerContext ctx, ChannelShutdownDirection direction) { 331 return ctx.shutdown(direction); 332 } 333 334 /** 335 * Called once a register operation is made to register for IO on the {@link EventLoop}. 336 * 337 * @param ctx the {@link ChannelHandlerContext} for which the register operation is made 338 * @return the {@link Future} which will be notified once the operation completes. 339 */ 340 @Skip 341 default Future<Void> register(ChannelHandlerContext ctx) { 342 return ctx.register(); 343 } 344 345 /** 346 * Called once a deregister operation is made from the current registered {@link EventLoop}. 347 * 348 * @param ctx the {@link ChannelHandlerContext} for which the deregister operation is made 349 * @return the {@link Future} which will be notified once the operation completes. 350 */ 351 @Skip 352 default Future<Void> deregister(ChannelHandlerContext ctx) { 353 return ctx.deregister(); 354 } 355 356 /** 357 * Intercepts {@link ChannelHandlerContext#read()}. 358 */ 359 @Skip 360 default void read(ChannelHandlerContext ctx) { 361 ctx.read(); 362 } 363 364 /** 365 * Called once a write operation is made. The write operation will write the messages through the 366 * {@link ChannelPipeline}. Those are then ready to be flushed to the actual {@link Channel} once 367 * {@link Channel#flush()} is called. 368 * 369 * @param ctx the {@link ChannelHandlerContext} for which the write operation is made 370 * @param msg the message to write 371 * @return the {@link Future} which will be notified once the operation completes. 372 */ 373 @Skip 374 default Future<Void> write(ChannelHandlerContext ctx, Object msg) { 375 return ctx.write(msg); 376 } 377 378 /** 379 * Called once a flush operation is made. The flush operation will try to flush out all previous written messages 380 * that are pending. 381 * 382 * @param ctx the {@link ChannelHandlerContext} for which the flush operation is made 383 */ 384 @Skip 385 default void flush(ChannelHandlerContext ctx) { 386 ctx.flush(); 387 } 388 389 /** 390 * Called once a custom defined outbound event was sent. This operation will pass the event through the 391 * {@link ChannelPipeline} in the outbound direction. 392 * 393 * @param ctx the {@link ChannelHandlerContext} for which the operation is made. 394 * @param event the event. 395 * @return the {@link Future} which will be notified once the operation completes. 396 */ 397 @Skip 398 default Future<Void> sendOutboundEvent(ChannelHandlerContext ctx, Object event) { 399 return ctx.sendOutboundEvent(event); 400 } 401 402 /** 403 * The number of the outbound bytes that are buffered / queued in this {@link ChannelHandler}. This number will 404 * affect the writability of the {@link Channel} together the buffered / queued bytes in the {@link Channel} itself. 405 * By default this methods returns {@code 0}. If the {@link ChannelHandler} implementation buffers / queues 406 * outbound data this methods should be implemented to return the correct value. 407 * 408 * @param ctx the {@link ChannelHandlerContext} for which the operation is made. 409 * @return the number of buffered / queued bytes. 410 */ 411 @Skip 412 default long pendingOutboundBytes(ChannelHandlerContext ctx) { 413 return 0; 414 } 415 }