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 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 a 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 }
220