From: Robert Varga Date: Sat, 15 Feb 2014 22:21:51 +0000 (+0100) Subject: Cleanup framing mechanisms X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~417^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=195dbe7884c7338a8fe9b58765ca5665f4a6f78a Cleanup framing mechanisms This gets rid of pre-instantiated NetconfMessageHeader in favor of creating a static constructor method. Furthermore allow our output chunking to be variable and bump the default from 1K to 8K. The upper limit on chunk size is 16M. Change-Id: I0ab4405fc7d750cca5875049f03b053aa80037ef Signed-off-by: Robert Varga --- diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageHeaderTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageHeaderTest.java index aa3c5d4d9b..959e2ff144 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageHeaderTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageHeaderTest.java @@ -8,33 +8,24 @@ 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()); } } diff --git a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageParserTest.java b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageParserTest.java index 85bccba14f..0138cf2bcb 100644 --- a/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageParserTest.java +++ b/opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageParserTest.java @@ -22,6 +22,7 @@ import java.util.Queue; 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; @@ -59,15 +60,15 @@ public class MessageParserTest { 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); @@ -77,8 +78,7 @@ public class MessageParserTest { 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); diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ChunkedFramingMechanismEncoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ChunkedFramingMechanismEncoder.java index d8dd788165..f7d1ba2b7e 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ChunkedFramingMechanismEncoder.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ChunkedFramingMechanismEncoder.java @@ -8,26 +8,43 @@ 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 { + 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())); @@ -36,8 +53,6 @@ public class ChunkedFramingMechanismEncoder extends MessageToByteEncoder { - - private byte[] eom = NetconfMessageConstants.endOfMessage; +import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants; +public class EOMFramingMechanismEncoder extends MessageToByteEncoder { @Override protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception { out.writeBytes(msg); - out.writeBytes(eom); + out.writeBytes(NetconfMessageConstants.endOfMessage); } - } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageConstants.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageConstants.java index 0d83a72bd3..1a08f9063f 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageConstants.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageConstants.java @@ -16,8 +16,6 @@ public class NetconfMessageConstants { 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 diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageHeader.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageHeader.java index a61541b914..fa26455c98 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageHeader.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageHeader.java @@ -8,49 +8,29 @@ 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#\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 @@ -58,22 +38,23 @@ public final class NetconfMessageHeader { 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; } }