* 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;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
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;
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.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;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-public class NetconfClientSessionNegotiator extends
- AbstractNetconfSessionNegotiator<NetconfClientSessionPreferences, NetconfClientSession,
- NetconfClientSessionListener> {
+// Non-final for mocking
+class NetconfClientSessionNegotiator
+ extends AbstractNetconfSessionNegotiator<NetconfClientSession, NetconfClientSessionListener> {
private static final Logger LOG = LoggerFactory.getLogger(NetconfClientSessionNegotiator.class);
private static final XPathExpression SESSION_ID_X_PATH = XMLNetconfUtil
private static final Interner<Set<String>> INTERNER = Interners.newWeakInterner();
- protected NetconfClientSessionNegotiator(final NetconfClientSessionPreferences sessionPreferences,
- final Promise<NetconfClientSession> promise,
- final Channel channel,
- final Timer timer,
- final NetconfClientSessionListener sessionListener,
- final long connectionTimeoutMillis) {
- super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
+ private final NetconfMessage startExi;
+
+ NetconfClientSessionNegotiator(final NetconfClientSessionPreferences sessionPreferences,
+ final Promise<NetconfClientSession> promise, final Channel channel, final Timer timer,
+ final NetconfClientSessionListener sessionListener, final long connectionTimeoutMillis) {
+ super(sessionPreferences.getHelloMessage(), promise, channel, timer, sessionListener, connectionTimeoutMillis);
+ startExi = sessionPreferences.getStartExiMessage();
}
+ @SuppressWarnings("checkstyle:IllegalCatch")
@Override
- @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
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
- final NetconfMessage startExiMessage = sessionPreferences.getStartExiMessage();
- if (shouldUseExi(netconfMessage) && startExiMessage instanceof NetconfStartExiMessage) {
+ if (startExi instanceof NetconfStartExiMessage && shouldUseExi(netconfMessage)) {
LOG.debug("Netconf session {} should use exi.", session);
- tryToInitiateExi(session, (NetconfStartExiMessage) startExiMessage);
+ tryToInitiateExi(session, (NetconfStartExiMessage) startExi);
} else {
// Exi is not supported, release session immediately
LOG.debug("Netconf session {} isn't capable of using exi.", session);
ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER,
new ExiConfirmationInboundHandler(session, startExiMessage));
- session.sendMessage(startExiMessage).addListener(new ChannelFutureListener() {
- @Override
- public void operationComplete(final ChannelFuture channelFuture) {
- if (!channelFuture.isSuccess()) {
- LOG.warn("Failed to send start-exi message {} on session {}", startExiMessage, this,
- channelFuture.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);
}
});
}
- @SuppressFBWarnings("BC_UNCONFIRMED_CAST")
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) {
@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