// Copyright (C) 2011 - Will Glozer. All rights reserved. package com.lambdaworks.redis.protocol; import java.nio.charset.Charset; import java.util.Collection; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.EncoderException; import io.netty.handler.codec.MessageToByteEncoder; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; /** * A netty {@link ChannelHandler} responsible for encoding commands. * * @author Mark Paluch */ @ChannelHandler.Sharable public class CommandEncoder extends MessageToByteEncoder<Object> { private static final InternalLogger logger = InternalLoggerFactory.getInstance(CommandEncoder.class); private final boolean traceEnabled = logger.isTraceEnabled(); private final boolean debugEnabled = logger.isDebugEnabled(); public CommandEncoder() { this(true); } public CommandEncoder(boolean preferDirect) { super(preferDirect); } @Override protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, Object msg, boolean preferDirect) throws Exception { if (msg instanceof Collection) { if (preferDirect) { return ctx.alloc().ioBuffer(((Collection) msg).size() * 16); } else { return ctx.alloc().heapBuffer(((Collection) msg).size() * 16); } } if (preferDirect) { return ctx.alloc().ioBuffer(); } else { return ctx.alloc().heapBuffer(); } } @Override @SuppressWarnings("unchecked") protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception { if (msg instanceof RedisCommand) { RedisCommand<?, ?, ?> command = (RedisCommand<?, ?, ?>) msg; encode(ctx, out, command); } if (msg instanceof Collection) { Collection<RedisCommand<?, ?, ?>> commands = (Collection<RedisCommand<?, ?, ?>>) msg; for (RedisCommand<?, ?, ?> command : commands) { encode(ctx, out, command); } } } private void encode(ChannelHandlerContext ctx, ByteBuf out, RedisCommand<?, ?, ?> command) { try { out.markWriterIndex(); command.encode(out); } catch (RuntimeException e) { out.resetWriterIndex(); command.completeExceptionally(new EncoderException( "Cannot encode command. Please close the connection as the connection state may be out of sync.", e)); } if (debugEnabled) { logger.debug("{} writing command {}", logPrefix(ctx.channel()), command); if (traceEnabled) { logger.trace("{} Sent: {}", logPrefix(ctx.channel()), out.toString(Charset.defaultCharset()).trim()); } } } private String logPrefix(Channel channel) { StringBuffer buffer = new StringBuffer(64); buffer.append('[').append(ChannelLogDescriptor.logDescriptor(channel)).append(']'); return buffer.toString(); } }