From: Tony Tkacik Date: Tue, 18 Feb 2014 11:05:27 +0000 (+0000) Subject: Merge "Untangle the XML/Hello message decoders" X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~413 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=6958a923b6da4fb9e74c4050f8d38a7360e03f6d;hp=0a3054d11aba0d7d9e53ce9ea9c7ef866c11d683 Merge "Untangle the XML/Hello message decoders" --- diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfChunkAggregator.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfChunkAggregator.java index cee8e7133a..f7045c3b30 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfChunkAggregator.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfChunkAggregator.java @@ -46,6 +46,7 @@ public class NetconfChunkAggregator extends ByteToMessageDecoder { { final byte b = in.readByte(); if (b != '\n') { + logger.debug("Got byte {} while waiting for {}", b, (byte)'\n'); throw new IllegalStateException("Malformed chunk header encountered (byte 0)"); } @@ -56,6 +57,7 @@ public class NetconfChunkAggregator extends ByteToMessageDecoder { { final byte b = in.readByte(); if (b != '#') { + logger.debug("Got byte {} while waiting for {}", b, (byte)'#'); throw new IllegalStateException("Malformed chunk header encountered (byte 1)"); } @@ -66,6 +68,7 @@ public class NetconfChunkAggregator extends ByteToMessageDecoder { { final byte b = in.readByte(); if (b < '1' || b > '9') { + logger.debug("Got byte {} while waiting for {}-{}", b, (byte)'1', (byte)'9'); throw new IllegalStateException("Invalid chunk size encountered (byte 0)"); } @@ -82,6 +85,7 @@ public class NetconfChunkAggregator extends ByteToMessageDecoder { } if (b < '0' || b > '9') { + logger.debug("Got byte {} while waiting for {}-{}", b, (byte)'0', (byte)'9'); throw new IllegalStateException("Invalid chunk size encountered"); } @@ -89,6 +93,7 @@ public class NetconfChunkAggregator extends ByteToMessageDecoder { chunkSize += b - '0'; if (chunkSize > maxChunkSize) { + logger.debug("Parsed chunk size {}, maximum allowed is {}", chunkSize, maxChunkSize); throw new IllegalStateException("Maximum chunk size exceeded"); } break; diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java index 42586a5ecc..248871a7aa 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToHelloMessageDecoder.java @@ -7,6 +7,12 @@ */ package org.opendaylight.controller.netconf.util.handler; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.io.ByteArrayInputStream; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.List; @@ -14,8 +20,12 @@ import java.util.List; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage; import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader; +import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Document; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableList; @@ -25,7 +35,8 @@ import com.google.common.collect.ImmutableList; * {@link org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage} * . Used by netconf server to retrieve information about session metadata. */ -public class NetconfXMLToHelloMessageDecoder extends NetconfXMLToMessageDecoder { +public final class NetconfXMLToHelloMessageDecoder extends ByteToMessageDecoder { + private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToHelloMessageDecoder.class); private static final List POSSIBLE_ENDS = ImmutableList.of( new byte[] { ']', '\n' }, @@ -35,34 +46,46 @@ public class NetconfXMLToHelloMessageDecoder extends NetconfXMLToMessageDecoder new byte[] { '\r', '\n', '[' }, new byte[] { '\n', '[' }); - private String additionalHeaderCache; - @Override - protected byte[] preprocessMessageBytes(byte[] bytes) { - // Extract bytes containing header with additional metadata - - if (startsWithAdditionalHeader(bytes)) { - // Auth information containing username, ip address... extracted for monitoring - int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes); - if (endOfAuthHeader > -1) { - byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2); - additionalHeaderCache = additionalHeaderToString(additionalHeaderBytes); - bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length); - } + @VisibleForTesting + public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + if (in.readableBytes() == 0) { + LOG.debug("No more content in incoming buffer."); + return; } - return bytes; - } + in.markReaderIndex(); + try { + LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in)); + byte[] bytes = new byte[in.readableBytes()]; + in.readBytes(bytes); + + logMessage(bytes); + + // Extract bytes containing header with additional metadata + String additionalHeader = null; + if (startsWithAdditionalHeader(bytes)) { + // Auth information containing username, ip address... extracted for monitoring + int endOfAuthHeader = getAdditionalHeaderEndIndex(bytes); + if (endOfAuthHeader > -1) { + byte[] additionalHeaderBytes = Arrays.copyOfRange(bytes, 0, endOfAuthHeader + 2); + additionalHeader = additionalHeaderToString(additionalHeaderBytes); + bytes = Arrays.copyOfRange(bytes, endOfAuthHeader + 2, bytes.length); + } + } - @Override - protected void cleanUpAfterDecode() { - additionalHeaderCache = null; - } + Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes)); - @Override - protected NetconfMessage buildNetconfMessage(Document doc) { - return new NetconfHelloMessage(doc, additionalHeaderCache == null ? null - : NetconfHelloMessageAdditionalHeader.fromString(additionalHeaderCache)); + final NetconfMessage message; + if (additionalHeader != null) { + message = new NetconfHelloMessage(doc, NetconfHelloMessageAdditionalHeader.fromString(additionalHeader)); + } else { + message = new NetconfHelloMessage(doc); + } + out.add(message); + } finally { + in.discardReadBytes(); + } } private int getAdditionalHeaderEndIndex(byte[] bytes) { @@ -102,6 +125,12 @@ public class NetconfXMLToHelloMessageDecoder extends NetconfXMLToMessageDecoder return -1; } + + private void logMessage(byte[] bytes) { + String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString(); + LOG.debug("Parsing message \n{}", s); + } + private boolean startsWithAdditionalHeader(byte[] bytes) { for (byte[] possibleStart : POSSIBLE_STARTS) { int i = 0; diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java index b697edfb05..06a4dc7207 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/handler/NetconfXMLToMessageDecoder.java @@ -7,73 +7,32 @@ */ package org.opendaylight.controller.netconf.util.handler; -import java.io.ByteArrayInputStream; -import java.nio.ByteBuffer; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + import java.util.List; -import org.opendaylight.controller.netconf.api.NetconfDeserializerException; import org.opendaylight.controller.netconf.api.NetconfMessage; import org.opendaylight.controller.netconf.util.xml.XmlUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.Document; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Charsets; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; - -public class NetconfXMLToMessageDecoder extends ByteToMessageDecoder { +public final class NetconfXMLToMessageDecoder extends ByteToMessageDecoder { private static final Logger LOG = LoggerFactory.getLogger(NetconfXMLToMessageDecoder.class); @Override @VisibleForTesting public void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - if (in.readableBytes() == 0) { - LOG.debug("No more content in incoming buffer."); - return; - } - - in.markReaderIndex(); - try { + if (in.readableBytes() != 0) { LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in)); - byte[] bytes = new byte[in.readableBytes()]; - in.readBytes(bytes); - - logMessage(bytes); - - bytes = preprocessMessageBytes(bytes); - NetconfMessage message; - try { - Document doc = XmlUtil.readXmlToDocument(new ByteArrayInputStream(bytes)); - message = buildNetconfMessage(doc); - } catch (Exception e) { - throw new NetconfDeserializerException("Could not parse message from " + new String(bytes), e); - } - - out.add(message); - } finally { - in.discardReadBytes(); - cleanUpAfterDecode(); + out.add(new NetconfMessage(XmlUtil.readXmlToDocument(new ByteBufInputStream(in)))); + } else { + LOG.debug("No more content in incoming buffer."); } } - - protected void cleanUpAfterDecode() {} - - protected NetconfMessage buildNetconfMessage(Document doc) { - return new NetconfMessage(doc); - } - - protected byte[] preprocessMessageBytes(byte[] bytes) { - return bytes; - } - - private void logMessage(byte[] bytes) { - String s = Charsets.UTF_8.decode(ByteBuffer.wrap(bytes)).toString(); - LOG.debug("Parsing message \n{}", s); - } - } diff --git a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java index 6b7bffcd86..18830f85dd 100644 --- a/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java +++ b/opendaylight/netconf/netconf-util/src/test/java/org/opendaylight/controller/netconf/util/messages/NetconfMessageFactoryTest.java @@ -16,14 +16,13 @@ import java.util.List; import org.junit.Test; import org.opendaylight.controller.netconf.util.handler.NetconfXMLToHelloMessageDecoder; -import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder; import com.google.common.io.Files; public class NetconfMessageFactoryTest { @Test public void testAuth() throws Exception { - NetconfXMLToMessageDecoder parser = new NetconfXMLToHelloMessageDecoder(); + NetconfXMLToHelloMessageDecoder parser = new NetconfXMLToHelloMessageDecoder(); File authHelloFile = new File(getClass().getResource("/netconfMessages/client_hello_with_auth.xml").getFile()); final List out = new ArrayList<>();