import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
-import io.netty.handler.codec.ByteToMessageDecoder;
-import io.netty.handler.codec.MessageToByteEncoder;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.opendaylight.netconf.api.NetconfExiSession;
import org.opendaylight.netconf.api.NetconfSessionListener;
import org.opendaylight.netconf.api.messages.NetconfMessage;
import org.opendaylight.netconf.api.xml.XmlElement;
import org.opendaylight.netconf.codec.MessageDecoder;
import org.opendaylight.netconf.codec.MessageEncoder;
-import org.opendaylight.netconf.nettyutil.handler.EXIMessageDecoder;
-import org.opendaylight.netconf.nettyutil.handler.EXIMessageEncoder;
import org.opendaylight.netconf.nettyutil.handler.NetconfEXICodec;
import org.opendaylight.netconf.nettyutil.handler.exi.EXIParameters;
import org.opendaylight.netconf.shaded.exificient.core.exceptions.EXIException;
}
final var exiCodec = NetconfEXICodec.forParameters(exiParams);
- final var exiEncoder = EXIMessageEncoder.create(exiCodec);
- final EXIMessageDecoder exiDecoder;
+ final var exiEncoder = exiCodec.newMessageEncoder();
+ final MessageDecoder exiDecoder;
try {
- exiDecoder = EXIMessageDecoder.create(exiCodec);
+ exiDecoder = exiCodec.newMessageDecoder();
} catch (EXIException e) {
LOG.warn("Failed to instantiate EXI decodeer for {} on session {}", exiCodec, this, e);
throw new IllegalStateException("Cannot instantiate encoder for options", e);
* @param decoder EXI decoder
* @param encoder EXI encoder
*/
- protected abstract void addExiHandlers(ByteToMessageDecoder decoder, MessageToByteEncoder<NetconfMessage> encoder);
+ @NonNullByDefault
+ protected abstract void addExiHandlers(MessageDecoder decoder, MessageEncoder encoder);
protected final void replaceMessageDecoder(final ChannelHandler handler) {
replaceChannelHandler(MessageDecoder.HANDLER_NAME, handler);
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import java.io.IOException;
-import java.io.InputStream;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TransformerHandler;
import org.opendaylight.netconf.api.messages.NetconfMessage;
import org.opendaylight.netconf.codec.MessageDecoder;
-import org.opendaylight.netconf.shaded.exificient.core.exceptions.EXIException;
import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
-public final class EXIMessageDecoder extends MessageDecoder {
+final class EXIMessageDecoder extends MessageDecoder {
private static final Logger LOG = LoggerFactory.getLogger(EXIMessageDecoder.class);
private static final SAXTransformerFactory FACTORY;
}
/**
- * 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.
+ * 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 DocumentBuilder documentBuilder = UntrustedXML.newDocumentBuilder();
private final ThreadLocalSAXDecoder reader;
- private final DocumentBuilder documentBuilder;
- private EXIMessageDecoder(final ThreadLocalSAXDecoder reader) {
+ EXIMessageDecoder(final ThreadLocalSAXDecoder reader) {
this.reader = requireNonNull(reader);
- documentBuilder = UntrustedXML.newDocumentBuilder();
- }
-
- public static EXIMessageDecoder create(final NetconfEXICodec codec) throws EXIException {
- return new EXIMessageDecoder(codec.getReader());
}
@Override
LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
}
- final TransformerHandler handler = FACTORY.newTransformerHandler();
+ final var handler = FACTORY.newTransformerHandler();
reader.setContentHandler(handler);
- final DOMResult domResult = new DOMResult(documentBuilder.newDocument());
+ final var domResult = new DOMResult(documentBuilder.newDocument());
handler.setResult(domResult);
- try (InputStream is = new ByteBufInputStream(in)) {
+ try (var is = new ByteBufInputStream(in)) {
// Performs internal reset before doing anything
reader.parse(new InputSource(is));
}
import io.netty.buffer.ByteBufOutputStream;
import io.netty.channel.ChannelHandlerContext;
import java.io.IOException;
-import java.io.OutputStream;
-import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import org.opendaylight.netconf.api.messages.NetconfMessage;
import org.opendaylight.netconf.codec.MessageEncoder;
import org.opendaylight.netconf.shaded.exificient.core.exceptions.EXIException;
-import org.opendaylight.netconf.shaded.exificient.main.api.sax.SAXEncoder;
+import org.opendaylight.netconf.shaded.exificient.main.api.sax.SAXFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public final class EXIMessageEncoder extends MessageEncoder {
+final class EXIMessageEncoder extends MessageEncoder {
private static final Logger LOG = LoggerFactory.getLogger(EXIMessageEncoder.class);
- private final NetconfEXICodec codec;
- private EXIMessageEncoder(final NetconfEXICodec codec) {
- this.codec = requireNonNull(codec);
- }
+ private final SAXFactory factory;
- public static EXIMessageEncoder create(final NetconfEXICodec codec) {
- return new EXIMessageEncoder(codec);
+ EXIMessageEncoder(final SAXFactory factory) {
+ this.factory = requireNonNull(factory);
}
@Override
throws IOException, TransformerException, EXIException {
LOG.trace("Sent to encode : {}", msg);
- try (OutputStream os = new ByteBufOutputStream(out)) {
- final SAXEncoder encoder = codec.getWriter();
+ try (var os = new ByteBufOutputStream(out)) {
+ final var encoder = factory.createEXIWriter();
encoder.setOutputStream(os);
- final Transformer transformer = ThreadLocalTransformers.getDefaultTransformer();
+ final var transformer = ThreadLocalTransformers.getDefaultTransformer();
transformer.transform(new DOMSource(msg.getDocument()), new SAXResult(encoder));
}
}
import static java.util.Objects.requireNonNull;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.netconf.codec.MessageDecoder;
+import org.opendaylight.netconf.codec.MessageEncoder;
import org.opendaylight.netconf.nettyutil.handler.exi.EXIParameters;
import org.opendaylight.netconf.shaded.exificient.core.EXIFactory;
import org.opendaylight.netconf.shaded.exificient.core.exceptions.EXIException;
-import org.opendaylight.netconf.shaded.exificient.main.api.sax.SAXEncoder;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
* Since we have a limited number of options we can have, instantiating a weak cache
* will allow us to reuse instances where possible.
*/
- private static final LoadingCache<EXIParameters, NetconfEXICodec> CODECS =
- CacheBuilder.newBuilder().weakValues().build(new CacheLoader<EXIParameters, NetconfEXICodec>() {
+ private static final LoadingCache<EXIParameters, @NonNull NetconfEXICodec> CODECS =
+ CacheBuilder.newBuilder().weakValues().build(new CacheLoader<>() {
@Override
public NetconfEXICodec load(final EXIParameters key) {
return new NetconfEXICodec(key.getFactory());
this.exiFactory = new ThreadLocalSAXFactory(requireNonNull(exiFactory));
}
- public static NetconfEXICodec forParameters(final EXIParameters parameters) {
+ public static @NonNull NetconfEXICodec forParameters(final EXIParameters parameters) {
return CODECS.getUnchecked(parameters);
}
- ThreadLocalSAXDecoder getReader() throws EXIException {
- final ThreadLocalSAXDecoder reader = exiFactory.createEXIReader();
+ public @NonNull MessageDecoder newMessageDecoder() throws EXIException {
+ final var reader = exiFactory.createEXIReader();
reader.setEntityResolver(ENTITY_RESOLVER);
- return reader;
+ return new EXIMessageDecoder(reader);
}
- SAXEncoder getWriter() throws EXIException {
- return exiFactory.createEXIWriter();
+ public @NonNull MessageEncoder newMessageEncoder() {
+ return new EXIMessageEncoder(exiFactory);
+ }
+
+ @VisibleForTesting
+ ThreadLocalSAXFactory exiFactory() {
+ return exiFactory;
}
}
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoop;
-import io.netty.handler.codec.ByteToMessageDecoder;
-import io.netty.handler.codec.MessageToByteEncoder;
import java.io.EOFException;
import java.util.Optional;
import java.util.Set;
testingNetconfSession = spy(testingNetconfSession);
testingNetconfSession.startExiCommunication(NetconfStartExiMessageProvider.create(EXIParameters.empty(), "4"));
- verify(testingNetconfSession).addExiHandlers(any(ByteToMessageDecoder.class), any(MessageToByteEncoder.class));
+ verify(testingNetconfSession).addExiHandlers(any(MessageDecoder.class), any(MessageEncoder.class));
}
@Test
package org.opendaylight.netconf.nettyutil;
import io.netty.channel.Channel;
-import io.netty.handler.codec.ByteToMessageDecoder;
-import io.netty.handler.codec.MessageToByteEncoder;
import org.opendaylight.netconf.api.NetconfSessionListener;
-import org.opendaylight.netconf.api.messages.NetconfMessage;
+import org.opendaylight.netconf.codec.MessageDecoder;
+import org.opendaylight.netconf.codec.MessageEncoder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
class TestingNetconfSession
}
@Override
- protected void addExiHandlers(final ByteToMessageDecoder decoder,
- final MessageToByteEncoder<NetconfMessage> encoder) {
+ protected void addExiHandlers(final MessageDecoder decoder, final MessageEncoder encoder) {
+ // No-op
}
@Override
public void stopExiCommunication() {
+ // No-op
}
}
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import io.netty.buffer.Unpooled;
import java.io.ByteArrayOutputStream;
class NetconfEXIHandlersTest {
private final String msgAsString = "<netconf-message/>";
- private EXIMessageEncoder netconfMessageToEXIEncoder;
- private EXIMessageDecoder netconfEXIMessageDecoder;
+ private EXIMessageEncoder exiEncoder;
+ private EXIMessageDecoder exiDecoder;
private NetconfMessage msg;
private byte[] msgAsExi;
@BeforeEach
void setUp() throws Exception {
final var codec = NetconfEXICodec.forParameters(EXIParameters.empty());
- netconfMessageToEXIEncoder = EXIMessageEncoder.create(codec);
- netconfEXIMessageDecoder = EXIMessageDecoder.create(codec);
+ exiEncoder = assertInstanceOf(EXIMessageEncoder.class, codec.newMessageEncoder());
+ exiDecoder = assertInstanceOf(EXIMessageDecoder.class, codec.newMessageDecoder());
msg = new NetconfMessage(XmlUtil.readXmlToDocument(msgAsString));
msgAsExi = msgToExi(msg, codec);
private static byte[] msgToExi(final NetconfMessage msg, final NetconfEXICodec codec) throws Exception {
final var bos = new ByteArrayOutputStream();
- final var encoder = codec.getWriter();
+ final var encoder = codec.exiFactory().createEXIWriter();
encoder.setOutputStream(bos);
ThreadLocalTransformers.getDefaultTransformer().transform(new DOMSource(msg.getDocument()),
new SAXResult(encoder));
@Test
void testEncodeDecode() throws Exception {
final var buffer = Unpooled.buffer();
- netconfMessageToEXIEncoder.encode(null, msg, buffer);
+ exiEncoder.encode(null, msg, buffer);
final int exiLength = msgAsExi.length;
// array from buffer is cca 256 n length, compare only subarray
assertArrayEquals(msgAsExi, Arrays.copyOfRange(buffer.array(), 0, exiLength));
}
final var out = new ArrayList<>();
- netconfEXIMessageDecoder.decode(null, buffer, out);
+ exiDecoder.decode(null, buffer, out);
final var diff = DiffBuilder.compare(msg.getDocument())
.withTest(((NetconfMessage) out.get(0)).getDocument())
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.netty.channel.Channel;
-import io.netty.handler.codec.ByteToMessageDecoder;
-import io.netty.handler.codec.MessageToByteEncoder;
import java.util.Collection;
-import org.opendaylight.netconf.api.messages.NetconfMessage;
+import org.opendaylight.netconf.codec.MessageDecoder;
+import org.opendaylight.netconf.codec.MessageEncoder;
import org.opendaylight.netconf.codec.XMLMessageDecoder;
import org.opendaylight.netconf.nettyutil.AbstractNetconfExiSession;
import org.opendaylight.netconf.nettyutil.handler.XMLMessageEncoder;
}
@Override
- protected void addExiHandlers(final ByteToMessageDecoder decoder,
- final MessageToByteEncoder<NetconfMessage> encoder) {
+ protected void addExiHandlers(final MessageDecoder decoder, final MessageEncoder encoder) {
// TODO used only in negotiator, client supports only auto start-exi
replaceMessageDecoder(decoder);
replaceMessageEncoder(encoder);
import org.opendaylight.netconf.api.messages.RpcMessage;
import org.opendaylight.netconf.api.xml.XmlUtil;
import org.opendaylight.netconf.codec.ChunkedFrameEncoder;
+import org.opendaylight.netconf.codec.MessageDecoder;
import org.opendaylight.netconf.codec.XMLMessageDecoder;
import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
-import org.opendaylight.netconf.nettyutil.handler.EXIMessageDecoder;
import org.opendaylight.netconf.nettyutil.handler.HelloXMLMessageDecoder;
+import org.opendaylight.netconf.nettyutil.handler.NetconfEXICodec;
import org.opendaylight.netconf.nettyutil.handler.exi.EXIParameters;
import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessageProvider;
+import org.opendaylight.netconf.shaded.exificient.core.exceptions.EXIException;
import org.opendaylight.netconf.test.util.XmlFileLoader;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
import org.opendaylight.yangtools.yang.common.Uint32;
doReturn(pipeline).when(pipeline).replace(any(ChannelHandler.class), anyString(),
any(NetconfClientSession.class));
doReturn(null).when(pipeline).replace(anyString(), anyString(), any(MessageToByteEncoder.class));
- doReturn(null).when(pipeline).replace(anyString(), anyString(), any(EXIMessageDecoder.class));
+
+ Class<? extends MessageDecoder> exiClass;
+ try {
+ exiClass = NetconfEXICodec.forParameters(EXIParameters.empty()).newMessageDecoder().getClass();
+ } catch (EXIException e) {
+ throw new AssertionError(e);
+ }
+
+ doReturn(null).when(pipeline).replace(anyString(), anyString(), any(exiClass));
return pipeline;
}
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
-import org.opendaylight.netconf.nettyutil.handler.EXIMessageDecoder;
-import org.opendaylight.netconf.nettyutil.handler.EXIMessageEncoder;
import org.opendaylight.netconf.nettyutil.handler.NetconfEXICodec;
import org.opendaylight.netconf.nettyutil.handler.exi.EXIParameters;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
Mockito.doReturn(channelHandler).when(pipeline).replace(anyString(), anyString(), any(ChannelHandler.class));
final NetconfClientSession session = new NetconfClientSession(sessionListener, channel, sessId, caps);
- final EXIMessageEncoder exiEncoder = EXIMessageEncoder.create(codec);
- final EXIMessageDecoder exiDecoder = EXIMessageDecoder.create(codec);
- session.addExiHandlers(exiDecoder, exiEncoder);
+ session.addExiHandlers(codec.newMessageDecoder(), codec.newMessageEncoder());
session.stopExiCommunication();
assertEquals(caps, session.getServerCapabilities());
import com.google.common.net.InetAddresses;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
-import io.netty.handler.codec.ByteToMessageDecoder;
-import io.netty.handler.codec.MessageToByteEncoder;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.time.Instant;
import org.opendaylight.netconf.api.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.netconf.api.messages.NetconfMessage;
import org.opendaylight.netconf.api.messages.NotificationMessage;
+import org.opendaylight.netconf.codec.MessageDecoder;
+import org.opendaylight.netconf.codec.MessageEncoder;
import org.opendaylight.netconf.codec.XMLMessageDecoder;
import org.opendaylight.netconf.nettyutil.AbstractNetconfExiSession;
import org.opendaylight.netconf.nettyutil.handler.XMLMessageEncoder;
}
@Override
- protected void addExiHandlers(final ByteToMessageDecoder decoder,
- final MessageToByteEncoder<NetconfMessage> encoder) {
+ protected void addExiHandlers(final MessageDecoder decoder, final MessageEncoder encoder) {
replaceMessageDecoder(decoder);
replaceMessageEncoderAfterNextMessage(encoder);
}
import org.opendaylight.netconf.codec.MessageDecoder;
import org.opendaylight.netconf.codec.MessageEncoder;
import org.opendaylight.netconf.codec.XMLMessageDecoder;
-import org.opendaylight.netconf.nettyutil.handler.EXIMessageDecoder;
-import org.opendaylight.netconf.nettyutil.handler.EXIMessageEncoder;
import org.opendaylight.netconf.nettyutil.handler.NetconfEXICodec;
import org.opendaylight.netconf.nettyutil.handler.XMLMessageEncoder;
import org.opendaylight.netconf.nettyutil.handler.exi.EXIParameters;
channel.pipeline().addLast(MessageDecoder.HANDLER_NAME, new XMLMessageDecoder());
channel.pipeline().addLast(MessageEncoder.HANDLER_NAME, new XMLMessageEncoder());
final var codec = NetconfEXICodec.forParameters(EXIParameters.empty());
- session.addExiHandlers(EXIMessageDecoder.create(codec), EXIMessageEncoder.create(codec));
+ session.addExiHandlers(codec.newMessageDecoder(), codec.newMessageEncoder());
}
@Test