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
c7827dc16a
commit
18443efeab
@ -18,7 +18,9 @@ package io.netty.handler.codec;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandler.Sharable;
|
import io.netty.channel.ChannelHandler.Sharable;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.util.internal.ObjectUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteOrder;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
@ -51,6 +53,7 @@ import java.util.List;
|
|||||||
@Sharable
|
@Sharable
|
||||||
public class LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf> {
|
public class LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf> {
|
||||||
|
|
||||||
|
private final ByteOrder byteOrder;
|
||||||
private final int lengthFieldLength;
|
private final int lengthFieldLength;
|
||||||
private final boolean lengthIncludesLengthFieldLength;
|
private final boolean lengthIncludesLengthFieldLength;
|
||||||
private final int lengthAdjustment;
|
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
|
* if {@code lengthFieldLength} is not 1, 2, 3, 4, or 8
|
||||||
*/
|
*/
|
||||||
public LengthFieldPrepender(int lengthFieldLength, int lengthAdjustment, boolean lengthIncludesLengthFieldLength) {
|
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 &&
|
if (lengthFieldLength != 1 && lengthFieldLength != 2 &&
|
||||||
lengthFieldLength != 3 && lengthFieldLength != 4 &&
|
lengthFieldLength != 3 && lengthFieldLength != 4 &&
|
||||||
lengthFieldLength != 8) {
|
lengthFieldLength != 8) {
|
||||||
@ -123,7 +148,9 @@ public class LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf> {
|
|||||||
"lengthFieldLength must be either 1, 2, 3, 4, or 8: " +
|
"lengthFieldLength must be either 1, 2, 3, 4, or 8: " +
|
||||||
lengthFieldLength);
|
lengthFieldLength);
|
||||||
}
|
}
|
||||||
|
ObjectUtil.checkNotNull(byteOrder, "byteOrder");
|
||||||
|
|
||||||
|
this.byteOrder = byteOrder;
|
||||||
this.lengthFieldLength = lengthFieldLength;
|
this.lengthFieldLength = lengthFieldLength;
|
||||||
this.lengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength;
|
this.lengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength;
|
||||||
this.lengthAdjustment = lengthAdjustment;
|
this.lengthAdjustment = lengthAdjustment;
|
||||||
@ -147,27 +174,27 @@ public class LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf> {
|
|||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"length does not fit into a byte: " + length);
|
"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;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (length >= 65536) {
|
if (length >= 65536) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"length does not fit into a short integer: " + length);
|
"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;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (length >= 16777216) {
|
if (length >= 16777216) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"length does not fit into a medium integer: " + length);
|
"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;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
out.add(ctx.alloc().buffer(4).writeInt(length));
|
out.add(ctx.alloc().buffer(4).order(byteOrder).writeInt(length));
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
out.add(ctx.alloc().buffer(8).writeLong(length));
|
out.add(ctx.alloc().buffer(8).order(byteOrder).writeLong(length));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("should not reach here");
|
throw new Error("should not reach here");
|
||||||
|
@ -24,6 +24,8 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static io.netty.buffer.Unpooled.*;
|
import static io.netty.buffer.Unpooled.*;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class LengthFieldPrependerTest {
|
public class LengthFieldPrependerTest {
|
||||||
@ -87,4 +89,25 @@ public class LengthFieldPrependerTest {
|
|||||||
// Expected
|
// 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