Rework NETCONF interfaces 18/5218/7
authorRobert Varga <rovarga@cisco.com>
Sun, 9 Feb 2014 22:41:45 +0000 (23:41 +0100)
committerRobert Varga <rovarga@cisco.com>
Tue, 11 Feb 2014 14:43:43 +0000 (15:43 +0100)
NetconfSession and NetconfClientSessionListener are supposed to be
interfaces, not classes. Convert them to such and introduce utility
classes which retain their current functionality. Remove an unused
method and fix type safety warnings while we're at it.

Change-Id: Id7d78c831e3c3d46abb4379efe4a5ca353cd55ff
Signed-off-by: Robert Varga <rovarga@cisco.com>
18 files changed:
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java [new file with mode: 0644]
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/AbstractNetconfClientNotifySessionListener.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionListener.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiatorFactory.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiator.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSessionNegotiatorFactory.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationRouterImpl.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractNetconfSessionNegotiator.java

diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/AbstractNetconfSession.java
new file mode 100644 (file)
index 0000000..bd75c27
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.controller.netconf.api;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+
+import java.io.IOException;
+
+import org.opendaylight.protocol.framework.AbstractProtocolSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractNetconfSession<S extends NetconfSession, L extends NetconfSessionListener<S>> extends AbstractProtocolSession<NetconfMessage> implements NetconfSession {
+    private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSession.class);
+    private final L sessionListener;
+    private final long sessionId;
+    private boolean up = false;
+
+    protected final Channel channel;
+
+    protected AbstractNetconfSession(L sessionListener, Channel channel, long sessionId) {
+        this.sessionListener = sessionListener;
+        this.channel = channel;
+        this.sessionId = sessionId;
+        logger.debug("Session {} created", toString());
+    }
+
+    protected abstract S thisInstance();
+
+    @Override
+    public void close() {
+        channel.close();
+        up = false;
+        sessionListener.onSessionTerminated(thisInstance(), new NetconfTerminationReason("Session closed"));
+    }
+
+    @Override
+    protected void handleMessage(NetconfMessage netconfMessage) {
+        logger.debug("handling incoming message");
+        sessionListener.onMessage(thisInstance(), netconfMessage);
+    }
+
+    @Override
+    public ChannelFuture sendMessage(NetconfMessage netconfMessage) {
+        return channel.writeAndFlush(netconfMessage);
+    }
+
+    @Override
+    protected void endOfInput() {
+        logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up"
+                : "initialized");
+        if (isUp()) {
+            this.sessionListener.onSessionDown(thisInstance(), new IOException("End of input detected. Close the session."));
+        }
+    }
+
+    @Override
+    protected void sessionUp() {
+        logger.debug("Session {} up", toString());
+        sessionListener.onSessionUp(thisInstance());
+        this.up = true;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("ServerNetconfSession{");
+        sb.append("sessionId=").append(sessionId);
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public final boolean isUp() {
+        return up;
+    }
+
+    public final long getSessionId() {
+        return sessionId;
+    }
+}
+
index 4770cb128fb7399f50759a2ffb599796001992b6..e52e71ceea91ac43f470c110d1127c499b748b42 100644 (file)
@@ -7,78 +7,10 @@
  */
 package org.opendaylight.controller.netconf.api;
 
-import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 
-import java.io.IOException;
+import org.opendaylight.protocol.framework.ProtocolSession;
 
