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}<{@link String}> {
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 }