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 }