Netconf message related constants moved to one place. 97/2097/4
authorMilos Fabian <milfabia@cisco.com>
Wed, 23 Oct 2013 09:09:59 +0000 (11:09 +0200)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 24 Oct 2013 14:41:04 +0000 (14:41 +0000)
Change-Id: Idcbf63f51d152779804aa54432366874088db332
Signed-off-by: Milos Fabian <milfabia@cisco.com>
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/handler/NetconfMessageAggregator.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageChunkDecoder.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageConstants.java [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageHeader.java

index 7e9318e0d69796eeaf4b54fe8080e7eef8ff395f..baf2d7d761373a4dfb00895eed62a4d16b0470ee 100644 (file)
@@ -10,82 +10,101 @@ package org.opendaylight.controller.netconf.impl;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
-import java.io.IOException;
+import java.util.Queue;
 
-import javax.xml.parsers.ParserConfigurationException;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.embedded.EmbeddedChannel;
 
-import org.custommonkey.xmlunit.XMLAssert;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
+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.messages.FramingMechanism;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.protocol.framework.DeserializerException;
-import org.opendaylight.protocol.framework.DocumentedException;
-import org.opendaylight.protocol.util.ByteArray;
-import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
+import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
+import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
 
 public class MessageParserTest {
 
-    private NetconfMessageFactory parser = null;
+    private NetconfMessage msg;
+    private NetconfMessageFactory msgFactory = new NetconfMessageFactory();
 
     @Before
-    public void setUp() {
-        this.parser = new NetconfMessageFactory();
+    public void setUp() throws Exception {
+        this.msg = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/getConfig.xml");
     }
 
     @Test
-    public void testPutEOM() throws IOException, SAXException, ParserConfigurationException {
-        final NetconfMessage msg = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/client_hello.xml");
-        final byte[] bytes = this.parser.put(msg);
-        assertArrayEquals(NetconfMessageFactory.endOfMessage, ByteArray.subByte(bytes, bytes.length
-                - NetconfMessageFactory.endOfMessage.length, NetconfMessageFactory.endOfMessage.length));
-    }
+    public void testChunkedFramingMechanismOnPipeline() throws Exception {
+        EmbeddedChannel testChunkChannel = new EmbeddedChannel(
+                FramingMechanismHandlerFactory.createHandler(FramingMechanism.CHUNK),
+                new ProtocolMessageEncoder<NetconfMessage>(msgFactory),
 
-    @Ignore
-    @Test
-    // TODO not working on WINDOWS
-    // arrays first differed at element [4]; expected:<49> but was:<53>
-    // at
-    // org.junit.internal.ComparisonCriteria.arrayEquals(ComparisonCriteria.java:52)
-    public void testPutChunk() throws IOException, SAXException, ParserConfigurationException {
-        final NetconfMessage msg = XmlFileLoader.xmlFileToNetconfMessage("netconfMessages/client_hello.xml");
-        this.parser.setFramingMechanism(FramingMechanism.CHUNK);
-        final byte[] bytes = this.parser.put(msg);
-        final byte[] header = new byte[] { (byte) 0x0a, (byte) 0x23 , (byte) 0x32, (byte) 0x31, (byte) 0x31, (byte) 0x0a};
-        assertArrayEquals(header, ByteArray.subByte(bytes, 0, header.length));
-        assertArrayEquals(NetconfMessageFactory.endOfChunk, ByteArray.subByte(bytes, bytes.length
-                - NetconfMessageFactory.endOfChunk.length, NetconfMessageFactory.endOfChunk.length));
-    }
+                new NetconfMessageAggregator(FramingMechanism.CHUNK), new NetconfMessageChunkDecoder(),
+                new ProtocolMessageDecoder<NetconfMessage>(msgFactory));
 
-    @Test
-    public void testParseEOM() throws IOException, SAXException, DeserializerException, DocumentedException,
-            ParserConfigurationException {
-        final Document msg = XmlFileLoader.xmlFileToDocument("netconfMessages/client_hello.xml");
-        final byte[] bytes = this.parser.put(new NetconfMessage(msg));
-        final Document doc = this.parser
-                .parse(ByteArray.subByte(bytes, 0, bytes.length - NetconfMessageFactory.endOfMessage.length))
-                .getDocument();
-        assertEquals(XmlUtil.toString(msg), XmlUtil.toString(doc));
-        XMLAssert.assertXMLEqual(msg, doc);
+        testChunkChannel.writeOutbound(this.msg);
+        Queue<Object> messages = testChunkChannel.outboundMessages();
+        assertFalse(messages.isEmpty());
+
+        int msgLength = this.msgFactory.put(this.msg).length;
+        int chunkCount = msgLength / NetconfMessageConstants.MAX_CHUNK_SIZE;
+        if ((msgLength % NetconfMessageConstants.MAX_CHUNK_SIZE) != 0) {
+            chunkCount++;
+        }
+        for (int i = 1; i <= chunkCount; i++) {
+            ByteBuf recievedOutbound = (ByteBuf) messages.poll();
+            int exptHeaderLength = NetconfMessageConstants.MAX_CHUNK_SIZE;
+            if (i == chunkCount) {
+                exptHeaderLength = msgLength - (NetconfMessageConstants.MAX_CHUNK_SIZE * (i - 1));
+                byte[] eom = new byte[NetconfMessageConstants.endOfChunk.length];
+                recievedOutbound.getBytes(recievedOutbound.readableBytes() - NetconfMessageConstants.endOfChunk.length,
+                        eom);
+                assertArrayEquals(NetconfMessageConstants.endOfChunk, 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);
+            assertEquals(exptHeaderLength, messageHeader.getLength());
+
+            testChunkChannel.writeInbound(recievedOutbound);
+        }
+        assertTrue(messages.isEmpty());
+
+        NetconfMessage receivedMessage = (NetconfMessage) testChunkChannel.readInbound();
+        assertNotNull(receivedMessage);
+        assertTrue(this.msg.getDocument().isEqualNode(receivedMessage.getDocument()));
     }
 
     @Test
-    public void testParseChunk() throws IOException, SAXException, DeserializerException, DocumentedException,
-            ParserConfigurationException {
-        final Document msg = XmlFileLoader.xmlFileToDocument("netconfMessages/client_hello.xml");
-        this.parser.setFramingMechanism(FramingMechanism.CHUNK);
-        final byte[] bytes = this.parser.put(new NetconfMessage(msg));
-        final Document doc = this.parser
-                .parse(ByteArray.subByte(bytes, 6, bytes.length - NetconfMessageFactory.endOfChunk.length - 6))
-                .getDocument();
-        assertEquals(XmlUtil.toString(msg), XmlUtil.toString(doc));
-        XMLAssert.assertXMLEqual(msg, doc);
-    }
+    public void testEOMFramingMechanismOnPipeline() throws Exception {
+        EmbeddedChannel testChunkChannel = new EmbeddedChannel(
+                FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM),
+                new ProtocolMessageEncoder<NetconfMessage>(msgFactory), new NetconfMessageAggregator(
+                        FramingMechanism.EOM), new ProtocolMessageDecoder<NetconfMessage>(msgFactory));
 
+        testChunkChannel.writeOutbound(this.msg);
+        ByteBuf recievedOutbound = (ByteBuf) testChunkChannel.readOutbound();
+
+        byte[] eom = new byte[NetconfMessageConstants.endOfMessage.length];
+        recievedOutbound.getBytes(recievedOutbound.readableBytes() - NetconfMessageConstants.endOfMessage.length, eom);
+        assertArrayEquals(NetconfMessageConstants.endOfMessage, eom);
+
+        testChunkChannel.writeInbound(recievedOutbound);
+        NetconfMessage receivedMessage = (NetconfMessage) testChunkChannel.readInbound();
+        assertNotNull(receivedMessage);
+        assertTrue(this.msg.getDocument().isEqualNode(receivedMessage.getDocument()));
+    }
 }
index 7f710c9f1981fe2feed007aa12cb716075254d23..d8dd7881653b466b24886da068f1d6bab529027b 100644 (file)
@@ -8,10 +8,8 @@
 
 package org.opendaylight.controller.netconf.util.handler;
 
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
 import org.opendaylight.controller.netconf.util.messages.NetconfMessageHeader;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
@@ -20,27 +18,25 @@ import io.netty.handler.codec.MessageToByteEncoder;
 
 public class ChunkedFramingMechanismEncoder extends MessageToByteEncoder<ByteBuf> {
 
-    private final static Logger logger = LoggerFactory.getLogger(ChunkedFramingMechanismEncoder.class);
-
     private NetconfMessageHeader messageHeader = new NetconfMessageHeader();
 
+    private final static int MAX_CHUNK_SIZE = NetconfMessageConstants.MAX_CHUNK_SIZE;
+
     @Override
     protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
-        while (msg.readableBytes() > NetconfMessageFactory.MAX_CHUNK_SIZE) {
-            ByteBuf chunk = Unpooled.buffer(NetconfMessageFactory.MAX_CHUNK_SIZE);
-            chunk.writeBytes(createChunkHeader(NetconfMessageFactory.MAX_CHUNK_SIZE));
-            chunk.writeBytes(msg.readBytes(NetconfMessageFactory.MAX_CHUNK_SIZE));
+        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));
             ctx.write(chunk);
         }
         out.writeBytes(createChunkHeader(msg.readableBytes()));
         out.writeBytes(msg.readBytes(msg.readableBytes()));
-        out.writeBytes(NetconfMessageFactory.endOfChunk);
-        logger.debug("Output message size is {}", out.readableBytes());
+        out.writeBytes(NetconfMessageConstants.endOfChunk);
     }
 
     private ByteBuf createChunkHeader(int chunkSize) {
         messageHeader.setLength(chunkSize);
-        logger.debug("Chunked data length is {}.", chunkSize);
         return Unpooled.wrappedBuffer(messageHeader.toBytes());
     }
 
index b8a933a011411fa8c46655682dfcac8790bfaa87..7ec5a8f8dcd6c7304b8e7f5edbf7d292acb70199 100644 (file)
@@ -8,7 +8,7 @@
 
 package org.opendaylight.controller.netconf.util.handler;
 
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandlerContext;
@@ -16,7 +16,7 @@ import io.netty.handler.codec.MessageToByteEncoder;
 
 public class EOMFramingMechanismEncoder extends MessageToByteEncoder<ByteBuf> {
 
-    private byte[] eom = NetconfMessageFactory.endOfMessage;
+    private byte[] eom = NetconfMessageConstants.endOfMessage;
 
     @Override
     protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
index 131c3d71a57c9df779302ca4ff352e10f53841e6..868ddbd99c37a07a6fd31198cd81fe01c654e662 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.controller.netconf.util.handler;
 import java.util.List;
 
 import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -23,11 +23,11 @@ public class NetconfMessageAggregator extends ByteToMessageDecoder {
 
     private final static Logger logger = LoggerFactory.getLogger(NetconfMessageAggregator.class);
 
-    private byte[] eom = NetconfMessageFactory.endOfMessage;
+    private byte[] eom = NetconfMessageConstants.endOfMessage;
 
     public NetconfMessageAggregator(FramingMechanism framingMechanism) {
         if (framingMechanism == FramingMechanism.CHUNK) {
-            eom = NetconfMessageFactory.endOfChunk;
+            eom = NetconfMessageConstants.endOfChunk;
         }
     }
 
@@ -41,7 +41,7 @@ public class NetconfMessageAggregator extends ByteToMessageDecoder {
             ByteBuf msg = in.readBytes(index);
             in.readBytes(eom.length);
             in.discardReadBytes();
-            logger.debug("Message is complete. {}", msg.readableBytes());
+            logger.debug("Message is complete.");
             out.add(msg);
         }
     }
index b713fcd7e3e5c5224fb9f481db83edda9721e661..39182263b6cd9e0c1067d347ad5839efb06281bf 100644 (file)
@@ -11,7 +11,7 @@ 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.controller.netconf.util.messages.NetconfMessageConstants;
 import org.opendaylight.protocol.framework.DeserializerException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -38,13 +38,12 @@ public class NetconfMessageChunkDecoder extends ByteToMessageDecoder {
                 }
                 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);
+                logger.error("Failed to decode chunked message.", e);
                 this.exceptionCaught(ctx, e);
             }
         }
