[ONOS-6376] Netconf ssh connection through Apache Mina library

Change-Id: If69fd89afe3082debc3c28a06debfed53426635c
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfControllerImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfControllerImplTest.java
index 8287e6d..666b0ad 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfControllerImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfControllerImplTest.java
@@ -140,12 +140,13 @@
         assertEquals("Incorrect NetConf connect timeout, should be default",
                      5, ctrl.netconfConnectTimeout);
         assertEquals("Incorrect NetConf reply timeout, should be default",
-                5, ctrl.netconfReplyTimeout);
+                     5, ctrl.netconfReplyTimeout);
         ctrl.activate(null);
         assertEquals("Incorrect NetConf connect timeout, should be default",
                      5, ctrl.netconfConnectTimeout);
         assertEquals("Incorrect NetConf reply timeout, should be default",
-                5, ctrl.netconfReplyTimeout);    }
+                     5, ctrl.netconfReplyTimeout);
+    }
 
     /**
      * Test modification of component configuration.
@@ -153,14 +154,15 @@
     @Test
     public void testModified() {
         assertEquals("Incorrect NetConf connect timeout, should be default",
-                    5, ctrl.netconfConnectTimeout);
+                     5, ctrl.netconfConnectTimeout);
         assertEquals("Incorrect NetConf session timeout, should be default",
                      5, ctrl.netconfReplyTimeout);
         ctrl.modified(context);
         assertEquals("Incorrect NetConf connect timeout, should be default",
-                    2, ctrl.netconfConnectTimeout);
+                     2, ctrl.netconfConnectTimeout);
         assertEquals("Incorrect NetConf session timeout",
                      1, ctrl.netconfReplyTimeout);
+        assertEquals("ethz-ssh2", ctrl.sshLibrary);
     }
 
     /**
@@ -398,6 +400,8 @@
                 return "2";
             } else if (key.equals("netconfReplyTimeout")) {
                 return "1";
+            } else if (key.equals("sshLibrary")) {
+                return "ethz-ssh2";
             }
             return null;
         }
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
index 27223b8..846642c 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
@@ -24,7 +24,7 @@
 import static org.onosproject.netconf.TargetConfig.RUNNING;
 import static org.onosproject.netconf.TargetConfig.CANDIDATE;
 
-import java.util.ArrayList;
+import java.io.File;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
@@ -35,12 +35,10 @@
 import java.util.concurrent.FutureTask;
 import java.util.regex.Pattern;
 
-import org.apache.sshd.SshServer;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.server.Command;
-import org.apache.sshd.server.PasswordAuthenticator;
-import org.apache.sshd.server.UserAuth;
-import org.apache.sshd.server.auth.UserAuthPassword;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.auth.password.PasswordAuthenticator;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 import org.apache.sshd.server.session.ServerSession;
 import org.junit.AfterClass;
@@ -59,7 +57,7 @@
 
 /**
  * Unit tests for NetconfSession.
- *
+ * <p>
  * Sets up an SSH Server with Apache SSHD and connects to it using 2 clients
  * Truly verifies that the NETCONF flows are compliant with a NETCONF server.
  */
@@ -77,8 +75,8 @@
 
     private static final String SAMPLE_REQUEST =
             "<some-yang-element xmlns=\"some-namespace\">"
-            + "<some-child-element/>"
-            + "</some-yang-element>";
+                    + "<some-child-element/>"
+                    + "</some-yang-element>";
 
     private static final String EDIT_CONFIG_REQUEST =
             "<?xml version=\"1.0\" encoding=\"UTF-8\"?><rpc message-id=\"6\"  "
@@ -112,9 +110,6 @@
     @BeforeClass
     public static void setUp() throws Exception {
         sshServerNetconf = SshServer.setUpDefaultServer();
-        List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<>();
-        userAuthFactories.add(new UserAuthPassword.Factory());
-        sshServerNetconf.setUserAuthFactories(userAuthFactories);
         sshServerNetconf.setPasswordAuthenticator(
                 new PasswordAuthenticator() {
                     @Override
@@ -126,7 +121,9 @@
                     }
                 });
         sshServerNetconf.setPort(PORT_NUMBER);
