View Javadoc
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}&lt;Message&gt; {
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}&lt;{@link Channel}&gt; {
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}&lt;Message&gt; {
95   *     private final {@link AttributeKey}&lt;{@link Boolean}&gt; 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}&lt;{@link Boolean}&gt; 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}&lt;{@link Channel}&gt; {
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 }