BUG-2459: reuse EXI Reader 12/13312/18
authorRobert Varga <rovarga@cisco.com>
Tue, 2 Dec 2014 15:21:14 +0000 (16:21 +0100)
committerRobert Varga <rovarga@cisco.com>
Thu, 18 Dec 2014 15:58:36 +0000 (16:58 +0100)
The reader performs an internal reset on each invocation of parse(), so
it can be freely reused as long as we guarantee there are no concurrent
invocations. Our decoder class is not Shared, so netty guarantees this.

Change-Id: Icd575988e48ca5252d6f6716f4e08f83b23c99ca
Signed-off-by: Robert Varga <rovarga@cisco.com>
opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/NetconfClientSessionTest.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/AbstractNetconfSession.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfEXIToMessageDecoder.java
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfEXIHandlersTest.java

index 103585cf7e330b1c3173c16a3feb23a6aa2b6ccc..2a3ecf2c04edd6106b7593a23b4e31239a040d14 100644 (file)
@@ -55,7 +55,7 @@ public class NetconfClientSessionTest {
 
         NetconfClientSession session = new NetconfClientSession(sessionListener, channel, sessId, caps);
         final NetconfMessageToEXIEncoder exiEncoder = NetconfMessageToEXIEncoder.create(codec);
-        final NetconfEXIToMessageDecoder exiDecoder = new NetconfEXIToMessageDecoder(codec);
+        final NetconfEXIToMessageDecoder exiDecoder = NetconfEXIToMessageDecoder.create(codec);
         session.addExiHandlers(exiDecoder, exiEncoder);
         session.stopExiCommunication();
 
index 13b72bc62c460ffdec7da204e2c9297c4914f7b7..a59b1a0d76bcdb01095e7c25e76377cd83ad019a 100644 (file)
@@ -132,9 +132,15 @@ public abstract class AbstractNetconfSession<S extends NetconfSession, L extends
             throw new IllegalStateException("Cannot instantiate encoder for options", e);
         }
 
-        final NetconfEXIToMessageDecoder exiDecoder = new NetconfEXIToMessageDecoder(exiCodec);
-        addExiHandlers(exiDecoder, exiEncoder);
+        final NetconfEXIToMessageDecoder exiDecoder;
+        try {
+            exiDecoder = NetconfEXIToMessageDecoder.create(exiCodec);
+        } catch (EXIOptionsException e) {
+            LOG.warn("Failed to instantiate EXI decodeer for {} on session {}", exiCodec, this, e);
+            throw new IllegalStateException("Cannot instantiate encoder for options", e);
+        }
 
+        addExiHandlers(exiDecoder, exiEncoder);
         LOG.debug("Session {} EXI handlers added to pipeline", this);
     }
 
index 77d33e18313d84b96202a9105453e7d06720ca3a..db265dee4096d10a141f876038603b52c7c10479 100644 (file)
@@ -33,11 +33,19 @@ public final class NetconfEXIToMessageDecoder extends ByteToMessageDecoder {
 
     private static final Logger LOG = LoggerFactory.getLogger(NetconfEXIToMessageDecoder.class);
     private static final SAXTransformerFactory FACTORY = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
+    /**
+     * This class is not marked as shared, so it can be attached to only a single channel,
+     * which means that {@link #decode(ChannelHandlerContext, ByteBuf, List)}
+     * cannot be invoked concurrently. Hence we can reuse the reader.
+     */
+    private final EXIReader reader;
 
-    private final NetconfEXICodec codec;
+    private NetconfEXIToMessageDecoder(final EXIReader reader) {
+        this.reader = Preconditions.checkNotNull(reader);
+    }
 
-    public NetconfEXIToMessageDecoder(final NetconfEXICodec codec) {
-        this.codec = Preconditions.checkNotNull(codec);
+    public static NetconfEXIToMessageDecoder create(final NetconfEXICodec codec) throws EXIOptionsException {
+        return new NetconfEXIToMessageDecoder(codec.getReader());
     }
 
     @Override
@@ -59,15 +67,15 @@ public final class NetconfEXIToMessageDecoder extends ByteToMessageDecoder {
             LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
         }
 
-        final EXIReader r = codec.getReader();
         final TransformerHandler handler = FACTORY.newTransformerHandler();
-        r.setContentHandler(handler);
+        reader.setContentHandler(handler);
 
         final DOMResult domResult = new DOMResult();
         handler.setResult(domResult);
 
         try (final InputStream is = new ByteBufInputStream(in)) {
-            r.parse(new InputSource(is));
+            // Performs internal reset before doing anything
+            reader.parse(new InputSource(is));
         }
 
         out.add(new NetconfMessage((Document) domResult.getNode()));
index 1972cb181fe0cfac7483a59ab06112717676f531..666da8ad46dc1a7d7241ae989ce26d24c7720ee6 100644 (file)
@@ -41,7 +41,7 @@ public class NetconfEXIHandlersTest {
     public void setUp() throws Exception {
         final NetconfEXICodec codec = new NetconfEXICodec(new EXIOptions());
         netconfMessageToEXIEncoder = NetconfMessageToEXIEncoder.create(codec);
-        netconfEXIToMessageDecoder = new NetconfEXIToMessageDecoder(codec);
+        netconfEXIToMessageDecoder = NetconfEXIToMessageDecoder.create(codec);
 
         msg = new NetconfMessage(XmlUtil.readXmlToDocument(msgAsString));
         this.msgAsExi = msgToExi(msgAsString, codec);