@@ -53,8 +52,8 @@ public class NetconfMessageChunkDecoder extends ByteToMessageDecoder {
     }
 
     private int readHeader(ByteBuf in) {
-        ByteBuf chunkSize = Unpooled.buffer(NetconfMessageHeader.MIN_HEADER_LENGTH,
-                NetconfMessageHeader.MAX_HEADER_LENGTH);
+        ByteBuf chunkSize = Unpooled.buffer(NetconfMessageConstants.MIN_HEADER_LENGTH,
+                NetconfMessageConstants.MAX_HEADER_LENGTH);
         byte b = in.readByte();
         if (b != 10)
             return -1;
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
new file mode 100644 (file)
index 0000000..0d83a72
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.messages;
+
+import com.google.common.base.Charsets;
+
+public class NetconfMessageConstants {
+
+    public static final byte[] endOfMessage = "]]>]]>".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
+}
\ No newline at end of file
index f7a2eb54cbb6117e62a804f76869b79fca9c1803..0b6914ec2ae44f12f5c4ade5a9c9574c7b2a7de6 100644 (file)
@@ -10,9 +10,6 @@ package org.opendaylight.controller.netconf.util.messages;
 
 import com.google.common.base.Charsets;
 import com.google.common.base.Optional;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.ChannelHandler;
-import io.netty.handler.codec.DelimiterBasedFrameDecoder;
 import org.opendaylight.controller.netconf.api.NetconfDeserializerException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -30,7 +27,6 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
-import java.util.List;
 
 /**
  * NetconfMessageFactory for (de)serializing DOM documents.
@@ -39,14 +35,6 @@ public final class NetconfMessageFactory implements ProtocolMessageFactory<Netco
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfMessageFactory.class);
 
-    public static final byte[] endOfMessage = "]]>]]>".getBytes(Charsets.UTF_8);
-
-    public static final byte[] endOfChunk = "\n##\n".getBytes(Charsets.UTF_8);
-
-    public static final int MAX_CHUNK_SIZE = 1024; // Bytes
-
-    private FramingMechanism framing = FramingMechanism.EOM;
-
     private final Optional<String> clientId;
 
     public NetconfMessageFactory() {
@@ -57,10 +45,6 @@ public final class NetconfMessageFactory implements ProtocolMessageFactory<Netco
         this.clientId = clientId;
     }
 
-    public static ChannelHandler getDelimiterFrameDecoder() {
-        return new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Unpooled.copiedBuffer(endOfMessage));
-    }
-
     @Override
     public NetconfMessage parse(byte[] bytes) throws DeserializerException, DocumentedException {
         String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString();
@@ -89,52 +73,16 @@ public final class NetconfMessageFactory implements ProtocolMessageFactory<Netco
             Comment comment = netconfMessage.getDocument().createComment("clientId:" + clientId.get());
             netconfMessage.getDocument().appendChild(comment);
         }
-        byte[] bytes = (this.framing == FramingMechanism.EOM) ? this.putEOM(netconfMessage) : this
-                .putChunked(netconfMessage);
+        final ByteBuffer msgBytes = Charsets.UTF_8.encode(xmlToString(netconfMessage.getDocument()));
         String content = xmlToString(netconfMessage.getDocument());
 
         logger.trace("Putting message \n{}", content);
-        return bytes;
-    }
-
-    private byte[] putEOM(NetconfMessage msg) {
-        // create byte buffer from the String XML
-        // all Netconf messages are encoded using UTF-8
-        final ByteBuffer msgBytes = Charsets.UTF_8.encode(xmlToString(msg.getDocument()));
-        final ByteBuffer result = ByteBuffer.allocate(msgBytes.limit() + endOfMessage.length);
-        result.put(msgBytes);
-        // put end of message
-        result.put(endOfMessage);
-        return result.array();
-    }
-
-    private byte[] putChunked(NetconfMessage msg) {
-        final ByteBuffer msgBytes = Charsets.UTF_8.encode(xmlToString(msg.getDocument()));
-        final NetconfMessageHeader h = new NetconfMessageHeader();
-        if (msgBytes.limit() > MAX_CHUNK_SIZE)
-            logger.warn("Netconf message too long, should be split.");
-        h.setLength(msgBytes.limit());
-        final byte[] headerBytes = h.toBytes();
-        final ByteBuffer result = ByteBuffer.allocate(headerBytes.length + msgBytes.limit() + endOfChunk.length);
-        result.put(headerBytes);
-        result.put(msgBytes);
-        result.put(endOfChunk);
-        return result.array();
+        byte[] b = new byte[msgBytes.limit()];
+        msgBytes.get(b);
+        return b;
     }
 
     private String xmlToString(Document doc) {
         return XmlUtil.toString(doc, false);
     }
-
-    /**
-     * For Hello message the framing is always EOM, but the framing mechanism
-     * may change.
-     *
-     * @param fm
-     *            new framing mechanism
-     */
-    public void setFramingMechanism(final FramingMechanism fm) {
-        logger.debug("Framing mechanism changed to {}", fm);
-        this.framing = fm;
-    }
 }
index ccf7a3fbd250425a526d9a6761fcb373a4c7a532..4ea7df5da0f89358fa4e8c9e15784bb89ff22eb4 100644 (file)
@@ -27,10 +27,6 @@ public final class NetconfMessageHeader {
 
     private static final byte headerEnd = (byte) 0x0a;
 
-    public static final int MIN_HEADER_LENGTH = 4; // bytes
-
-    public static final int MAX_HEADER_LENGTH = 13; // bytes
-
     private boolean parsed = false;
 
     public NetconfMessageHeader() {