package xmg.quest.netty.core;
/**
* @author 作者 : xuminggang
* @version 创建时间:2020年6月8日 上午10:19:13
*
*/
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.ReferenceCounted;
import io.netty.util.internal.TypeParameterMatcher;
import java.util.List;
/**
* 一种{@link ChannelInboundHandlerAdapter} 适配器将一个消息解码为另一个消息.
* 比如下面是一种实现将一个{@link String}解码为一个{@link Integer},这个Integer代表字符串的长度。
*
* <pre>
* public class StringToIntegerDecoder extends
* {@link MessageToMessageDecoder}<{@link String}> {
*
* {@code @Override}
* public void decode({@link ChannelHandlerContext} ctx, {@link String} message,
* List<Object> out) throws {@link Exception} {
* out.add(message.length());
* }
* }
* </pre>
*
* 注意:如果消息类型是{@link ReferenceCounted},那么你需要对刚传递的消息调用 {@link ReferenceCounted#retain()}。
* {@link MessageToMessageDecoder}在解码消息时调用{@link ReferenceCounted#release()}也是需要的。
*
*/
public abstract class MessageToMessageDecoder<I> extends ChannelInboundHandlerAdapter {
private final TypeParameterMatcher matcher;
/**
* 创建一个新实例将尝试检测与类的类型参数匹配的类型
*/
protected MessageToMessageDecoder() {
matcher = TypeParameterMatcher.find(this, MessageToMessageDecoder.class, "I");
}
/**
* 创建一个新实例
*
* @param inboundMessageType 要匹配和解码的信息类型
*/
protected MessageToMessageDecoder(Class<? extends I> inboundMessageType) {
matcher = TypeParameterMatcher.get(inboundMessageType);
}
/**
* 返回 {@code true} 如果给定的消息应该被处理。
* 如果 {@code false} 将会传递给下一个{@link ChannelPipeline}的 {@link ChannelInboundHandler}。
*/
public boolean acceptInboundMessage(Object msg) throws Exception {
return matcher.match(msg);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
CodecOutputList out = CodecOutputList.newInstance();
try {
if (acceptInboundMessage(msg)) {
@SuppressWarnings("unchecked")
I cast = (I) msg;
try {
decode(ctx, cast, out);
} finally {
ReferenceCountUtil.release(cast);
}
} else {
out.add(msg);
}
} catch (DecoderException e) {
throw e;
} catch (Exception e) {
throw new DecoderException(e);
} finally {
int size = out.size();
for (int i = 0; i < size; i ++) {
ctx.fireChannelRead(out.getUnsafe(i));
}
out.recycle();
}
}
/**
* 将一个消息解码为另一个消息。该方法将会被每个可被解码器处理的写入消息调用。
*
* @param ctx 该 {@link MessageToMessageDecoder}所属的 {@link ChannelHandlerContext}
* @param msg 该消息解码为另一个
* @param out 解码后的消息会被加入到 {@link List}
* @throws Exception 如果错误发生抛出异常
*/
protected abstract void decode(ChannelHandlerContext ctx, I msg, List<Object> out) throws Exception;
}