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.netty.handler.codec; 17 18 import io.netty.channel.ChannelHandlerContext; 19 import io.netty.channel.ChannelInboundHandler; 20 import io.netty.channel.ChannelInboundHandlerAdapter; 21 import io.netty.channel.ChannelPipeline; 22 import io.netty.util.ReferenceCountUtil; 23 import io.netty.util.ReferenceCounted; 24 import io.netty.util.internal.TypeParameterMatcher; 25 26 import java.util.List; 27 28 /** 29 * {@link ChannelInboundHandlerAdapter} which decodes from one message to an other message. 30 * 31 * 32 * For example here is an implementation which decodes a {@link String} to an {@link Integer} which represent 33 * the length of the {@link String}. 34 * 35 * <pre> 36 * public class StringToIntegerDecoder extends 37 * {@link MessageToMessageDecoder}<{@link String}> { 38 * 39 * {@code @Override} 40 * public void decode({@link ChannelHandlerContext} ctx, {@link String} message, 41 * List<Object> out) throws {@link Exception} { 42 * out.add(message.length()); 43 * } 44 * } 45 * </pre> 46 * 47 * Be aware that you need to call {@link ReferenceCounted#retain()} on messages that are just passed through if they 48 * are of type {@link ReferenceCounted}. This is needed as the {@link MessageToMessageDecoder} will call 49 * {@link ReferenceCounted#release()} on decoded messages. 50 * 51 */ 52 public abstract class MessageToMessageDecoder<I> extends ChannelInboundHandlerAdapter { 53 54 private final TypeParameterMatcher matcher; 55 56 /** 57 * Create a new instance which will try to detect the types to match out of the type parameter of the class. 58 */ 59 protected MessageToMessageDecoder() { 60 matcher = TypeParameterMatcher.find(this, MessageToMessageDecoder.class, "I"); 61 } 62 63 /** 64 * Create a new instance 65 * 66 * @param inboundMessageType The type of messages to match and so decode 67 */ 68 protected MessageToMessageDecoder(Class<? extends I> inboundMessageType) { 69 matcher = TypeParameterMatcher.get(inboundMessageType); 70 } 71 72 /** 73 * Returns {@code true} if the given message should be handled. If {@code false} it will be passed to the next 74 * {@link ChannelInboundHandler} in the {@link ChannelPipeline}. 75 */ 76 public boolean acceptInboundMessage(Object msg) throws Exception { 77 return matcher.match(msg); 78 } 79 80 @Override 81 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 82 CodecOutputList out = CodecOutputList.newInstance(); 83 try { 84 if (acceptInboundMessage(msg)) { 85 @SuppressWarnings("unchecked") 86 I cast = (I) msg; 87 try { 88 decode(ctx, cast, out); 89 } finally { 90 ReferenceCountUtil.release(cast); 91 } 92 } else { 93 out.add(msg); 94 } 95 } catch (DecoderException e) { 96 throw e; 97 } catch (Exception e) { 98 throw new DecoderException(e); 99 } finally { 100 try { 101 int size = out.size(); 102 for (int i = 0; i < size; i++) { 103 ctx.fireChannelRead(out.getUnsafe(i)); 104 } 105 } finally { 106 out.recycle(); 107 } 108 } 109 } 110 111 /** 112 * Decode from one message to an other. This method will be called for each written message that can be handled 113 * by this decoder. 114 * 115 * @param ctx the {@link ChannelHandlerContext} which this {@link MessageToMessageDecoder} belongs to 116 * @param msg the message to decode to an other one 117 * @param out the {@link List} to which decoded messages should be added 118 * @throws Exception is thrown if an error occurs 119 */ 120 protected abstract void decode(ChannelHandlerContext ctx, I msg, List<Object> out) throws Exception; 121 }