package com.dianping.pigeon.remoting.netty.codec;
import com.dianping.pigeon.log.LoggerLoader;
import com.dianping.pigeon.remoting.common.codec.SerializerFactory;
import com.dianping.pigeon.remoting.common.domain.InvocationResponse;
import com.dianping.pigeon.remoting.common.domain.InvocationSerializable;
import com.dianping.pigeon.remoting.common.exception.SerializationException;
import com.dianping.pigeon.remoting.common.util.Constants;
import com.dianping.pigeon.remoting.provider.util.ProviderUtils;
import com.dianping.pigeon.log.Logger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferInputStream;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneDecoder;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
/**
* @author qi.yin
* 2016/06/21 上午9:55.
*/
public abstract class AbstractDecoder extends OneToOneDecoder {
private static final Logger logger = LoggerLoader.getLogger(AbstractDecoder.class);
@Override
public Object decode(ChannelHandlerContext ctx, Channel channel, Object msg)
throws Exception {
if (msg == null || !(msg instanceof CodecEvent)) {
return null;
}
CodecEvent codecEvent = (CodecEvent) msg;
if (codecEvent.isValid()) {
Object message = null;
if (codecEvent.isUnified()) {
message = _doDecode(ctx, channel, codecEvent);
codecEvent.setInvocation((InvocationSerializable) message);
} else {
message = doDecode(ctx, channel, codecEvent);
codecEvent.setInvocation((InvocationSerializable) message);
}
}
return codecEvent;
}
protected Object doDecode(ChannelHandlerContext ctx, Channel channel, CodecEvent codecEvent)
throws IOException {
Object msg = null;
ChannelBuffer buffer = codecEvent.getBuffer();
//head
buffer.skipBytes(CodecConstants.MEGIC_FIELD_LENGTH);
byte serialize = buffer.readByte();
Long sequence = null;
try {
//body length
int totalLength = buffer.readInt();
int frameLength = totalLength + CodecConstants.FRONT_LENGTH;
//body
int bodyLength = (totalLength - CodecConstants.TAIL_LENGTH);
ChannelBuffer frame = extractFrame(buffer, buffer.readerIndex(), bodyLength);
buffer.readerIndex(buffer.readerIndex() + bodyLength);
//tail
sequence = buffer.readLong();
buffer.skipBytes(CodecConstants.EXPAND_FIELD_LENGTH);
//deserialize
ChannelBufferInputStream is = new ChannelBufferInputStream(frame);
msg = deserialize(serialize, is);
//after
doAfter(channel, msg, serialize, frameLength, codecEvent.getReceiveTime());
} catch (Throwable e) {
SerializationException se = new SerializationException(e);
try {
if (sequence != null) {
doFailResponse(ctx, channel, ProviderUtils.createThrowableResponse(sequence.longValue(),
serialize, se));
}
logger.error("Deserialize failed. host:"
+ ((InetSocketAddress) channel.getRemoteAddress()).getAddress().getHostAddress()
+ "\n" + e.getMessage(), se);
} catch (Throwable t) {
logger.error("[doDecode] doFailResponse failed.", t);
}
}
return msg;
}
protected Object _doDecode(ChannelHandlerContext ctx, Channel channel, CodecEvent codecEvent) throws IOException {
Object msg = null;
ChannelBuffer buffer = codecEvent.getBuffer();
try {
//magic
buffer.skipBytes(CodecConstants._MEGIC_FIELD_LENGTH);
//version
buffer.readByte();
//serialize
byte serialize = (byte) (buffer.readByte() & 0x1f);
serialize = SerializerFactory.convertToSerialize(serialize);
int totalLength = buffer.readInt();
int frameLength = totalLength + CodecConstants._FRONT_LENGTH_;
ChannelBuffer frameBody = extractFrame(buffer, buffer.readerIndex(), totalLength);
buffer.readerIndex(buffer.readerIndex() + totalLength);
ChannelBufferInputStream is = new ChannelBufferInputStream(frameBody);
//deserialize
msg = deserialize(serialize, is);
//doAfter
doAfter(channel, msg, serialize, frameLength, codecEvent.getReceiveTime());
} catch (Throwable e) {
logger.error("Deserialize failed. host:"
+ ((InetSocketAddress) channel.getRemoteAddress()).getAddress().getHostAddress()
+ "\n" + e.getMessage(), e);
}
return msg;
}
protected ChannelBuffer extractFrame(ChannelBuffer buffer, int index, int length) {
ChannelBuffer frame = buffer.slice(index, length);
return frame;
}
private Object doAfter(Channel channel,
Object msg,
byte serialize,
int frameLength,
long receiveTime)
throws IOException {
if (msg instanceof InvocationSerializable) {
InvocationSerializable msg_ = (InvocationSerializable) msg;
int msgType = msg_.getMessageType();
if (msgType == Constants.MESSAGE_TYPE_SERVICE && frameLength > 0) {
msg_.setSize(frameLength);
}
msg_.setSerialize(serialize);
}
doInitMsg(msg, channel, receiveTime);
return msg;
}
protected abstract Object deserialize(byte serializerType, InputStream is);
protected abstract Object doInitMsg(Object message, Channel channel, long receiveTime);
protected abstract void doFailResponse(ChannelHandlerContext ctx, Channel channel, InvocationResponse response);
}