/*
 * 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:
/** * 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:
/** * 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:
/** * 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:
/** * 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:
/** * 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()); } }