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