package org.opendaylight.controller.netconf.impl;
-import org.junit.Before;
-import org.junit.Test;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
-
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
-public class MessageHeaderTest {
-
- private NetconfMessageHeader header = null;
-
- @Before
- public void setUp() {
- this.header = new NetconfMessageHeader();
- }
+import org.junit.Test;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
+public class MessageHeaderTest {
@Test
public void testFromBytes() {
final byte[] raw = new byte[] { (byte) 0x0a, (byte) 0x23, (byte) 0x35, (byte) 0x38, (byte) 0x0a };
- this.header.fromBytes(raw);
- assertEquals(58, this.header.getLength());
+ NetconfMessageHeader header = NetconfMessageHeader.fromBytes(raw);
+ assertEquals(58, header.getLength());
}
@Test
public void testToBytes() {
- this.header.setLength(123);
+ NetconfMessageHeader header = new NetconfMessageHeader(123);
assertArrayEquals(new byte[] { (byte) 0x0a, (byte) 0x23, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x0a },
- this.header.toBytes());
+ header.toBytes());
}
}
import org.junit.Before;
import org.junit.Test;
import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.util.handler.ChunkedFramingMechanismEncoder;
import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
import org.opendaylight.controller.netconf.util.handler.NetconfMessageChunkDecoder;
enc.encode(null, msg, out);
int msgLength = out.readableBytes();
- int chunkCount = msgLength / NetconfMessageConstants.MAX_CHUNK_SIZE;
- if ((msgLength % NetconfMessageConstants.MAX_CHUNK_SIZE) != 0) {
+ int chunkCount = msgLength / ChunkedFramingMechanismEncoder.DEFAULT_CHUNK_SIZE;
+ if ((msgLength % ChunkedFramingMechanismEncoder.DEFAULT_CHUNK_SIZE) != 0) {
chunkCount++;
}
for (int i = 1; i <= chunkCount; i++) {
ByteBuf recievedOutbound = (ByteBuf) messages.poll();
- int exptHeaderLength = NetconfMessageConstants.MAX_CHUNK_SIZE;
+ int exptHeaderLength = ChunkedFramingMechanismEncoder.DEFAULT_CHUNK_SIZE;
if (i == chunkCount) {
- exptHeaderLength = msgLength - (NetconfMessageConstants.MAX_CHUNK_SIZE * (i - 1));
+ exptHeaderLength = msgLength - (ChunkedFramingMechanismEncoder.DEFAULT_CHUNK_SIZE * (i - 1));
byte[] eom = new byte[NetconfMessageConstants.endOfChunk.length];
recievedOutbound.getBytes(recievedOutbound.readableBytes() - NetconfMessageConstants.endOfChunk.length,
eom);
byte[] header = new byte[String.valueOf(exptHeaderLength).length()
+ NetconfMessageConstants.MIN_HEADER_LENGTH - 1];
recievedOutbound.getBytes(0, header);
- NetconfMessageHeader messageHeader = new NetconfMessageHeader();
- messageHeader.fromBytes(header);
+ NetconfMessageHeader messageHeader = NetconfMessageHeader.fromBytes(header);
assertEquals(exptHeaderLength, messageHeader.getLength());
testChunkChannel.writeInbound(recievedOutbound);
package org.opendaylight.controller.netconf.util.handler;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
-
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
+
+import com.google.common.base.Preconditions;
+
public class ChunkedFramingMechanismEncoder extends MessageToByteEncoder<ByteBuf> {
+ public static final int DEFAULT_CHUNK_SIZE = 8192;
+ public static final int MIN_CHUNK_SIZE = 128;
+ public static final int MAX_CHUNK_SIZE = 16 * 1024 * 1024;
- private NetconfMessageHeader messageHeader = new NetconfMessageHeader();
+ private final int chunkSize;
- private final static int MAX_CHUNK_SIZE = NetconfMessageConstants.MAX_CHUNK_SIZE;
+ public ChunkedFramingMechanismEncoder() {
+ this(DEFAULT_CHUNK_SIZE);
+ }
+
+ public ChunkedFramingMechanismEncoder(int chunkSize) {
+ Preconditions.checkArgument(chunkSize > MIN_CHUNK_SIZE);
+ Preconditions.checkArgument(chunkSize < MAX_CHUNK_SIZE);
+ this.chunkSize = chunkSize;
+ }
+
+ public final int getChunkSize() {
+ return chunkSize;
+ }
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
- while (msg.readableBytes() > MAX_CHUNK_SIZE) {
- ByteBuf chunk = Unpooled.buffer(MAX_CHUNK_SIZE);
- chunk.writeBytes(createChunkHeader(MAX_CHUNK_SIZE));
- chunk.writeBytes(msg.readBytes(MAX_CHUNK_SIZE));
+ while (msg.readableBytes() > chunkSize) {
+ ByteBuf chunk = Unpooled.buffer(chunkSize);
+ chunk.writeBytes(createChunkHeader(chunkSize));
+ chunk.writeBytes(msg.readBytes(chunkSize));
ctx.write(chunk);
}
out.writeBytes(createChunkHeader(msg.readableBytes()));
}
private ByteBuf createChunkHeader(int chunkSize) {
- messageHeader.setLength(chunkSize);
- return Unpooled.wrappedBuffer(messageHeader.toBytes());
+ return Unpooled.wrappedBuffer(NetconfMessageHeader.toBytes(chunkSize));
}
-
}
package org.opendaylight.controller.netconf.util.handler;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
-
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
-public class EOMFramingMechanismEncoder extends MessageToByteEncoder<ByteBuf> {
-
- private byte[] eom = NetconfMessageConstants.endOfMessage;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
+public class EOMFramingMechanismEncoder extends MessageToByteEncoder<ByteBuf> {
@Override
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
out.writeBytes(msg);
- out.writeBytes(eom);
+ out.writeBytes(NetconfMessageConstants.endOfMessage);
}
-
}
public static final byte[] endOfChunk = "\n##\n".getBytes(Charsets.UTF_8);
- public static final int MAX_CHUNK_SIZE = 1024; // bytes
-
public static final int MIN_HEADER_LENGTH = 4; // bytes
public static final int MAX_HEADER_LENGTH = 13; // bytes
package org.opendaylight.controller.netconf.util.messages;
+import java.nio.ByteBuffer;
+
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
-import java.nio.ByteBuffer;
-
/**
* Netconf message header is used only when chunked framing mechanism is
* supported. The header consists of only the length field.
*/
+@Deprecated
public final class NetconfMessageHeader {
-
- private long length;
-
// \n#<length>\n
- private static final byte[] headerBegin = new byte[] { (byte) 0x0a, (byte) 0x23 };
+ private static final byte[] HEADER_START = new byte[] { (byte) 0x0a, (byte) 0x23 };
+ private static final byte HEADER_END = (byte) 0x0a;
+ private final long length;
- private static final byte headerEnd = (byte) 0x0a;
-
- private boolean parsed = false;
-
- public NetconfMessageHeader() {
-
- }
-
- public NetconfMessageHeader fromBytes(final byte[] bytes) {
- // the length is variable therefore bytes between headerBegin and
- // headerEnd mark the length
- // the length should be only numbers and therefore easily parsed with
- // ASCII
- this.length = Long.parseLong(Charsets.US_ASCII.decode(
- ByteBuffer.wrap(bytes, headerBegin.length, bytes.length - headerBegin.length - 1)).toString());
- Preconditions.checkState(this.length < Integer.MAX_VALUE && this.length > 0);
- this.parsed = true;
- return this;
+ public NetconfMessageHeader(final long length) {
+ Preconditions.checkArgument(length < Integer.MAX_VALUE && length > 0);
+ this.length = length;
}
public byte[] toBytes() {
- final byte[] l = String.valueOf(this.length).getBytes(Charsets.US_ASCII);
- final byte[] h = new byte[headerBegin.length + l.length + 1];
- System.arraycopy(headerBegin, 0, h, 0, headerBegin.length);
- System.arraycopy(l, 0, h, headerBegin.length, l.length);
- System.arraycopy(new byte[] { headerEnd }, 0, h, headerBegin.length + l.length, 1);
- return h;
+ return toBytes(this.length);
}
// FIXME: improve precision to long
return (int) this.length;
}
- public void setLength(final int length) {
- this.length = length;
- }
+ public static NetconfMessageHeader fromBytes(final byte[] bytes) {
+ // the length is variable therefore bytes between headerBegin and
+ // headerEnd mark the length
+ // the length should be only numbers and therefore easily parsed with
+ // ASCII
+ long length = Long.parseLong(Charsets.US_ASCII.decode(
+ ByteBuffer.wrap(bytes, HEADER_START.length, bytes.length - HEADER_START.length - 1)).toString());
- /**
- * @return the parsed
- */
- public boolean isParsed() {
- return this.parsed;
+ return new NetconfMessageHeader(length);
}
- /**
- * @param parsed
- * the parsed to set
- */
- public void setParsed() {
- this.parsed = false;
+ public static byte[] toBytes(final long length) {
+ final byte[] l = String.valueOf(length).getBytes(Charsets.US_ASCII);
+ final byte[] h = new byte[HEADER_START.length + l.length + 1];
+ System.arraycopy(HEADER_START, 0, h, 0, HEADER_START.length);
+ System.arraycopy(l, 0, h, HEADER_START.length, l.length);
+ System.arraycopy(new byte[] { HEADER_END }, 0, h, HEADER_START.length + l.length, 1);
+ return h;
}
}