Add support for byte order to LengthFieldPrepender

Motivation:

While the LengthFieldBasedFrameDecoder supports a byte order the LengthFieldPrepender does not.
That means that I can simply add a LengthFieldBasedFrameDecoder with ByteOrder.LITTLE_ENDIAN to my pipeline
but have to write my own Encoder to write length fields in little endian byte order.

Modifications:

Added a constructor that takes a byte order and all other parameters.
All other constructors delegate to this one with ByteOrder.BIG_ENDIAN.
LengthFieldPrepender.encode() uses this byte order to write the length field.

Result:

LengthFieldPrepender will write the length field in the defined byte order.
This commit is contained in:
Robert.Panzer 2015-03-09 11:32:40 +01:00 committed by Norman Maurer
parent 6954f034fd
commit 01c3fd3ace
2 changed files with 52 additions and 0 deletions

View File

@ -18,7 +18,9 @@ package io.netty.handler.codec;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.ObjectUtil;
import java.nio.ByteOrder;
/**
* An encoder that prepends the length of the message. The length value is
@ -49,6 +51,7 @@ import io.netty.channel.ChannelHandlerContext;
@Sharable
public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
private final ByteOrder byteOrder;
private final int lengthFieldLength;
private final boolean lengthIncludesLengthFieldLength;
private final int lengthAdjustment;
@ -114,6 +117,28 @@ public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
* if {@code lengthFieldLength} is not 1, 2, 3, 4, or 8
*/
public LengthFieldPrepender(int lengthFieldLength, int lengthAdjustment, boolean lengthIncludesLengthFieldLength) {
this(ByteOrder.BIG_ENDIAN, lengthFieldLength, lengthAdjustment, lengthIncludesLengthFieldLength);
}
/**
* Creates a new instance.
*
* @param byteOrder the {@link ByteOrder} of the length field
* @param lengthFieldLength the length of the prepended length field.
* Only 1, 2, 3, 4, and 8 are allowed.
* @param lengthAdjustment the compensation value to add to the value
* of the length field
* @param lengthIncludesLengthFieldLength
* if {@code true}, the length of the prepended
* length field is added to the value of the
* prepended length field.
*
* @throws IllegalArgumentException
* if {@code lengthFieldLength} is not 1, 2, 3, 4, or 8
*/
public LengthFieldPrepender(
ByteOrder byteOrder, int lengthFieldLength,
int lengthAdjustment, boolean lengthIncludesLengthFieldLength) {
if (lengthFieldLength != 1 && lengthFieldLength != 2 &&
lengthFieldLength != 3 && lengthFieldLength != 4 &&
lengthFieldLength != 8) {
@ -121,7 +146,9 @@ public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
"lengthFieldLength must be either 1, 2, 3, 4, or 8: " +
lengthFieldLength);
}
ObjectUtil.checkNotNull(byteOrder, "byteOrder");
this.byteOrder = byteOrder;
this.lengthFieldLength = lengthFieldLength;
this.lengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength;
this.lengthAdjustment = lengthAdjustment;
@ -173,4 +200,9 @@ public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
out.writeBytes(msg, msg.readerIndex(), msg.readableBytes());
}
@Override
protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception {
return super.allocateBuffer(ctx, msg, preferDirect).order(byteOrder);
}
}

View File

@ -25,6 +25,8 @@ import org.junit.Test;
import static io.netty.buffer.Unpooled.*;
import static org.hamcrest.core.Is.*;
import java.nio.ByteOrder;
import static org.junit.Assert.*;
public class LengthFieldPrependerTest {
@ -73,4 +75,22 @@ public class LengthFieldPrependerTest {
// Expected
}
}
@Test
public void testPrependLengthInLittleEndian() throws Exception {
final EmbeddedChannel ch = new EmbeddedChannel(new LengthFieldPrepender(ByteOrder.LITTLE_ENDIAN, 4, 0, false));
ch.writeOutbound(msg);
ByteBuf buf = (ByteBuf) ch.readOutbound();
assertEquals(5, buf.readableBytes());
byte[] writtenBytes = new byte[buf.readableBytes()];
buf.getBytes(0, writtenBytes);
assertEquals(1, writtenBytes[0]);
assertEquals(0, writtenBytes[1]);
assertEquals(0, writtenBytes[2]);
assertEquals(0, writtenBytes[3]);
assertEquals('A', writtenBytes[4]);
buf.release();
assertFalse("The channel must have been completely read", ch.finish());
}
}