Reworked Netconf framing mechanism, added chunked framing mechanism.
[controller.git] / opendaylight / netconf / netconf-util / src / main / java / org / opendaylight / controller / netconf / util / handler / NetconfMessageChunkDecoder.java
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageChunkDecoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageChunkDecoder.java
new file mode 100644 (file)
index 0000000..b713fcd
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.util.handler;
+
+import java.nio.charset.Charset;
+import java.util.List;
+
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
+import org.opendaylight.protocol.framework.DeserializerException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
+public class NetconfMessageChunkDecoder extends ByteToMessageDecoder {
+
+    private final static Logger logger = LoggerFactory.getLogger(NetconfMessageChunkDecoder.class);
+
+    @Override
+    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+        ByteBuf byteBufMsg = Unpooled.buffer(in.readableBytes());
+        int chunkSize = -1;
+        boolean isParsed = false;
+        while (in.isReadable()) {
+            try {
+                if (!isParsed) {
+                    chunkSize = readHeader(in);
+                    isParsed = true;
+                }
+                if (chunkSize != -1 && isParsed) {
+                    in.readBytes(byteBufMsg, chunkSize);
+                    logger.debug("Chunked data of size {} read.", chunkSize);
+                    isParsed = false;
+                } else {
+                    throw new DeserializerException("Unable to parse chunked data or header.");
+                }
+            } catch (Exception e) {
+                logger.debug("Failed to decode chunked message.", e);
+                this.exceptionCaught(ctx, e);
+            }
+        }
+        out.add(byteBufMsg);
+        isParsed = false;
+    }
+
+    private int readHeader(ByteBuf in) {
+        ByteBuf chunkSize = Unpooled.buffer(NetconfMessageHeader.MIN_HEADER_LENGTH,
+                NetconfMessageHeader.MAX_HEADER_LENGTH);
+        byte b = in.readByte();
+        if (b != 10)
+            return -1;
+        b = in.readByte();
+        if (b != 35)
+            return -1;
+        while ((b = in.readByte()) != 10) {
+            chunkSize.writeByte(b);
+        }
+        return Integer.parseInt(chunkSize.toString(Charset.forName("UTF-8")));
+    }
+
+}