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:
parent
63859a550f
commit
08b1438e7b
@ -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;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@ -51,6 +53,7 @@ import java.util.List;
|
||||
@Sharable
|
||||
public class LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf> {
|
||||
|
||||
private final ByteOrder byteOrder;
|
||||
private final int lengthFieldLength;
|
||||
private final boolean lengthIncludesLengthFieldLength;
|
||||
private final int lengthAdjustment;
|
||||
@ -116,6 +119,28 @@ public class LengthFieldPrepender extends MessageToMessageEncoder<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) {
|
||||
@ -123,7 +148,9 @@ public class LengthFieldPrepender extends MessageToMessageEncoder<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;
|
||||
@ -147,27 +174,27 @@ public class LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf> {
|
||||
throw new IllegalArgumentException(
|
||||
"length does not fit into a byte: " + length);
|
||||
}
|
||||
out.add(ctx.alloc().buffer(1).writeByte((byte) length));
|
||||
out.add(ctx.alloc().buffer(1).order(byteOrder).writeByte((byte) length));
|
||||
break;
|
||||
case 2:
|
||||
if (length >= 65536) {
|
||||
throw new IllegalArgumentException(
|
||||
"length does not fit into a short integer: " + length);
|
||||
}
|
||||
out.add(ctx.alloc().buffer(2).writeShort((short) length));
|
||||
out.add(ctx.alloc().buffer(2).order(byteOrder).writeShort((short) length));
|
||||
break;
|
||||
case 3:
|
||||
if (length >= 16777216) {
|
||||
throw new IllegalArgumentException(
|
||||
"length does not fit into a medium integer: " + length);
|
||||
}
|
||||
out.add(ctx.alloc().buffer(3).writeMedium(length));
|
||||
out.add(ctx.alloc().buffer(3).order(byteOrder).writeMedium(length));
|
||||
break;
|
||||
case 4:
|
||||
out.add(ctx.alloc().buffer(4).writeInt(length));
|
||||
out.add(ctx.alloc().buffer(4).order(byteOrder).writeInt(length));
|
||||
break;
|
||||
case 8:
|
||||
out.add(ctx.alloc().buffer(8).writeLong(length));
|
||||
out.add(ctx.alloc().buffer(8).order(byteOrder).writeLong(length));
|
||||
break;
|
||||
default:
|
||||
throw new Error("should not reach here");
|
||||
|
@ -24,6 +24,8 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static io.netty.buffer.Unpooled.*;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class LengthFieldPrependerTest {
|
||||
@ -87,4 +89,25 @@ 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 = ch.readOutbound();
|
||||
assertEquals(4, 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]);
|
||||
buf.release();
|
||||
|
||||
buf = ch.readOutbound();
|
||||
assertSame(buf, msg);
|
||||
buf.release();
|
||||
assertFalse("The channel must have been completely read", ch.finish());
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user