/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
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;
An encoder that prepends the length of the message. The length value is
prepended as a binary form.
For example, LengthFieldPrepender
(2) will encode the
following 12-bytes string:
+----------------+
| "HELLO, WORLD" |
+----------------+
into the following:
+--------+----------------+
+ 0x000C | "HELLO, WORLD" |
+--------+----------------+
If you turned on the lengthIncludesLengthFieldLength
flag in the constructor, the encoded data would look like the following (12 (original data) + 2 (prepended data) = 14 (0xE)): +--------+----------------+
+ 0x000E | "HELLO, WORLD" |
+--------+----------------+
/**
* An encoder that prepends the length of the message. The length value is
* prepended as a binary form.
* <p>
* For example, <tt>{@link LengthFieldPrepender}(2)</tt> will encode the
* following 12-bytes string:
* <pre>
* +----------------+
* | "HELLO, WORLD" |
* +----------------+
* </pre>
* into the following:
* <pre>
* +--------+----------------+
* + 0x000C | "HELLO, WORLD" |
* +--------+----------------+
* </pre>
* If you turned on the {@code lengthIncludesLengthFieldLength} flag in the
* constructor, the encoded data would look like the following
* (12 (original data) + 2 (prepended data) = 14 (0xE)):
* <pre>
* +--------+----------------+
* + 0x000E | "HELLO, WORLD" |
* +--------+----------------+
* </pre>
*/
@Sharable
public class LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf> {
private final ByteOrder byteOrder;
private final int lengthFieldLength;
private final boolean lengthIncludesLengthFieldLength;
private final int lengthAdjustment;
Creates a new instance.
Params: - lengthFieldLength – the length of the prepended length field.
Only 1, 2, 3, 4, and 8 are allowed.
Throws: - IllegalArgumentException – if
lengthFieldLength
is not 1, 2, 3, 4, or 8
/**
* Creates a new instance.
*
* @param lengthFieldLength the length of the prepended length field.
* Only 1, 2, 3, 4, and 8 are allowed.
*
* @throws IllegalArgumentException
* if {@code lengthFieldLength} is not 1, 2, 3, 4, or 8
*/
public LengthFieldPrepender(int lengthFieldLength) {
this(lengthFieldLength, false);
}
Creates a new instance.
Params: - lengthFieldLength – the length of the prepended length field.
Only 1, 2, 3, 4, and 8 are allowed.
- lengthIncludesLengthFieldLength – if
true
, the length of the prepended length field is added to the value of the prepended length field.
Throws: - IllegalArgumentException – if
lengthFieldLength
is not 1, 2, 3, 4, or 8
/**
* Creates a new instance.
*
* @param lengthFieldLength the length of the prepended length field.
* Only 1, 2, 3, 4, and 8 are allowed.
* @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(int lengthFieldLength, boolean lengthIncludesLengthFieldLength) {
this(lengthFieldLength, 0, lengthIncludesLengthFieldLength);
}
Creates a new instance.
Params: - lengthFieldLength – the length of the prepended length field.
Only 1, 2, 3, 4, and 8 are allowed.
- lengthAdjustment – the compensation value to add to the value
of the length field
Throws: - IllegalArgumentException – if
lengthFieldLength
is not 1, 2, 3, 4, or 8
/**
* Creates a new instance.
*
* @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
*
* @throws IllegalArgumentException
* if {@code lengthFieldLength} is not 1, 2, 3, 4, or 8
*/
public LengthFieldPrepender(int lengthFieldLength, int lengthAdjustment) {
this(lengthFieldLength, lengthAdjustment, false);
}
Creates a new instance.
Params: - lengthFieldLength – the length of the prepended length field.
Only 1, 2, 3, 4, and 8 are allowed.
- lengthAdjustment – the compensation value to add to the value
of the length field
- lengthIncludesLengthFieldLength – if
true
, the length of the prepended length field is added to the value of the prepended length field.
Throws: - IllegalArgumentException – if
lengthFieldLength
is not 1, 2, 3, 4, or 8
/**
* Creates a new instance.
*
* @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(int lengthFieldLength, int lengthAdjustment, boolean lengthIncludesLengthFieldLength) {
this(ByteOrder.BIG_ENDIAN, lengthFieldLength, lengthAdjustment, lengthIncludesLengthFieldLength);
}
Creates a new instance.
Params: - byteOrder – the
ByteOrder
of the length field - lengthFieldLength – the length of the prepended length field.
Only 1, 2, 3, 4, and 8 are allowed.
- lengthAdjustment – the compensation value to add to the value
of the length field
- lengthIncludesLengthFieldLength – if
true
, the length of the prepended length field is added to the value of the prepended length field.
Throws: - IllegalArgumentException – if
lengthFieldLength
is not 1, 2, 3, 4, or 8
/**
* 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) {
throw new IllegalArgumentException(
"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;
}
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
int length = msg.readableBytes() + lengthAdjustment;
if (lengthIncludesLengthFieldLength) {
length += lengthFieldLength;
}
if (length < 0) {
throw new IllegalArgumentException(
"Adjusted frame length (" + length + ") is less than zero");
}
switch (lengthFieldLength) {
case 1:
if (length >= 256) {
throw new IllegalArgumentException(
"length does not fit into a 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).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).order(byteOrder).writeMedium(length));
break;
case 4:
out.add(ctx.alloc().buffer(4).order(byteOrder).writeInt(length));
break;
case 8:
out.add(ctx.alloc().buffer(8).order(byteOrder).writeLong(length));
break;
default:
throw new Error("should not reach here");
}
out.add(msg.retain());
}
}