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 * 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.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 public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter {
43
44 private final TypeParameterMatcher matcher;
45 private final boolean autoRelease;
46
47 /**
48 * see {@link #SimpleChannelInboundHandler(boolean)} with {@code true} as boolean parameter.
49 */
50 protected SimpleChannelInboundHandler() {
51 this(true);
52 }
53
54 /**
55 * Create a new instance which will try to detect the types to match out of the type parameter of the class.
56 *
57 * @param autoRelease {@code true} if handled messages should be released automatically by passing them to
58 * {@link ReferenceCountUtil#release(Object)}.
59 */
60 protected SimpleChannelInboundHandler(boolean autoRelease) {
61 matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I");
62 this.autoRelease = autoRelease;
63 }
64
65 /**
66 * see {@link #SimpleChannelInboundHandler(Class, boolean)} with {@code true} as boolean value.
67 */
68 protected SimpleChannelInboundHandler(Class<? extends I> inboundMessageType) {
69 this(inboundMessageType, true);
70 }
71
72 /**
73 * Create a new instance
74 *
75 * @param inboundMessageType The type of messages to match
76 * @param autoRelease {@code true} if handled messages should be released automatically by passing them to
77 * {@link ReferenceCountUtil#release(Object)}.
78 */
79 protected SimpleChannelInboundHandler(Class<? extends I> inboundMessageType, boolean autoRelease) {
80 matcher = TypeParameterMatcher.get(inboundMessageType);
81 this.autoRelease = autoRelease;
82 }
83
84 /**
85 * Returns {@code true} if the given message should be handled. If {@code false} it will be passed to the next
86 * {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
87 */
88 public boolean acceptInboundMessage(Object msg) throws Exception {
89 return matcher.match(msg);
90 }
91
92 @Override
93 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
94 boolean release = true;
95 try {
96 if (acceptInboundMessage(msg)) {
97 @SuppressWarnings("unchecked")
98 I imsg = (I) msg;
99 channelRead0(ctx, imsg);
100 } else {
101 release = false;
102 ctx.fireChannelRead(msg);
103 }
104 } finally {
105 if (autoRelease && release) {
106 ReferenceCountUtil.release(msg);
107 }
108 }
109 }
110
111 /**
112 * Is called for each message of type {@link I}.
113 *
114 * @param ctx the {@link ChannelHandlerContext} which this {@link SimpleChannelInboundHandler}
115 * belongs to
116 * @param msg the message to handle
117 * @throws Exception is thrown if an error occurred
118 */
119 protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;
120 }