package edu.uw.zookeeper.netty; import static com.google.common.base.Preconditions.checkNotNull; import java.io.IOException; import java.util.List; import org.apache.logging.log4j.Logger; import com.google.common.base.Optional; import edu.uw.zookeeper.net.Decoder; import edu.uw.zookeeper.net.LoggingMarker; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.ByteToMessageDecoder; public class DecoderHandler extends ByteToMessageDecoder { public static ChannelPipeline toPipeline( DecoderHandler handler, ChannelPipeline pipeline) { return pipeline.addFirst(DecoderHandler.class.getName(), handler); } public static DecoderHandler fromPipeline(ChannelPipeline pipeline) { // it seems that get by name may be faster than by class return (DecoderHandler) pipeline.get(DecoderHandler.class.getName()); } public static DecoderHandler withDecoder( Decoder<? extends Optional<?>, ?> decoder, Logger logger) { return new DecoderHandler(decoder, logger); } private final Logger logger; private final Decoder<? extends Optional<?>, ?> decoder; protected DecoderHandler( Decoder<? extends Optional<?>, ?> decoder, Logger logger) { super(); this.logger = checkNotNull(logger); this.decoder = checkNotNull(decoder); } @Override public int actualReadableBytes() { // TODO: check that this is safe to expose... return super.actualReadableBytes(); } @Override protected void decode(ChannelHandlerContext ctx, ByteBuf input, List<Object> output) throws IOException { if (input.isReadable()) { Optional<?> decoded = decoder.decode(input); if (decoded.isPresent()) { Object message = decoded.get(); if (logger.isTraceEnabled()) { logger.trace(LoggingMarker.NET_MARKER.get(), "DECODED {} ({})", message, ctx.channel()); } output.add(message); } } } }