-import org.opendaylight.protocol.framework.AbstractProtocolSession;
-import org.opendaylight.protocol.framework.SessionListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class NetconfSession extends AbstractProtocolSession<NetconfMessage> {
-    private static final Logger logger = LoggerFactory.getLogger(NetconfSession.class);
-    private final SessionListener<NetconfMessage, NetconfSession, NetconfTerminationReason> sessionListener;
-    private final long sessionId;
-    private boolean up = false;
-
-    protected final Channel channel;
-
-    protected NetconfSession(SessionListener<NetconfMessage, NetconfSession, NetconfTerminationReason> sessionListener, Channel channel, long sessionId) {
-        this.sessionListener = sessionListener;
-        this.channel = channel;
-        this.sessionId = sessionId;
-        logger.debug("Session {} created", toString());
-    }
-
-    @Override
-    public void close() {
-        channel.close();
-        up = false;
-        sessionListener.onSessionTerminated(this, new NetconfTerminationReason("Session closed"));
-    }
-
-    @Override
-    protected void handleMessage(NetconfMessage netconfMessage) {
-        logger.debug("handling incoming message");
-        sessionListener.onMessage(this, netconfMessage);
-    }
-
-    public ChannelFuture sendMessage(NetconfMessage netconfMessage) {
-        return channel.writeAndFlush(netconfMessage);
-    }
-
-    @Override
-    protected void endOfInput() {
-        logger.debug("Session {} end of input detected while session was in state {}", toString(), isUp() ? "up"
-                : "initialized");
-        if (isUp()) {
-            this.sessionListener.onSessionDown(this, new IOException("End of input detected. Close the session."));
-        }
-    }
-
-    @Override
-    protected void sessionUp() {
-        logger.debug("Session {} up", toString());
-        sessionListener.onSessionUp(this);
-        this.up = true;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuffer sb = new StringBuffer("ServerNetconfSession{");
-        sb.append("sessionId=").append(sessionId);
-        sb.append('}');
-        return sb.toString();
-    }
-
-    public final boolean isUp() {
-        return up;
-    }
-
-    public final long getSessionId() {
-        return sessionId;
-    }
+public interface NetconfSession extends ProtocolSession<NetconfMessage> {
+    ChannelFuture sendMessage(NetconfMessage message);
 }
-
index aee4085599c7fc05ba25493c8b5df2f95f1b0560..6ae966d1f71b7299ce3b7f444df179a6bbcc4e2a 100644 (file)
@@ -15,7 +15,7 @@ import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 /**
  * Class extending {@link NetconfClientSessionListener} to provide notification capability.
  */
-public abstract class AbstractNetconfClientNotifySessionListener extends NetconfClientSessionListener {
+public abstract class AbstractNetconfClientNotifySessionListener extends SimpleNetconfClientSessionListener {
     /*
      * Maybe some capabilities could be expressed as internal NetconfClientSessionListener handlers.
      * It would enable NetconfClient functionality to be extended by using namespace handlers.
index a9dd2c3394b4ad15b38360edcd5be18ee701fcd8..4cdca208bc5e472088b07741b958c2e716e3f2dd 100644 (file)
@@ -31,6 +31,10 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Stopwatch;
 import com.google.common.collect.Sets;
 
+/**
+ * @deprecated Use {@link NetconfClientDispatcher.createClient()} or {@link NetconfClientDispatcher.createReconnectingClient()} instead.
+ */
+@Deprecated
 public class NetconfClient implements Closeable {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
@@ -53,7 +57,7 @@ public class NetconfClient implements Closeable {
     private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException {
         this.label = clientLabelForLogging;
         dispatch = netconfClientDispatcher;
-        sessionListener = new NetconfClientSessionListener();
+        sessionListener = new SimpleNetconfClientSessionListener();
         Future<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
         this.address = address;
         clientSession = get(clientFuture);
@@ -74,7 +78,8 @@ public class NetconfClient implements Closeable {
         return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher);
     }
 
-    public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher,NetconfClientSessionListener listener) throws InterruptedException {
+    public static NetconfClient clientFor(String clientLabelForLogging, InetSocketAddress address,
+            ReconnectStrategy strategy, NetconfClientDispatcher netconfClientDispatcher, NetconfClientSessionListener listener) throws InterruptedException {
         return new NetconfClient(clientLabelForLogging,address,strategy,netconfClientDispatcher,listener);
     }
 
@@ -102,7 +107,7 @@ public class NetconfClient implements Closeable {
     }
 
     public Future<NetconfMessage> sendRequest(NetconfMessage message) {
-        return sessionListener.sendRequest(message);
+        return ((SimpleNetconfClientSessionListener)sessionListener).sendRequest(message);
     }
 
     /**
@@ -122,7 +127,7 @@ public class NetconfClient implements Closeable {
         final Stopwatch stopwatch = new Stopwatch().start();
 
         try {
-            return sessionListener.sendRequest(message).get(attempts * attemptMsDelay, TimeUnit.MILLISECONDS);
+            return sendRequest(message).get(attempts * attemptMsDelay, TimeUnit.MILLISECONDS);
         } finally {
             stopwatch.stop();
             logger.debug("Total time spent waiting for response from {}: {} ms", address, stopwatch.elapsed(TimeUnit.MILLISECONDS));
index dd08bf565c5d10c951d1cb3d87ee24162c46cb91..bff2a54c58926e9e445ac13878950384f1b9160d 100644 (file)
@@ -17,10 +17,10 @@ import io.netty.util.concurrent.Promise;
 import java.io.Closeable;
 import java.net.InetSocketAddress;
 
-import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
 import org.opendaylight.protocol.framework.AbstractDispatcher;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -29,7 +29,7 @@ import com.google.common.base.Optional;
 
 public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSession, NetconfClientSessionListener> implements Closeable {
 
-    private static final Logger logger = LoggerFactory.getLogger(NetconfClient.class);
+    private static final Logger logger = LoggerFactory.getLogger(NetconfClientDispatcher.class);
 
     private final NetconfClientSessionNegotiatorFactory negotatorFactory;
     private final HashedWheelTimer timer;
@@ -62,7 +62,21 @@ public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSes
         });
     }
 
-    private static class ClientChannelInitializer extends AbstractChannelInitializer {
+    public Future<Void> createReconnectingClient(final InetSocketAddress address,
+            final NetconfClientSessionListener listener,
+            final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) {
+        final ClientChannelInitializer init = new ClientChannelInitializer(negotatorFactory, listener);
+
+        return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy,
+                new PipelineInitializer<NetconfClientSession>() {
+            @Override
+            public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+                init.initialize(ch, promise);
+            }
+        });
+    }
+
+    private static class ClientChannelInitializer extends AbstractChannelInitializer<NetconfClientSession> {
 
         private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
         private final NetconfClientSessionListener sessionListener;
@@ -74,12 +88,7 @@ public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSes
         }
 
         @Override
-        public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
-            super.initialize(ch,promise);
-        }
-
-        @Override
-        protected void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+        protected void initializeAfterDecoder(SocketChannel ch, Promise<NetconfClientSession> promise) {
             ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(
                     new SessionListenerFactory<NetconfClientSessionListener>() {
                         @Override
@@ -88,8 +97,8 @@ public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSes
                         }
                     }, ch, promise));
         }
-
     }
+
     @Override
     public void close() {
         try {
index 5ee89fec40ab12fe3fbd104130eef0dc31d56d8e..2d07dd58332ea6bd8b5c030a6408be876aae0278 100644 (file)
@@ -12,19 +12,16 @@ import io.netty.channel.Channel;
 
 import java.util.Collection;
 
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
-import org.opendaylight.protocol.framework.SessionListener;
+import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class NetconfClientSession extends NetconfSession {
+public final class NetconfClientSession extends AbstractNetconfSession<NetconfClientSession, NetconfClientSessionListener> {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class);
     private final Collection<String> capabilities;
 
-    public NetconfClientSession(SessionListener<NetconfMessage, NetconfSession, NetconfTerminationReason> sessionListener, Channel channel, long sessionId,
+    public NetconfClientSession(NetconfClientSessionListener sessionListener, Channel channel, long sessionId,
             Collection<String> capabilities) {
         super(sessionListener,channel,sessionId);
         this.capabilities = capabilities;
@@ -35,4 +32,8 @@ public class NetconfClientSession extends NetconfSession {
         return capabilities;
     }
 
+    @Override
+    protected NetconfClientSession thisInstance() {
+        return this;
+    }
 }
index 1ac2e7e26462c84a239757f93ee6b2d926f53e46..21be3a8cabf4cf24edb6a9fc08530ebce76bcb53 100644 (file)
 /*
- * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * 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.controller.netconf.client;
 
-import io.netty.util.concurrent.Future;
-import io.netty.util.concurrent.GlobalEventExecutor;
-import io.netty.util.concurrent.Promise;
-
-import java.util.ArrayDeque;
-import java.util.Queue;
-
-import javax.annotation.concurrent.GuardedBy;
-
-import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSessionListener;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-
-public class NetconfClientSessionListener implements NetconfSessionListener<NetconfClientSession> {
-    private static final class RequestEntry {
-        final Promise<NetconfMessage> promise;
-        final NetconfMessage request;
-
-        public RequestEntry(Promise<NetconfMessage> future, NetconfMessage request) {
-            this.promise = Preconditions.checkNotNull(future);
-            this.request = Preconditions.checkNotNull(request);
-        }
-    }
-
-    private static final Logger logger = LoggerFactory.getLogger(NetconfClientSessionListener.class);
-
-    @GuardedBy("this")
-    private final Queue<RequestEntry> requests = new ArrayDeque<>();
-
-    @GuardedBy("this")
-    private NetconfClientSession clientSession;
-
-    @GuardedBy("this")
-    private void dispatchRequest() {
-        while (!requests.isEmpty()) {
-            final RequestEntry e = requests.peek();
-            if (e.promise.setUncancellable()) {
-                logger.debug("Sending message {}", e.request);
-                clientSession.sendMessage(e.request);
-                break;
-            }
-
-            logger.debug("Message {} has been cancelled, skipping it", e.request);
-            requests.poll();
-        }
-    }
-
-    @Override
-    public final synchronized void onSessionUp(NetconfClientSession clientSession) {
-        this.clientSession = Preconditions.checkNotNull(clientSession);
-        logger.debug("Client session {} went up", clientSession);
-        dispatchRequest();
-    }
-
-    private synchronized void tearDown(final Exception cause) {
-        final RequestEntry e = requests.poll();
-        if (e != null) {
-            e.promise.setFailure(cause);
-        }
-
-        this.clientSession = null;
-    }
-
-    @Override
-    public final void onSessionDown(NetconfClientSession clientSession, Exception e) {
-        logger.debug("Client Session {} went down unexpectedly", clientSession, e);
-        tearDown(e);
-    }
-
-    @Override
-    public final void onSessionTerminated(NetconfClientSession clientSession,
-            NetconfTerminationReason netconfTerminationReason) {
-        logger.debug("Client Session {} terminated, reason: {}", clientSession,
-                netconfTerminationReason.getErrorMessage());
-        tearDown(new RuntimeException(netconfTerminationReason.getErrorMessage()));
-    }
-
-    @Override
-    public synchronized void onMessage(NetconfClientSession session, NetconfMessage message) {
-        logger.debug("New message arrived: {}", message);
-
-        final RequestEntry e = requests.poll();
-        if (e != null) {
-            e.promise.setSuccess(message);
-            dispatchRequest();
-        } else {
-            logger.info("Ignoring unsolicited message {}", message);
-        }
-    }
-
-    final synchronized Future<NetconfMessage> sendRequest(NetconfMessage message) {
-        final RequestEntry req = new RequestEntry(GlobalEventExecutor.INSTANCE.<NetconfMessage>newPromise(), message);
 
-        requests.add(req);
-        if (clientSession != null) {
-            dispatchRequest();
-        }
+public interface NetconfClientSessionListener extends NetconfSessionListener<NetconfClientSession> {
 
-        return req.promise;
-    }
 }
index 100b98c15af18e1791dc4c43fcc460189ee4384e..3c2e814d899aea8c170795106b786e26063b6871 100644 (file)
@@ -8,11 +8,17 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import com.google.common.base.Function;
-import com.google.common.collect.Collections2;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+
+import java.util.Collection;
+import java.util.List;
+
+import javax.annotation.Nullable;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
@@ -20,21 +26,17 @@ import org.opendaylight.controller.netconf.util.xml.XMLNetconfUtil;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
-import org.opendaylight.protocol.framework.SessionListener;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 
-import javax.annotation.Nullable;
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import java.util.Collection;
-import java.util.List;
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
 
 public class NetconfClientSessionNegotiator extends
-        AbstractNetconfSessionNegotiator<NetconfSessionPreferences, NetconfClientSession> {
+        AbstractNetconfSessionNegotiator<NetconfSessionPreferences, NetconfClientSession, NetconfClientSessionListener> {
 
     protected NetconfClientSessionNegotiator(NetconfSessionPreferences sessionPreferences,
-            Promise<NetconfClientSession> promise, Channel channel, Timer timer, SessionListener sessionListener,
+            Promise<NetconfClientSession> promise, Channel channel, Timer timer, NetconfClientSessionListener sessionListener,
             long connectionTimeoutMillis) {
         super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
     }
@@ -69,7 +71,7 @@ public class NetconfClientSessionNegotiator extends
     }
 
     @Override
-    protected NetconfClientSession getSession(SessionListener sessionListener, Channel channel, NetconfMessage message) {
+    protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel, NetconfMessage message) {
         return new NetconfClientSession(sessionListener, channel, extractSessionId(message.getDocument()),
                 getCapabilities(message.getDocument()));
     }
index db6c024e5afe24e35d336ce2c5322340814289eb..e678a601ff46a5496fbc311047a2162afa5bde61 100644 (file)
@@ -8,11 +8,13 @@
 
 package org.opendaylight.controller.netconf.client;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+
+import java.io.IOException;
+import java.io.InputStream;
+
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
@@ -21,18 +23,17 @@ import org.opendaylight.protocol.framework.SessionNegotiator;
 import org.opendaylight.protocol.framework.SessionNegotiatorFactory;
 import org.xml.sax.SAXException;
 
-import java.io.IOException;
-import java.io.InputStream;
-
-public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory {
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 
-    private final Timer timer;
+public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfMessage, NetconfClientSession, NetconfClientSessionListener> {
 
     private final Optional<String> additionalHeader;
     private final long connectionTimeoutMillis;
+    private final Timer timer;
 
     public NetconfClientSessionNegotiatorFactory(Timer timer, Optional<String> additionalHeader, long connectionTimeoutMillis) {
-        this.timer = timer;
+        this.timer = Preconditions.checkNotNull(timer);
         this.additionalHeader = additionalHeader;
         this.connectionTimeoutMillis = connectionTimeoutMillis;
     }
@@ -48,8 +49,8 @@ public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorF
     }
 
     @Override
-    public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel,
-            Promise promise) {
+    public SessionNegotiator<NetconfClientSession> getSessionNegotiator(SessionListenerFactory<NetconfClientSessionListener> sessionListenerFactory, Channel channel,
+            Promise<NetconfClientSession> promise) {
         // Hello message needs to be recreated every time
         NetconfMessage helloMessage = loadHelloMessageTemplate();
         if(this.additionalHeader.isPresent()) {
@@ -59,5 +60,4 @@ public class NetconfClientSessionNegotiatorFactory implements SessionNegotiatorF
         return new NetconfClientSessionNegotiator(proposal, promise, channel, timer,
                 sessionListenerFactory.getSessionListener(), connectionTimeoutMillis);
     }
-
 }
index 25beb65179f9d54789739dd1faa8428704bf793f..0737279b042718309f5954205651d9da2dc151d4 100644 (file)
@@ -17,12 +17,12 @@ import io.netty.util.concurrent.Promise;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 
-import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
 import org.opendaylight.controller.netconf.util.handler.ssh.SshHandler;
 import org.opendaylight.controller.netconf.util.handler.ssh.authentication.AuthenticationHandler;
 import org.opendaylight.controller.netconf.util.handler.ssh.client.Invoker;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
+import org.opendaylight.protocol.framework.ReconnectStrategyFactory;
 import org.opendaylight.protocol.framework.SessionListenerFactory;
 
 import com.google.common.base.Optional;
@@ -62,7 +62,22 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
         });
     }
 
-    private static final class NetconfSshClientInitializer extends AbstractChannelInitializer {
+    @Override
+    public Future<Void> createReconnectingClient(final InetSocketAddress address,
+            final NetconfClientSessionListener listener,
+            final ReconnectStrategyFactory connectStrategyFactory, final ReconnectStrategy reestablishStrategy) {
+        final NetconfSshClientInitializer init = new NetconfSshClientInitializer(authHandler, negotatorFactory, listener);
+
+        return super.createReconnectingClient(address, connectStrategyFactory, reestablishStrategy,
+                new PipelineInitializer<NetconfClientSession>() {
+            @Override
+            public void initializeChannel(final SocketChannel ch, final Promise<NetconfClientSession> promise) {
+                init.initialize(ch, promise);
+            }
+        });
+    }
+
+    private static final class NetconfSshClientInitializer extends AbstractChannelInitializer<NetconfClientSession> {
 
         private final AuthenticationHandler authenticationHandler;
         private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
@@ -77,7 +92,7 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
         }
 
         @Override
-        public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+        public void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
             try {
                 Invoker invoker = Invoker.subsystem("netconf");
                 ch.pipeline().addFirst(new SshHandler(authenticationHandler, invoker));
@@ -88,7 +103,7 @@ public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
         }
 
         @Override
-        protected void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+        protected void initializeAfterDecoder(SocketChannel ch, Promise<NetconfClientSession> promise) {
             ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(new SessionListenerFactory<NetconfClientSessionListener>() {
                 @Override
                 public NetconfClientSessionListener getSessionListener() {
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/SimpleNetconfClientSessionListener.java
new file mode 100644 (file)
index 0000000..e96161c
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * 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.controller.netconf.client;
+
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GlobalEventExecutor;
+import io.netty.util.concurrent.Promise;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+public class SimpleNetconfClientSessionListener implements NetconfClientSessionListener {
+    private static final class RequestEntry {
+        final Promise<NetconfMessage> promise;
+        final NetconfMessage request;
+
+        public RequestEntry(Promise<NetconfMessage> future, NetconfMessage request) {
+            this.promise = Preconditions.checkNotNull(future);
+            this.request = Preconditions.checkNotNull(request);
+        }
+    }
+
+    private static final Logger logger = LoggerFactory.getLogger(SimpleNetconfClientSessionListener.class);
+
+    @GuardedBy("this")
+    private final Queue<RequestEntry> requests = new ArrayDeque<>();
+
+    @GuardedBy("this")
+    private NetconfClientSession clientSession;
+
+    @GuardedBy("this")
+    private void dispatchRequest() {
+        while (!requests.isEmpty()) {
+            final RequestEntry e = requests.peek();
+            if (e.promise.setUncancellable()) {
+                logger.debug("Sending message {}", e.request);
+                clientSession.sendMessage(e.request);
+                break;
+            }
+
+            logger.debug("Message {} has been cancelled, skipping it", e.request);
+            requests.poll();
+        }
+    }
+
+    @Override
+    public final synchronized void onSessionUp(NetconfClientSession clientSession) {
+        this.clientSession = Preconditions.checkNotNull(clientSession);
+        logger.debug("Client session {} went up", clientSession);
+        dispatchRequest();
+    }
+
+    private synchronized void tearDown(final Exception cause) {
+        final RequestEntry e = requests.poll();
+        if (e != null) {
+            e.promise.setFailure(cause);
+        }
+
+        this.clientSession = null;
+    }
+
+    @Override
+    public final void onSessionDown(NetconfClientSession clientSession, Exception e) {
+        logger.debug("Client Session {} went down unexpectedly", clientSession, e);
+        tearDown(e);
+    }
+
+    @Override
+    public final void onSessionTerminated(NetconfClientSession clientSession,
+            NetconfTerminationReason netconfTerminationReason) {
+        logger.debug("Client Session {} terminated, reason: {}", clientSession,
+                netconfTerminationReason.getErrorMessage());
+        tearDown(new RuntimeException(netconfTerminationReason.getErrorMessage()));
+    }
+
+    @Override
+    public synchronized void onMessage(NetconfClientSession session, NetconfMessage message) {
+        logger.debug("New message arrived: {}", message);
+
+        final RequestEntry e = requests.poll();
+        if (e != null) {
+            e.promise.setSuccess(message);
+            dispatchRequest();
+        } else {
+            logger.info("Ignoring unsolicited message {}", message);
+        }
+    }
+
+    final synchronized Future<NetconfMessage> sendRequest(NetconfMessage message) {
+        final RequestEntry req = new RequestEntry(GlobalEventExecutor.INSTANCE.<NetconfMessage>newPromise(), message);
+
+        requests.add(req);
+        if (clientSession != null) {
+            dispatchRequest();
+        }
+
+        return req.promise;
+    }
+}
index 7c5bd0cb21dcc25988c3e66c17f7821b3a780d11..bd39049c562fe8300fcccb053ec168adc02ad6f5 100644 (file)
@@ -12,14 +12,14 @@ import io.netty.channel.ChannelFuture;
 import io.netty.channel.EventLoopGroup;
 import io.netty.channel.socket.SocketChannel;
 import io.netty.util.concurrent.Promise;
-import org.opendaylight.controller.netconf.api.NetconfSession;
+
+import java.net.InetSocketAddress;
+
 import org.opendaylight.controller.netconf.impl.util.DeserializerExceptionHandler;
 import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
 import org.opendaylight.protocol.framework.AbstractDispatcher;
 
-import java.net.InetSocketAddress;
-
-public class NetconfServerDispatcher extends AbstractDispatcher<NetconfSession, NetconfServerSessionListener> {
+public class NetconfServerDispatcher extends AbstractDispatcher<NetconfServerSession, NetconfServerSessionListener> {
 
     private final ServerChannelInitializer initializer;
 
@@ -31,15 +31,15 @@ public class NetconfServerDispatcher extends AbstractDispatcher<NetconfSession,
 
     public ChannelFuture createServer(InetSocketAddress address) {
 
-        return super.createServer(address, new PipelineInitializer<NetconfSession>() {
+        return super.createServer(address, new PipelineInitializer<NetconfServerSession>() {
             @Override
-            public void initializeChannel(final SocketChannel ch, final Promise<NetconfSession> promise) {
+            public void initializeChannel(final SocketChannel ch, final Promise<NetconfServerSession> promise) {
                 initializer.initialize(ch, promise);
             }
         });
     }
 
-    public static class ServerChannelInitializer extends AbstractChannelInitializer {
+    public static class ServerChannelInitializer extends AbstractChannelInitializer<NetconfServerSession> {
 
         private final NetconfServerSessionNegotiatorFactory negotiatorFactory;
         private final NetconfServerSessionListenerFactory listenerFactory;
@@ -51,11 +51,10 @@ public class NetconfServerDispatcher extends AbstractDispatcher<NetconfSession,
         }
 
         @Override
-        protected void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+        protected void initializeAfterDecoder(SocketChannel ch, Promise<NetconfServerSession> promise) {
             ch.pipeline().addLast("deserializerExHandler", new DeserializerExceptionHandler());
             ch.pipeline().addLast("negotiator", negotiatorFactory.getSessionNegotiator(listenerFactory, ch, promise));
         }
-
     }
 
 }
index 1d22fa050b3510f7f14bc6ec8d3484a0b1eae845..93d4e5541084c084cc2f1a43e5d99ea063ffee9a 100644 (file)
@@ -15,11 +15,8 @@ import java.util.Date;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
+import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
-import org.opendaylight.protocol.framework.SessionListener;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.DomainName;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Host;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.monitoring.extension.rev131210.NetconfTcp;
@@ -37,7 +34,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
 
-public class NetconfServerSession extends NetconfSession implements NetconfManagementSession {
+public final class NetconfServerSession extends AbstractNetconfSession<NetconfServerSession, NetconfServerSessionListener> implements NetconfManagementSession {
 
     private static final Logger logger = LoggerFactory.getLogger(NetconfServerSession.class);
 
@@ -46,7 +43,7 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag
     private Date loginTime;
     private long inRpcSuccess, inRpcFail, outRpcError;
 
-    public NetconfServerSession(SessionListener<NetconfMessage, NetconfSession, NetconfTerminationReason> sessionListener, Channel channel, long sessionId,
+    public NetconfServerSession(NetconfServerSessionListener sessionListener, Channel channel, long sessionId,
             NetconfServerSessionNegotiator.AdditionalHeader header) {
         super(sessionListener, channel, sessionId);
         this.header = header;
@@ -108,9 +105,9 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag
 
     private Class<? extends Transport> getTransportForString(String transport) {
         switch(transport) {
-            case "ssh" : return NetconfSsh.class;
-            case "tcp" : return NetconfTcp.class;
-            default: throw new IllegalArgumentException("Unknown transport type " + transport);
+        case "ssh" : return NetconfSsh.class;
+        case "tcp" : return NetconfTcp.class;
+        default: throw new IllegalArgumentException("Unknown transport type " + transport);
         }
     }
 
@@ -119,4 +116,8 @@ public class NetconfServerSession extends NetconfSession implements NetconfManag
         return dateFormat.format(loginTime);
     }
 
+    @Override
+    protected NetconfServerSession thisInstance() {
+        return this;
+    }
 }
index 91555861dc4aaaa51fdfd69dd24ae9bb834f02e7..1303d1143500cfac3817723cc497adf8b44a303e 100644 (file)
@@ -8,33 +8,34 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import com.google.common.base.Optional;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+
+import java.net.InetSocketAddress;
+
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
 import org.opendaylight.controller.netconf.impl.util.AdditionalHeaderUtil;
 import org.opendaylight.controller.netconf.util.AbstractNetconfSessionNegotiator;
-import org.opendaylight.protocol.framework.SessionListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.net.InetSocketAddress;
+import com.google.common.base.Optional;
 
 public class NetconfServerSessionNegotiator extends
-        AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession> {
+        AbstractNetconfSessionNegotiator<NetconfServerSessionPreferences, NetconfServerSession, NetconfServerSessionListener> {
 
     static final Logger logger = LoggerFactory.getLogger(NetconfServerSessionNegotiator.class);
 
     protected NetconfServerSessionNegotiator(NetconfServerSessionPreferences sessionPreferences,
-            Promise<NetconfServerSession> promise, Channel channel, Timer timer, SessionListener sessionListener,
+            Promise<NetconfServerSession> promise, Channel channel, Timer timer, NetconfServerSessionListener sessionListener,
             long connectionTimeoutMillis) {
         super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
     }
 
     @Override
-    protected NetconfServerSession getSession(SessionListener sessionListener, Channel channel, NetconfMessage message) {
+    protected NetconfServerSession getSession(NetconfServerSessionListener sessionListener, Channel channel, NetconfMessage message) {
         Optional<String> additionalHeader = message.getAdditionalHeader();
 
         AdditionalHeader parsedHeader;
index 98462b8025ce965b596cfd323484164eaa7c97d1..8086b748d7e07e5c7d09bf29754847bf9d1526fd 100644 (file)
@@ -8,10 +8,15 @@
 
 package org.opendaylight.controller.netconf.impl;
 
-import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
 import io.netty.util.Timer;
 import io.netty.util.concurrent.Promise;
+
+import java.io.InputStream;
+
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfServerSessionPreferences;
 import org.opendaylight.controller.netconf.impl.mapping.CapabilityProvider;
@@ -27,11 +32,9 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
-import javax.xml.xpath.XPathConstants;
-import javax.xml.xpath.XPathExpression;
-import java.io.InputStream;
+import com.google.common.base.Preconditions;
 
-public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory {
+public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorFactory<NetconfMessage, NetconfServerSession, NetconfServerSessionListener> {
 
     public static final String SERVER_HELLO_XML_LOCATION = "/server_hello.xml";
 
@@ -59,8 +62,8 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     }
 
     @Override
-    public SessionNegotiator getSessionNegotiator(SessionListenerFactory sessionListenerFactory, Channel channel,
-            Promise promise) {
+    public SessionNegotiator<NetconfServerSession> getSessionNegotiator(SessionListenerFactory<NetconfServerSessionListener> sessionListenerFactory, Channel channel,
+            Promise<NetconfServerSession> promise) {
         long sessionId = idProvider.getNextSessionId();
 
         NetconfServerSessionPreferences proposal = new NetconfServerSessionPreferences(createHelloMessage(sessionId),
@@ -97,6 +100,6 @@ public class NetconfServerSessionNegotiatorFactory implements SessionNegotiatorF
     }
 
     private synchronized Document getHelloTemplateClone() {
-        return (Document) this.helloMessageTemplate.cloneNode(true);
+        return (Document) helloMessageTemplate.cloneNode(true);
     }
 }
index bc68db85de418d17f287529e2cb551291abb43c6..ece9d47ee9fcfe3a0e485347d450d6a7e7fd83e2 100644 (file)
@@ -234,10 +234,6 @@ public class NetconfOperationRouterImpl implements NetconfOperationRouter {
     private class NetconfOperationExecution implements NetconfOperationFilterChain {
         private final NetconfOperation operationWithHighestPriority;
 
-        private NetconfOperationExecution(NetconfOperation operationWithHighestPriority) {
-            this.operationWithHighestPriority = operationWithHighestPriority;
-        }
-
         public NetconfOperationExecution(TreeMap<HandlingPriority, Set<NetconfOperation>> sortedPriority,
                 HandlingPriority highestFoundPriority) {
             operationWithHighestPriority = sortedPriority.get(highestFoundPriority).iterator().next();
index 5b4b3d02ea8839b1dddbf5132d16157d0d325324..7068de8526eaf6c6a6f141cb2b77e1a262954ec8 100644 (file)
@@ -18,9 +18,9 @@ import org.opendaylight.controller.netconf.util.handler.NetconfMessageToXMLEncod
 import org.opendaylight.controller.netconf.util.handler.NetconfXMLToMessageDecoder;
 import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
 
-public abstract class AbstractChannelInitializer {
+public abstract class AbstractChannelInitializer<S extends NetconfSession> {
 
-    public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise){
+    public void initialize(SocketChannel ch, Promise<S> promise){
         ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM));
         ch.pipeline().addLast(new NetconfXMLToMessageDecoder());
         initializeAfterDecoder(ch, promise);
@@ -28,6 +28,6 @@ public abstract class AbstractChannelInitializer {
         ch.pipeline().addLast(new NetconfMessageToXMLEncoder());
     }
 
-    protected abstract void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise);
+    protected abstract void initializeAfterDecoder(SocketChannel ch, Promise<S> promise);
 
 }
index a485a4ea9436391d7433e91370f37481734d4e7b..9c35c7225f9adfae902667791f53854aa25a0246 100644 (file)
@@ -8,8 +8,6 @@
 
 package org.opendaylight.controller.netconf.util;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelHandlerContext;
@@ -20,8 +18,12 @@ import io.netty.util.TimerTask;
 import io.netty.util.concurrent.Future;
 import io.netty.util.concurrent.GenericFutureListener;
 import io.netty.util.concurrent.Promise;
+
+import java.util.concurrent.TimeUnit;
+
+import org.opendaylight.controller.netconf.api.AbstractNetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
+import org.opendaylight.controller.netconf.api.NetconfSessionListener;
 import org.opendaylight.controller.netconf.api.NetconfSessionPreferences;
 import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
 import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
@@ -31,23 +33,23 @@ import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.controller.netconf.util.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.protocol.framework.AbstractSessionNegotiator;
-import org.opendaylight.protocol.framework.SessionListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.NodeList;
 
-import java.util.concurrent.TimeUnit;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 
-public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionPreferences, S extends NetconfSession>
-        extends AbstractSessionNegotiator<NetconfMessage, S> {
+public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionPreferences, S extends AbstractNetconfSession<S, L>, L extends NetconfSessionListener<S>>
+extends AbstractSessionNegotiator<NetconfMessage, S> {
 
     private static final Logger logger = LoggerFactory.getLogger(AbstractNetconfSessionNegotiator.class);
     public static final String NAME_OF_EXCEPTION_HANDLER = "lastExceptionHandler";
 
     protected final P sessionPreferences;
 
-    private final SessionListener sessionListener;
+    private final L sessionListener;
     private Timeout timeout;
 
     /**
@@ -62,7 +64,7 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
     private final long connectionTimeoutMillis;
 
     protected AbstractNetconfSessionNegotiator(P sessionPreferences, Promise<S> promise, Channel channel, Timer timer,
-            SessionListener sessionListener, long connectionTimeoutMillis) {
+            L sessionListener, long connectionTimeoutMillis) {
         super(promise, channel);
         this.sessionPreferences = sessionPreferences;
         this.timer = timer;
@@ -168,7 +170,7 @@ public abstract class AbstractNetconfSessionNegotiator<P extends NetconfSessionP
         }
     }
 
-    protected abstract S getSession(SessionListener sessionListener, Channel channel, NetconfMessage message);
+    protected abstract S getSession(L sessionListener, Channel channel, NetconfMessage message);
 
     private boolean isHelloMessage(Document doc) {
         try {