/** * */ package fastdfs.client; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.timeout.IdleStateEvent; import io.netty.util.AttributeKey; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.UndeclaredThrowableException; import java.util.List; final class FastdfsHandler extends ByteToMessageDecoder { static final AttributeKey<FastdfsOperation<?>> OPERATION_KEY = AttributeKey.newInstance("fastdfsOperation"); @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { FastdfsOperation<?> operation = ctx.channel().attr(OPERATION_KEY).get(); if (null != operation) { operation.await(in); return; } if (in.readableBytes() <= 0) { return; } throw new FastdfsDataOverflowException( String.format( "fastdfs channel %s remain %s data bytes, but there is not operation await.", ctx.channel(), in.readableBytes() ) ); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { FastdfsOperation<?> operation = ctx.channel().attr(OPERATION_KEY).get(); // read idle event. if (evt == IdleStateEvent.FIRST_READER_IDLE_STATE_EVENT || evt == IdleStateEvent.READER_IDLE_STATE_EVENT) { if (null != operation) { throw new FastdfsReadTimeoutException( String.format( "execute %s read timeout.", operation ) ); } } // all idle event. if (evt == IdleStateEvent.FIRST_ALL_IDLE_STATE_EVENT || evt == IdleStateEvent.ALL_IDLE_STATE_EVENT) { throw new FastdfsTimeoutException("fastdfs channel was idle timeout."); } } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { super.channelInactive(ctx); FastdfsOperation<?> operation = ctx.channel().attr(OPERATION_KEY).get(); if (null == operation) { return; } operation.caught(new FastdfsException("channel closed.")); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { FastdfsOperation<?> operation = ctx.channel().attr(OPERATION_KEY).get(); if (null != operation) { operation.caught(translateException(cause)); } else ctx.close(); } private Throwable translateException(Throwable cause) { if (cause instanceof FastdfsException) { return cause; } Throwable unwrap = cause; for (; ; ) { if (unwrap instanceof InvocationTargetException) { unwrap = ((InvocationTargetException) unwrap).getTargetException(); continue; } if (unwrap instanceof UndeclaredThrowableException) { unwrap = ((UndeclaredThrowableException) unwrap).getUndeclaredThrowable(); continue; } break; } return new FastdfsException("fastdfs operation error.", unwrap); } }