-        sshServerNetconf.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(TEST_SERFILE));
+        SimpleGeneratorHostKeyProvider provider = new SimpleGeneratorHostKeyProvider();
+        provider.setFile(new File(TEST_SERFILE));
+        sshServerNetconf.setKeyPairProvider(provider);
         sshServerNetconf.setSubsystemFactories(
                 Arrays.<NamedFactory<Command>>asList(new NetconfSshdTestSubsystem.Factory()));
         sshServerNetconf.open();
@@ -224,10 +221,10 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF get-config running command failed. ",
-                    GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
+                       GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
 
             assertTrue("NETCONF get-config candidate command failed. ",
-                    GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
+                       GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
 
         } catch (NetconfException e) {
             e.printStackTrace();
@@ -242,7 +239,7 @@
         assertNotNull("Incorrect sessionId", session1.getSessionId());
         try {
             assertTrue("NETCONF get running command failed. ",
-                    GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST, null)).matches());
+                       GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST, null)).matches());
 
         } catch (NetconfException e) {
             e.printStackTrace();
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java
new file mode 100644
index 0000000..d8c1202
--- /dev/null
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImplTest.java
@@ -0,0 +1,472 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.netconf.ctl.impl;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.auth.password.PasswordAuthenticator;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.apache.sshd.server.session.ServerSession;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onlab.junit.TestTools;
+import org.onlab.packet.Ip4Address;
+import org.onosproject.netconf.NetconfDeviceInfo;
+import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.NetconfSession;
+import org.onosproject.netconf.TargetConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.FutureTask;
+import java.util.regex.Pattern;
+
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.junit.Assert.*;
+import static org.onosproject.netconf.TargetConfig.CANDIDATE;
+import static org.onosproject.netconf.TargetConfig.RUNNING;
+
+/**
+ * Unit tests for NetconfSession.
+ * <p>
+ * Sets up an SSH Server with Apache SSHD and connects to it using 2 clients
+ * Truly verifies that the NETCONF flows are compliant with a NETCONF server.
+ */
+public class NetconfSessionMinaImplTest {
+    private static final Logger log = LoggerFactory
+            .getLogger(NetconfStreamThread.class);
+
+    private static final int PORT_NUMBER = TestTools.findAvailablePort(50830);
+    private static final String TEST_USERNAME = "netconf";
+    private static final String TEST_PASSWORD = "netconf123";
+    private static final String TEST_HOSTNAME = "127.0.0.1";
+
+    private static final String TEST_SERFILE =
+            System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + "testkey.ser";
+
+    private static final String SAMPLE_REQUEST =
+            "<some-yang-element xmlns=\"some-namespace\">"
+                    + "<some-child-element/>"
+                    + "</some-yang-element>";
+
+    private static final String EDIT_CONFIG_REQUEST =
+            "<?xml version=\"1.0\" encoding=\"UTF-8\"?><rpc message-id=\"6\"  "
+                    + "xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+                    + "<edit-config>\n"
+                    + "<target><running/></target>\n"
+                    + "<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n"
+                    + "<some-yang-element xmlns=\"some-namespace\">"
+                    + "<some-child-element/></some-yang-element></config>\n"
+                    + "</edit-config>\n"
+                    + "</rpc>]]>]]>";
+
+    static final List<String> DEFAULT_CAPABILITIES = ImmutableList.<String>builder()
+            .add("urn:ietf:params:netconf:base:1.0")
+            .add("urn:ietf:params:netconf:base:1.1")
+            .add("urn:ietf:params:netconf:capability:writable-running:1.0")
+            .add("urn:ietf:params:netconf:capability:candidate:1.0")
+            .add("urn:ietf:params:netconf:capability:startup:1.0")
+            .add("urn:ietf:params:netconf:capability:rollback-on-error:1.0")
+            .add("urn:ietf:params:netconf:capability:interleave:1.0")
+            .add("urn:ietf:params:netconf:capability:notification:1.0")
+            .add("urn:ietf:params:netconf:capability:validate:1.0")
+            .add("urn:ietf:params:netconf:capability:validate:1.1")
+            .build();
+
+
+    private static NetconfSession session1;
+    private static NetconfSession session2;
+    private static SshServer sshServerNetconf;
+
+    @BeforeClass
+    public static void setUp() throws Exception {
+        sshServerNetconf = SshServer.setUpDefaultServer();
+        sshServerNetconf.setPasswordAuthenticator(
+                new PasswordAuthenticator() {
+                    @Override
+                    public boolean authenticate(
+                            String username,
+                            String password,
+                            ServerSession session) {
+                        return TEST_USERNAME.equals(username) && TEST_PASSWORD.equals(password);
+                    }
+                });
+        sshServerNetconf.setPort(PORT_NUMBER);
+        SimpleGeneratorHostKeyProvider provider = new SimpleGeneratorHostKeyProvider();
+        provider.setFile(new File(TEST_SERFILE));
+        sshServerNetconf.setKeyPairProvider(provider);
+        sshServerNetconf.setSubsystemFactories(
+                Arrays.<NamedFactory<Command>>asList(new NetconfSshdTestSubsystem.Factory()));
+        sshServerNetconf.open();
+        log.info("SSH Server opened on port {}", PORT_NUMBER);
+
+        NetconfDeviceInfo deviceInfo = new NetconfDeviceInfo(
+                TEST_USERNAME, TEST_PASSWORD, Ip4Address.valueOf(TEST_HOSTNAME), PORT_NUMBER);
+
+        session1 = new NetconfSessionMinaImpl(deviceInfo);
+        log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session1.getSessionId());
+        assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("-1"));
+        assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("0"));
+        assertThat(session1.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
+
+        session2 = new NetconfSessionMinaImpl(deviceInfo);
+        log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session2.getSessionId());
+        assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("-1"));
+        assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("0"));
+        assertThat(session2.getDeviceCapabilitiesSet(), containsInAnyOrder(DEFAULT_CAPABILITIES.toArray()));
+    }
+
+    @AfterClass
+    public static void tearDown() throws Exception {
+        if (session1 != null) {
+            session1.close();
+        }
+        if (session2 != null) {
+            session2.close();
+        }
+
+        sshServerNetconf.stop();
+    }
+
+    @Test
+    public void testEditConfigRequest() {
+        log.info("Starting edit-config async");
+        assertNotNull("Incorrect sessionId", session1.getSessionId());
+        try {
+            assertTrue("NETCONF edit-config command failed",
+                       session1.editConfig(TargetConfig.RUNNING.toString(),
+                                           null, SAMPLE_REQUEST));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF edit-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing edit-config async");
+    }
+
+    @Test
+    public void testEditConfigRequestWithOnlyNewConfiguration() {
+        log.info("Starting edit-config async");
+        assertNotNull("Incorrect sessionId", session1.getSessionId());
+        try {
+            assertTrue("NETCONF edit-config command failed",
+                       session1.editConfig(EDIT_CONFIG_REQUEST));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF edit-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing edit-config async");
+    }
+
+    @Test
+    public void testDeleteConfigRequestWithRunningTargetConfiguration() {
+        log.info("Starting delete-config async");
+        assertNotNull("Incorrect sessionId", session1.getSessionId());
+        try {
+            assertFalse("NETCONF delete-config command failed",
+                        session1.deleteConfig(TargetConfig.RUNNING));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF delete-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing delete-config async");
+    }
+
+    @Test
+    public void testCopyConfigRequest() {
+        log.info("Starting copy-config async");
+        assertNotNull("Incorrect sessionId", session1.getSessionId());
+        try {
+            assertTrue("NETCONF copy-config command failed",
+                       session1.copyConfig(TargetConfig.RUNNING.toString(),
+                                           "candidate"));
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF edit-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing copy-config async");
+    }
+
+    @Test
+    public void testGetConfigRequest() {
+        log.info("Starting get-config async");
+        assertNotNull("Incorrect sessionId", session1.getSessionId());
+        try {
+            assertTrue("NETCONF get-config running command failed. ",
+                       GET_REPLY_PATTERN.matcher(session1.getConfig(RUNNING, SAMPLE_REQUEST)).matches());
+
+            assertTrue("NETCONF get-config candidate command failed. ",
+                       GET_REPLY_PATTERN.matcher(session1.getConfig(CANDIDATE, SAMPLE_REQUEST)).matches());
+
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF get-config test failed: " + e.getMessage());
+        }
+        log.info("Finishing get-config async");
+    }
+
+    @Test
+    public void testGetRequest() {
+        log.info("Starting get async");
+        assertNotNull("Incorrect sessionId", session1.getSessionId());
+        try {
+            assertTrue("NETCONF get running command failed. ",
+                       GET_REPLY_PATTERN.matcher(session1.get(SAMPLE_REQUEST, null)).matches());
+
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF get test failed: " + e.getMessage());
+        }
+        log.info("Finishing get async");
+    }
+
+    @Test
+    public void testLockRequest() {
+        log.info("Starting lock async");
+        assertNotNull("Incorrect sessionId", session1.getSessionId());
+        try {
+            assertTrue("NETCONF lock request failed", session1.lock());
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF lock test failed: " + e.getMessage());
+        }
+        log.info("Finishing lock async");
+    }
+
+    @Test
+    public void testUnLockRequest() {
+        log.info("Starting unlock async");
+        assertNotNull("Incorrect sessionId", session1.getSessionId());
+        try {
+            assertTrue("NETCONF unlock request failed", session1.unlock());
+        } catch (NetconfException e) {
+            e.printStackTrace();
+            fail("NETCONF unlock test failed: " + e.getMessage());
+        }
+        log.info("Finishing unlock async");
+    }
+
+
+    @Test
+    public void testConcurrentSameSessionAccess() throws InterruptedException {
+        NCCopyConfigCallable testCopyConfig1 = new NCCopyConfigCallable(session1, RUNNING, "candidate");
+        NCCopyConfigCallable testCopyConfig2 = new NCCopyConfigCallable(session1, RUNNING, "startup");
+
+        FutureTask<Boolean> futureCopyConfig1 = new FutureTask<>(testCopyConfig1);
+        FutureTask<Boolean> futureCopyConfig2 = new FutureTask<>(testCopyConfig2);
+
+        ExecutorService executor = Executors.newFixedThreadPool(2);
+        log.info("Starting concurrent execution of copy-config through same session");
+        executor.execute(futureCopyConfig1);
+        executor.execute(futureCopyConfig2);
+
+        int count = 0;
+        while (count < 10) {
+            if (futureCopyConfig1.isDone() && futureCopyConfig2.isDone()) {
+                executor.shutdown();
+                log.info("Finished concurrent same session execution");
+                return;
+            }
+            Thread.sleep(100L);
+            count++;
+        }
+        fail("NETCONF test failed to complete.");
+    }
+
+    @Test
+    public void test2SessionAccess() throws InterruptedException {
+        NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session1, RUNNING, "candidate");
+        NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session2, RUNNING, "candidate");
+
+        FutureTask<Boolean> futureCopySession1 = new FutureTask<>(testCopySession1);
+        FutureTask<Boolean> futureCopySession2 = new FutureTask<>(testCopySession2);
+
+        ExecutorService executor = Executors.newFixedThreadPool(2);
+        log.info("Starting concurrent execution of copy-config through 2 different sessions");
+        executor.execute(futureCopySession1);
+        executor.execute(futureCopySession2);
+
+        int count = 0;
+        while (count < 10) {
+            if (futureCopySession1.isDone() && futureCopySession2.isDone()) {
+                executor.shutdown();
+                log.info("Finished concurrent 2 session execution");
+                return;
+            }
+            Thread.sleep(100L);
+            count++;
+        }
+        fail("NETCONF test failed to complete.");
+    }
+
+
+    public static String getTestHelloReply(Optional<Long> sessionId) {
+        return getTestHelloReply(DEFAULT_CAPABILITIES, sessionId);
+    }
+
+    public static String getTestHelloReply(Collection<String> capabilities, Optional<Long> sessionId) {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">");
+        sb.append("<capabilities>");
+        capabilities.forEach(capability -> {
+            sb.append("<capability>").append(capability).append("</capability>");
+        });
+        sb.append("</capabilities>");
+        if (sessionId.isPresent()) {
+            sb.append("<session-id>");
+            sb.append(sessionId.get().toString());
+            sb.append("</session-id>");
+        }
+        sb.append("</hello>");
+
+        return sb.toString();
+    }
+
+    public static String getOkReply(Optional<Integer> messageId) {
+        StringBuffer sb = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+        sb.append("<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ");
+        if (messageId.isPresent()) {
+            sb.append("message-id=\"");
+            sb.append(String.valueOf(messageId.get()));
+            sb.append("\">");
+        }
+        sb.append("<ok/>");
+        sb.append("</rpc-reply>");
+        return sb.toString();
+    }
+
+    public static String getGetReply(Optional<Integer> messageId) {
+        StringBuffer sb = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+        sb.append("<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" ");
+        if (messageId.isPresent()) {
+            sb.append("message-id=\"");
+            sb.append(String.valueOf(messageId.get()));
+            sb.append("\">");
+        }
+        sb.append("<data>\n");
+        sb.append(SAMPLE_REQUEST);
+        sb.append("</data>\n");
+        sb.append("</rpc-reply>");
+        return sb.toString();
+    }
+
+    public static final Pattern HELLO_REQ_PATTERN =
+            Pattern.compile("(<\\?xml).*"
+                    + "(<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                    + "( *)(<capabilities>)\\R?"
+                    + "( *)(<capability>urn:ietf:params:netconf:base:1.0</capability>)\\R?"
+                    + "( *)(</capabilities>)\\R?"
+                    + "(</hello>)\\R? *",
+                    Pattern.DOTALL);
+
+    public static final Pattern EDIT_CONFIG_REQ_PATTERN =
+            Pattern.compile("(<\\?xml).*"
+                    + "(<rpc message-id=\")[0-9]*(\") *(xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                    + "(<edit-config>)\\R?"
+                    + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
+                                    + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
+                                    + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                    + "(<config xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                    + ".*"
+                    + "(</config>)\\R?(</edit-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+
+
+    public static final Pattern LOCK_REQ_PATTERN =
+            Pattern.compile("(<\\?xml).*"
+                                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+                                    + "message-id=\")[0-9]*(\">)\\R?"
+                                    + "(<lock>)\\R?"
+                                    + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
+                                    + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
+                                    + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                                    + "(</lock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+
+    public static final Pattern UNLOCK_REQ_PATTERN =
+            Pattern.compile("(<\\?xml).*"
+                                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" "
+                                    + "message-id=\")[0-9]*(\">)\\R?"
+                                    + "(<unlock>)\\R?"
+                                    + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
+                                    + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
+                                    + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                                    + "(</unlock>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+
+    public static final Pattern COPY_CONFIG_REQ_PATTERN =
+            Pattern.compile("(<\\?xml).*"
+                    + "(<rpc xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\")[0-9]*(\">)\\R?"
+                    + "(<copy-config>)\\R?"
+                    + "(<target>\\R?((<" + TargetConfig.CANDIDATE.toString() + "/>)|"
+                                    + "(<" + TargetConfig.RUNNING.toString() + "/>)|"
+                                    + "(<" + TargetConfig.STARTUP.toString() + "/>))\\R?</target>)\\R?"
+                                    + "(<source>)\\R?(<config>)(("
+                                    + TargetConfig.CANDIDATE.toString() + ")|("
+                                    + TargetConfig.RUNNING.toString() + ")|("
+                                    + TargetConfig.STARTUP.toString()
+                                    + "))(</config>)\\R?(</source>)\\R?"
+                                    + "(</copy-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+
+    public static final Pattern GET_CONFIG_REQ_PATTERN =
+            Pattern.compile("(<\\?xml).*"
+                    + "(<rpc message-id=\")[0-9]*(\"  xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                    + "(<get-config>)\\R?" + "(<source>)\\R?((<"
+                                    + TargetConfig.CANDIDATE.toString()
+                                    + "/>)|(<" + TargetConfig.RUNNING.toString()
+                                    + "/>)|(<" + TargetConfig.STARTUP.toString()
+                                    + "/>))\\R?(</source>)\\R?"
+                    + "(<filter type=\"subtree\">).*(</filter>)\\R?"
+                    + "(</get-config>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+
+    public static final Pattern GET_REPLY_PATTERN =
+            Pattern.compile("(<\\?xml).*"
+                    + "(<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" message-id=\")[0-9]*(\">)\\R?"
+                    + "(<data>).*(</data>)\\R?"
+                    + "(</rpc-reply>)\\R?", Pattern.DOTALL);
+
+    public static final Pattern GET_REQ_PATTERN =
+            Pattern.compile("(<\\?xml).*"
+                    + "(<rpc message-id=\")[0-9]*(\"  xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">)\\R?"
+                    + "(<get>)\\R?"
+                    + "(<filter type=\"subtree\">).*(</filter>)\\R?"
+                    + "(</get>)\\R?(</rpc>)\\R?", Pattern.DOTALL);
+
+    public class NCCopyConfigCallable implements Callable<Boolean> {
+        private NetconfSession session;
+        private TargetConfig target;
+        private String source;
+
+        public NCCopyConfigCallable(NetconfSession session, TargetConfig target, String source) {
+            this.session = session;
+            this.target = target;
+            this.source = source;
+        }
+
+        @Override
+        public Boolean call() throws Exception {
+            return session.copyConfig(target, source);
+        }
+    }
+}
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java
index af1134c..cc1cbf9 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSshdTestSubsystem.java
@@ -22,14 +22,15 @@
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
 import java.util.Collection;
 import java.util.Optional;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 
 import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.common.util.ThreadUtils;
+import org.apache.sshd.common.util.threads.ThreadUtils;
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
@@ -188,11 +189,12 @@
                         deviceRequest = deviceRequest.replace(END_PATTERN, "");
                         Optional<Integer> messageId = NetconfStreamThread.getMsgId(deviceRequest);
                         log.info("Client Request on session {}. MsgId {}: {}",
-                                session.getId(), messageId, deviceRequest);
+                                session.getSessionId(), messageId, deviceRequest);
                         synchronized (outputStream) {
                             if (NetconfSessionImplTest.HELLO_REQ_PATTERN.matcher(deviceRequest).matches()) {
                                 String helloReply =
-                                        NetconfSessionImplTest.getTestHelloReply(Optional.of(session.getId()));
+                                        NetconfSessionImplTest.getTestHelloReply(Optional.of(ByteBuffer.wrap(
+                                                session.getSessionId()).asLongBuffer().get()));
                                 outputStream.write(helloReply + END_PATTERN);
                                 outputStream.flush();
                             } else if (NetconfSessionImplTest.EDIT_CONFIG_REQ_PATTERN.matcher(deviceRequest).matches()
@@ -211,7 +213,8 @@
                                 outputStream.flush();
                             } else {
                                 log.error("Unexpected NETCONF message structure on session {} : {}",
-                                        session.getId(), deviceRequest);
+                                          ByteBuffer.wrap(
+                                                  session.getSessionId()).asLongBuffer().get(), deviceRequest);
                             }
                         }
                         deviceRequestBuilder.setLength(0);