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.netty.channel; 17 18 import io.netty.util.Attribute; 19 import io.netty.util.AttributeKey; 20 21 import java.lang.annotation.Documented; 22 import java.lang.annotation.ElementType; 23 import java.lang.annotation.Inherited; 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 import java.lang.annotation.Target; 27 28 /** 29 * Handles an I/O event or intercepts an I/O operation, and forwards it to its next handler in 30 * its {@link ChannelPipeline}. 31 * 32 * <h3>Sub-types</h3> 33 * <p> 34 * {@link ChannelHandler} itself does not provide many methods, but you usually have to implement one of its subtypes: 35 * <ul> 36 * <li>{@link ChannelInboundHandler} to handle inbound I/O events, and</li> 37 * <li>{@link ChannelOutboundHandler} to handle outbound I/O operations.</li> 38 * </ul> 39 * </p> 40 * <p> 41 * Alternatively, the following adapter classes are provided for your convenience: 42 * <ul> 43 * <li>{@link ChannelInboundHandlerAdapter} to handle inbound I/O events,</li> 44 * <li>{@link ChannelOutboundHandlerAdapter} to handle outbound I/O operations, and</li> 45 * <li>{@link ChannelDuplexHandler} to handle both inbound and outbound events</li> 46 * </ul> 47 * </p> 48 * <p> 49 * For more information, please refer to the documentation of each subtype. 50 * </p> 51 * 52 * <h3>The context object</h3> 53 * <p> 54 * A {@link ChannelHandler} is provided with a {@link ChannelHandlerContext} 55 * object. A {@link ChannelHandler} is supposed to interact with the 56 * {@link ChannelPipeline} it belongs to via a context object. Using the 57 * context object, the {@link ChannelHandler} can pass events upstream or 58 * downstream, modify the pipeline dynamically, or store the information 59 * (using {@link AttributeKey}s) which is specific to the handler. 60 * 61 * <h3>State management</h3> 62 * 63 * A {@link ChannelHandler} often needs to store some stateful information. 64 * The simplest and recommended approach is to use member variables: 65 * <pre> 66 * public interface Message { 67 * // your methods here 68 * } 69 * 70 * public class DataServerHandler extends {@link SimpleChannelInboundHandler}<Message> { 71 * 72 * <b>private boolean loggedIn;</b> 73 * 74 * {@code @Override} 75 * public void channelRead0({@link ChannelHandlerContext} ctx, Message message) { 76 * if (message instanceof LoginMessage) { 77 * authenticate((LoginMessage) message); 78 * <b>loggedIn = true;</b> 79 * } else (message instanceof GetDataMessage) { 80 * if (<b>loggedIn</b>) { 81 * ctx.writeAndFlush(fetchSecret((GetDataMessage) message)); 82 * } else { 83 * fail(); 84 * } 85 * } 86 * } 87 * ... 88 * } 89 * </pre> 90 * Because the handler instance has a state variable which is dedicated to 91 * one connection, you have to create a new handler instance for each new 92 * channel to avoid a race condition where an unauthenticated client can get 93 * the confidential information: 94 * <pre> 95 * // Create a new handler instance per channel. 96 * // See {@link ChannelInitializer#initChannel(Channel)}. 97 * public class DataServerInitializer extends {@link ChannelInitializer}<{@link Channel}> { 98 * {@code @Override} 99 * public void initChannel({@link Channel} channel) { 100 * channel.pipeline().addLast("handler", <b>new DataServerHandler()</b>); 101 * } 102 * } 103 * 104 * </pre> 105 * 106 * <h4>Using {@link AttributeKey}s</h4> 107 * 108 * Although it's recommended to use member variables to store the state of a 109 * handler, for some reason you might not want to create many handler instances. 110 * In such a case, you can use {@link AttributeKey}s which is provided by 111 * {@link ChannelHandlerContext}: 112 * <pre> 113 * public interface Message { 114 * // your methods here 115 * } 116 * 117 * {@code @Sharable} 118 * public class DataServerHandler extends {@link SimpleChannelInboundHandler}<Message> { 119 * private final {@link AttributeKey}<{@link Boolean}> auth = 120 * {@link AttributeKey#valueOf(String) AttributeKey.valueOf("auth")}; 121 * 122 * {@code @Override} 123 * public void channelRead({@link ChannelHandlerContext} ctx, Message message) { 124 * {@link Attribute}<{@link Boolean}> attr = ctx.attr(auth); 125 * if (message instanceof LoginMessage) { 126 * authenticate((LoginMessage) o); 127 * <b>attr.set(true)</b>; 128 * } else (message instanceof GetDataMessage) { 129 * if (<b>Boolean.TRUE.equals(attr.get())</b>) { 130 * ctx.writeAndFlush(fetchSecret((GetDataMessage) o)); 131 * } else { 132 * fail(); 133 * } 134 * } 135 * } 136 * ... 137 * } 138 * </pre> 139 * Now that the state of the handler is attached to the {@link ChannelHandlerContext}, you can add the 140 * same handler instance to different pipelines: 141 * <pre> 142 * public class DataServerInitializer extends {@link ChannelInitializer}<{@link Channel}> { 143 * 144 * private static final DataServerHandler <b>SHARED</b> = new DataServerHandler(); 145 * 146 * {@code @Override} 147 * public void initChannel({@link Channel} channel) { 148 * channel.pipeline().addLast("handler", <b>SHARED</b>); 149 * } 150 * } 151 * </pre> 152 * 153 * 154 * <h4>The {@code @Sharable} annotation</h4> 155 * <p> 156 * In the example above which used an {@link AttributeKey}, 157 * you might have noticed the {@code @Sharable} annotation. 158 * <p> 159 * If a {@link ChannelHandler} is annotated with the {@code @Sharable} 160 * annotation, it means you can create an instance of the handler just once and 161 * add it to one or more {@link ChannelPipeline}s multiple times without 162 * a race condition. 163 * <p> 164 * If this annotation is not specified, you have to create a new handler 165 * instance every time you add it to a pipeline because it has unshared state 166 * such as member variables. 167 * <p> 168 * This annotation is provided for documentation purpose, just like 169 * <a href="http://www.javaconcurrencyinpractice.com/annotations/doc/">the JCIP annotations</a>. 170 * 171 * <h3>Additional resources worth reading</h3> 172 * <p> 173 * Please refer to the {@link ChannelHandler}, and 174 * {@link ChannelPipeline} to find out more about inbound and outbound operations, 175 * what fundamental differences they have, how they flow in a pipeline, and how to handle 176 * the operation in your application. 177 */ 178 public interface ChannelHandler { 179 180 /** 181 * Gets called after the {@link ChannelHandler} was added to the actual context and it's ready to handle events. 182 */ 183 void handlerAdded(ChannelHandlerContext ctx) throws Exception; 184 185 /** 186 * Gets called after the {@link ChannelHandler} was removed from the actual context and it doesn't handle events 187 * anymore. 188 */ 189 void handlerRemoved(ChannelHandlerContext ctx) throws Exception; 190 191 /** 192 * Gets called if a {@link Throwable} was thrown. 193 * 194 * @deprecated if you want to handle this event you should implement {@link ChannelInboundHandler} and 195 * implement the method there. 196 */ 197 @Deprecated 198 void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception; 199 200 /** 201 * Indicates that the same instance of the annotated {@link ChannelHandler} 202 * can be added to one or more {@link ChannelPipeline}s multiple times 203 * without a race condition. 204 * <p> 205 * If this annotation is not specified, you have to create a new handler 206 * instance every time you add it to a pipeline because it has unshared 207 * state such as member variables. 208 * <p> 209 * This annotation is provided for documentation purpose, just like 210 * <a href="http://www.javaconcurrencyinpractice.com/annotations/doc/">the JCIP annotations</a>. 211 */ 212 @Inherited 213 @Documented 214 @Target(ElementType.TYPE) 215 @Retention(RetentionPolicy.RUNTIME) 216 @interface Sharable { 217 // no value 218 } 219 }