From 3a186f6f164122ab47f816b5761ef526f939f946 Mon Sep 17 00:00:00 2001 From: Milos Fabian Date: Wed, 23 Oct 2013 11:09:59 +0200 Subject: [PATCH] Netconf message related constants moved to one place. Change-Id: Idcbf63f51d152779804aa54432366874088db332 Signed-off-by: Milos Fabian --- .../netconf/impl/MessageParserTest.java | 129 ++++++++++-------- .../ChunkedFramingMechanismEncoder.java | 20 ++- .../handler/EOMFramingMechanismEncoder.java | 4 +- .../handler/NetconfMessageAggregator.java | 8 +- .../handler/NetconfMessageChunkDecoder.java | 9 +- .../messages/NetconfMessageConstants.java | 24 ++++ .../util/messages/NetconfMessageFactory.java | 60 +------- .../util/messages/NetconfMessageHeader.java | 4 - 8 files changed, 120 insertions(+), 138 deletions(-) create mode 100644 opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageConstants.java 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 7e9318e0d6..baf2d7d761 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 @@ -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(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(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 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(msgFactory), new NetconfMessageAggregator( + FramingMechanism.EOM), new ProtocolMessageDecoder(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())); + } } 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 7f710c9f19..d8dd788165 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,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 { - 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()); } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/EOMFramingMechanismEncoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/EOMFramingMechanismEncoder.java index b8a933a011..7ec5a8f8dc 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/EOMFramingMechanismEncoder.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/EOMFramingMechanismEncoder.java @@ -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 { - private byte[] eom = NetconfMessageFactory.endOfMessage; + private byte[] eom = NetconfMessageConstants.endOfMessage; @Override protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception { diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageAggregator.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageAggregator.java index 131c3d71a5..868ddbd99c 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageAggregator.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfMessageAggregator.java @@ -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); } } 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 index b713fcd7e3..39182263b6 100644 --- 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 @@ -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 index 0000000000..0d83a72bd3 --- /dev/null +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageConstants.java @@ -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 diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java index f7a2eb54cb..0b6914ec2a 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactory.java @@ -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 clientId; public NetconfMessageFactory() { @@ -57,10 +45,6 @@ public final class NetconfMessageFactory implements ProtocolMessageFactory 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; - } } 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 ccf7a3fbd2..4ea7df5da0 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 @@ -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() { -- 2.36.6