Cleanup framing mechanisms 75/5375/1
authorRobert Varga <rovarga@cisco.com>
Sat, 15 Feb 2014 22:21:51 +0000 (23:21 +0100)
committerRobert Varga <rovarga@cisco.com>
Tue, 18 Feb 2014 05:22:35 +0000 (06:22 +0100)
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 <rovarga@cisco.com>
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageHeaderTest.java
opendaylight/netconf/netconf-impl/src/test/java/org/opendaylight/controller/netconf/impl/MessageParserTest.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/ChunkedFramingMechanismEncoder.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/EOMFramingMechanismEncoder.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageConstants.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageHeader.java

index aa3c5d4d9ba539167dd08aa3117dc45fbb7cc9b8..959e2ff144810c2017131e8041229e86b1cabd64 100644 (file)
@@ -8,33 +8,24 @@
 
 package org.opendaylight.controller.netconf.impl;
 
 
 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;
 
 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 };
     @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() {
     }
 
     @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 },
         assertArrayEquals(new byte[] { (byte) 0x0a, (byte) 0x23, (byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x0a },
-                this.header.toBytes());
+                header.toBytes());
     }
 }
     }
 }
index 85bccba14ff01da5d559ad83ff6080e0ef5b6b42..0138cf2bcb09271c32edc96796f03327d342889a 100644 (file)
@@ -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.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;
 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();
 
         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();
             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) {
             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[] 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);
             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);
             assertEquals(exptHeaderLength, messageHeader.getLength());
 
             testChunkChannel.writeInbound(recievedOutbound);
index d8dd7881653b466b24886da068f1d6bab529027b..f7d1ba2b7e3b378f964ddbf68c87db567ffd837a 100644 (file)
@@ -8,26 +8,43 @@
 
 package org.opendaylight.controller.netconf.util.handler;
 
 
 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 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 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 {
 
     @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()));
             ctx.write(chunk);
         }
         out.writeBytes(createChunkHeader(msg.readableBytes()));
@@ -36,8 +53,6 @@ public class ChunkedFramingMechanismEncoder extends MessageToByteEncoder<ByteBuf
     }
 
     private ByteBuf createChunkHeader(int chunkSize) {
     }
 
     private ByteBuf createChunkHeader(int chunkSize) {
-        messageHeader.setLength(chunkSize);
-        return Unpooled.wrappedBuffer(messageHeader.toBytes());
+        return Unpooled.wrappedBuffer(NetconfMessageHeader.toBytes(chunkSize));
     }
     }
-
 }
 }
index 7ec5a8f8dcd6c7304b8e7f5edbf7d292acb70199..383cebb04f680d2d7a352d1e18a6dcb8f81c3b90 100644 (file)
@@ -8,20 +8,16 @@
 
 package org.opendaylight.controller.netconf.util.handler;
 
 
 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;
 
 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);
     @Override
     protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
         out.writeBytes(msg);
-        out.writeBytes(eom);
+        out.writeBytes(NetconfMessageConstants.endOfMessage);
     }
     }
-
 }
 }
index 0d83a72bd39b9f8e7fecdd7d9eb39d87f18ed6ef..1a08f9063fdad0d526c483e10d0a83cce3acbb62 100644 (file)
@@ -16,8 +16,6 @@ public class NetconfMessageConstants {
 
     public static final byte[] endOfChunk = "\n##\n".getBytes(Charsets.UTF_8);
 
 
     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
     public static final int MIN_HEADER_LENGTH = 4; // bytes
 
     public static final int MAX_HEADER_LENGTH = 13; // bytes
index a61541b9146556f7b71e0766e0c8b99a65a81fd9..fa26455c9875d7245429ef72f2ce11b57c56acac 100644 (file)
@@ -8,49 +8,29 @@
 
 package org.opendaylight.controller.netconf.util.messages;
 
 
 package org.opendaylight.controller.netconf.util.messages;
 
+import java.nio.ByteBuffer;
+
 import com.google.common.base.Charsets;
 import com.google.common.base.Preconditions;
 
 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.
  */
 /**
  * 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 {
 public final class NetconfMessageHeader {
-
-    private long length;
-
     // \n#<length>\n
     // \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() {
     }
 
     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
     }
 
     // FIXME: improve precision to long
@@ -58,22 +38,23 @@ public final class NetconfMessageHeader {
         return (int) this.length;
     }
 
         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;
     }
 }
     }
 }