View Javadoc

1   /*
2    * Copyright 2013 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.ReferenceCountUtil;
19  import io.netty.util.internal.TypeParameterMatcher;
20  
21  /**
22   * {@link ChannelInboundHandlerAdapter} which allows to explicit only handle a specific type of messages.
23   *
24   * For example here is an implementation which only handle {@link String} messages.
25   *
26   * <pre>
27   *     public class StringHandler extends
28   *             {@link SimpleChannelInboundHandler}&lt;{@link String}&gt; {
29   *
30   *         {@code @Override}
31   *         protected void channelRead0({@link ChannelHandlerContext} ctx, {@link String} message)
32   *                 throws {@link Exception} {
33   *             System.out.println(message);
34   *         }
35   *     }
36   * </pre>
37   *
38   * Be aware that depending of the constructor parameters it will release all handled messages by passing them to
39   * {@link ReferenceCountUtil#release(Object)}. In this case you may need to use
40   * {@link ReferenceCountUtil#retain(Object)} if you pass the object to the next handler in the {@link ChannelPipeline}.
41   *
42   * <h3>Forward compatibility notice</h3>
43   * <p>
44   * Please keep in mind that {@link #channelRead0(ChannelHandlerContext, I)} will be renamed to
45   * {@code messageReceived(ChannelHandlerContext, I)} in 5.0.
46   * </p>
47   */
48  public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter {
49  
50      private final TypeParameterMatcher matcher;
51      private final boolean autoRelease;
52  
53      /**
54       * see {@link #SimpleChannelInboundHandler(boolean)} with {@code true} as boolean parameter.
55       */
56      protected SimpleChannelInboundHandler() {
57          this(true);
58      }
59  
60      /**
61       * Create a new instance which will try to detect the types to match out of the type parameter of the class.
62       *
63       * @param autoRelease   {@code true} if handled messages should be released automatically by passing them to
64       *                      {@link ReferenceCountUtil#release(Object)}.
65       */
66      protected SimpleChannelInboundHandler(boolean autoRelease) {
67          matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I");
68          this.autoRelease = autoRelease;
69      }
70  
71      /**
72       * see {@link #SimpleChannelInboundHandler(Class, boolean)} with {@code true} as boolean value.
73       */
74      protected SimpleChannelInboundHandler(Class<? extends I> inboundMessageType) {
75          this(inboundMessageType, true);
76      }
77  
78      /**
79       * Create a new instance
80       *
81       * @param inboundMessageType    The type of messages to match
82       * @param autoRelease           {@code true} if handled messages should be released automatically by passing them to
83       *                              {@link ReferenceCountUtil#release(Object)}.
84       */
85      protected SimpleChannelInboundHandler(Class<? extends I> inboundMessageType, boolean autoRelease) {
86          matcher = TypeParameterMatcher.get(inboundMessageType);
87          this.autoRelease = autoRelease;
88      }
89  
90      /**
91       * Returns {@code true} if the given message should be handled. If {@code false} it will be passed to the next
92       * {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
93       */
94      public boolean acceptInboundMessage(Object msg) throws Exception {
95          return matcher.match(msg);
96      }
97  
98      @Override
99      public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
100         boolean release = true;
101         try {
102             if (acceptInboundMessage(msg)) {
103                 @SuppressWarnings("unchecked")
104                 I imsg = (I) msg;
105                 channelRead0(ctx, imsg);
106             } else {
107                 release = false;
108                 ctx.fireChannelRead(msg);
109             }
110         } finally {
111             if (autoRelease && release) {
112                 ReferenceCountUtil.release(msg);
113             }
114         }
115     }
116 
117     /**
118      * <strong>Please keep in mind that this method will be renamed to
119      * {@code messageReceived(ChannelHandlerContext, I)} in 5.0.</strong>
120      *
121      * Is called for each message of type {@link I}.
122      *
123      * @param ctx           the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
124      *                      belongs to
125      * @param msg           the message to handle
126      * @throws Exception    is thrown if an error occurred
127      */
128     protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;
129 }