From 01c3fd3ace52032727861d342382a73890137e40 Mon Sep 17 00:00:00 2001 From: "Robert.Panzer" Date: Mon, 9 Mar 2015 11:32:40 +0100 Subject: [PATCH] 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. --- .../handler/codec/LengthFieldPrepender.java | 32 +++++++++++++++++++ .../codec/frame/LengthFieldPrependerTest.java | 20 ++++++++++++ 2 files changed, 52 insertions(+) diff --git a/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java b/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java index dd8e0e834c..2dbc0afcac 100644 --- a/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java +++ b/codec/src/main/java/io/netty/handler/codec/LengthFieldPrepender.java @@ -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 { + 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 { * 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 { "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 { 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); + } } diff --git a/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java b/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java index c02affe905..726761a931 100644 --- a/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java +++ b/codec/src/test/java/io/netty/handler/codec/frame/LengthFieldPrependerTest.java @@ -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()); + } + }