X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=netconf%2Fnetconf-client%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetconf%2Fclient%2FNetconfClientSessionNegotiator.java;h=0c98fa3f42edf08fbc86c90e7b515c514fe9ce6e;hb=7bf7d3fd39c6966a2414d4ca6fd77d195021c1f8;hp=55d92d6df6e33bc25ea471067bce24976d6db529;hpb=0a2f99ddeda1a557743403de51ee16ecec15fb89;p=netconf.git diff --git a/netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiator.java b/netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiator.java index 55d92d6df6..0c98fa3f42 100644 --- a/netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiator.java +++ b/netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/NetconfClientSessionNegotiator.java @@ -5,7 +5,6 @@ * 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.netconf.client; import com.google.common.base.Strings; @@ -13,8 +12,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Interner; import com.google.common.collect.Interners; import io.netty.channel.Channel; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.util.Timer; @@ -22,12 +19,12 @@ import io.netty.util.concurrent.Promise; import java.util.Set; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; -import org.opendaylight.controller.config.util.xml.XmlUtil; -import org.opendaylight.netconf.api.NetconfClientSessionPreferences; +import org.checkerframework.checker.index.qual.NonNegative; import org.opendaylight.netconf.api.NetconfDocumentedException; import org.opendaylight.netconf.api.NetconfMessage; import org.opendaylight.netconf.api.messages.NetconfHelloMessage; import org.opendaylight.netconf.api.xml.XmlNetconfConstants; +import org.opendaylight.netconf.api.xml.XmlUtil; import org.opendaylight.netconf.nettyutil.AbstractChannelInitializer; import org.opendaylight.netconf.nettyutil.AbstractNetconfSessionNegotiator; import org.opendaylight.netconf.nettyutil.handler.exi.NetconfStartExiMessage; @@ -39,41 +36,52 @@ import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -public class NetconfClientSessionNegotiator extends - AbstractNetconfSessionNegotiator -{ +// Non-final for mocking +class NetconfClientSessionNegotiator + extends AbstractNetconfSessionNegotiator { private static final Logger LOG = LoggerFactory.getLogger(NetconfClientSessionNegotiator.class); - private static final XPathExpression sessionIdXPath = XMLNetconfUtil + private static final XPathExpression SESSION_ID_X_PATH = XMLNetconfUtil .compileXPath("/netconf:hello/netconf:session-id"); - private static final XPathExpression sessionIdXPathNoNamespace = XMLNetconfUtil + private static final XPathExpression SESSION_ID_X_PATH_NO_NAMESPACE = XMLNetconfUtil .compileXPath("/hello/session-id"); private static final String EXI_1_0_CAPABILITY_MARKER = "exi:1.0"; private static final Interner> INTERNER = Interners.newWeakInterner(); - protected NetconfClientSessionNegotiator(final NetconfClientSessionPreferences sessionPreferences, - final Promise promise, - final Channel channel, - final Timer timer, - final NetconfClientSessionListener sessionListener, - final long connectionTimeoutMillis) { - super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis); + private final NetconfStartExiMessage startExi; + + NetconfClientSessionNegotiator(final NetconfHelloMessage hello, final NetconfStartExiMessage startExi, + final Promise promise, final Channel channel, final Timer timer, + final NetconfClientSessionListener sessionListener, final long connectionTimeoutMillis, + final @NonNegative int maximumIncomingChunkSize) { + super(hello, promise, channel, timer, sessionListener, connectionTimeoutMillis, maximumIncomingChunkSize); + this.startExi = startExi; } + @SuppressWarnings("checkstyle:IllegalCatch") @Override protected void handleMessage(final NetconfHelloMessage netconfMessage) throws NetconfDocumentedException { + if (!ifNegotiatedAlready()) { + LOG.debug("Server hello message received, starting negotiation on channel {}", channel); + try { + startNegotiation(); + } catch (final Exception e) { + LOG.warn("Unexpected negotiation failure on channel {}", channel, e); + negotiationFailed(e); + return; + } + } final NetconfClientSession session = getSessionForHelloMessage(netconfMessage); replaceHelloMessageInboundHandler(session); // If exi should be used, try to initiate exi communication // Call negotiationSuccessFul after exi negotiation is finished successfully or not - if (shouldUseExi(netconfMessage)) { + if (startExi != null && shouldUseExi(netconfMessage)) { LOG.debug("Netconf session {} should use exi.", session); - NetconfStartExiMessage startExiMessage = (NetconfStartExiMessage) sessionPreferences.getStartExiMessage(); - tryToInitiateExi(session, startExiMessage); + tryToInitiateExi(session, startExi); } else { // Exi is not supported, release session immediately LOG.debug("Netconf session {} isn't capable of using exi.", session); @@ -84,29 +92,26 @@ public class NetconfClientSessionNegotiator extends /** * Initiates exi communication by sending start-exi message and waiting for positive/negative response. * - * @param startExiMessage + * @param startExiMessage Exi message for initilization of exi communication. */ void tryToInitiateExi(final NetconfClientSession session, final NetconfStartExiMessage startExiMessage) { channel.pipeline().addAfter(AbstractChannelInitializer.NETCONF_MESSAGE_DECODER, ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER, new ExiConfirmationInboundHandler(session, startExiMessage)); - session.sendMessage(startExiMessage).addListener(new ChannelFutureListener() { - @Override - public void operationComplete(final ChannelFuture f) { - if (!f.isSuccess()) { - LOG.warn("Failed to send start-exi message {} on session {}", startExiMessage, this, f.cause()); - channel.pipeline().remove(ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER); - } else { - LOG.trace("Start-exi message {} sent to socket on session {}", startExiMessage, this); - } + session.sendMessage(startExiMessage).addListener(channelFuture -> { + if (!channelFuture.isSuccess()) { + LOG.warn("Failed to send start-exi message {} on session {}", startExiMessage, session, + channelFuture.cause()); + channel.pipeline().remove(ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER); + } else { + LOG.trace("Start-exi message {} sent to socket on session {}", startExiMessage, session); } }); } private boolean shouldUseExi(final NetconfHelloMessage helloMsg) { - return containsExi10Capability(helloMsg.getDocument()) - && containsExi10Capability(sessionPreferences.getHelloMessage().getDocument()); + return containsExi10Capability(helloMsg.getDocument()) && containsExi10Capability(localHello().getDocument()); } private static boolean containsExi10Capability(final Document doc) { @@ -120,15 +125,16 @@ public class NetconfClientSessionNegotiator extends } private static long extractSessionId(final Document doc) { - String textContent = getSessionIdWithXPath(doc, sessionIdXPath); + String textContent = getSessionIdWithXPath(doc, SESSION_ID_X_PATH); if (Strings.isNullOrEmpty(textContent)) { - textContent = getSessionIdWithXPath(doc, sessionIdXPathNoNamespace); + textContent = getSessionIdWithXPath(doc, SESSION_ID_X_PATH_NO_NAMESPACE); if (Strings.isNullOrEmpty(textContent)) { - throw new IllegalStateException("Session id not received from server, hello message: " + XmlUtil.toString(doc)); + throw new IllegalStateException("Session id not received from server, hello message: " + XmlUtil + .toString(doc)); } } - return Long.valueOf(textContent); + return Long.parseLong(textContent); } private static String getSessionIdWithXPath(final Document doc, final XPathExpression sessionIdXPath) { @@ -138,11 +144,12 @@ public class NetconfClientSessionNegotiator extends @Override protected NetconfClientSession getSession(final NetconfClientSessionListener sessionListener, final Channel channel, - final NetconfHelloMessage message) throws NetconfDocumentedException { + final NetconfHelloMessage message) { final long sessionId = extractSessionId(message.getDocument()); // Copy here is important: it disconnects the strings from the document - Set capabilities = ImmutableSet.copyOf(NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument())); + Set capabilities = ImmutableSet.copyOf(NetconfMessageUtil.extractCapabilitiesFromHello(message + .getDocument())); capabilities = INTERNER.intern(capabilities); @@ -150,7 +157,7 @@ public class NetconfClientSessionNegotiator extends } /** - * Handler to process response for start-exi message + * Handler to process response for start-exi message. */ private final class ExiConfirmationInboundHandler extends ChannelInboundHandlerAdapter { private static final String EXI_CONFIRMED_HANDLER = "exiConfirmedHandler"; @@ -158,11 +165,13 @@ public class NetconfClientSessionNegotiator extends private final NetconfClientSession session; private final NetconfStartExiMessage startExiMessage; - ExiConfirmationInboundHandler(final NetconfClientSession session, final NetconfStartExiMessage startExiMessage) { + ExiConfirmationInboundHandler(final NetconfClientSession session, + final NetconfStartExiMessage startExiMessage) { this.session = session; this.startExiMessage = startExiMessage; } + @SuppressWarnings("checkstyle:IllegalCatch") @Override public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception { ctx.pipeline().remove(ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER); @@ -176,20 +185,22 @@ public class NetconfClientSessionNegotiator extends session.startExiCommunication(startExiMessage); } catch (RuntimeException e) { // Unable to add exi, continue without exi - LOG.warn("Unable to start exi communication, Communication will continue without exi on session {}", session, e); + LOG.warn("Unable to start exi communication, Communication will continue without exi on session " + + "{}", session, e); } // Error response - } else if(NetconfMessageUtil.isErrorMessage(netconfMessage)) { + } else if (NetconfMessageUtil.isErrorMessage(netconfMessage)) { LOG.warn( "Error response to start-exi message {}, Communication will continue without exi on session {}", netconfMessage, session); // Unexpected response to start-exi, throwing message away, continue without exi } else { - LOG.warn("Unexpected response to start-exi message, should be ok, was {}, " + - "Communication will continue without exi and response message will be thrown away on session {}", - netconfMessage, session); + LOG.warn("Unexpected response to start-exi message, should be ok, was {}, " + + "Communication will continue without exi " + + "and response message will be thrown away on session {}", + netconfMessage, session); } negotiationSuccessful(session);