Moving from a searching a string for capabilities to a Set.
ONOS-5947 ONOS-5948
Change-Id: Icac65263691e624dc74cfbc03c27e3974b935da2
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
index 7da836c..457bcf2 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
@@ -33,17 +33,20 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.regex.Pattern;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
/**
* Implementation of a NETCONF session to talk to a device.
@@ -85,16 +88,27 @@
private static final String SUBSCRIPTION_SUBTREE_FILTER_OPEN =
"<filter xmlns:base10=\"urn:ietf:params:xml:ns:netconf:base:1.0\" base10:type=\"subtree\">";
- private static Pattern msgIdPattern = Pattern.compile("(message-id=\"[0-9]+\")");
+ private static final String INTERLEAVE_CAPABILITY_STRING = "urn:ietf:params:netconf:capability:interleave:1.0";
+ private static final String CAPABILITY_REGEX = "<capability>\\s*(.*?)\\s*</capability>";
+ private static final Pattern CAPABILITY_REGEX_PATTERN = Pattern.compile(CAPABILITY_REGEX);
+
+ private static final String SESSION_ID_REGEX = "<session-id>\\s*(.*?)\\s*</session-id>";
+ private static final Pattern SESSION_ID_REGEX_PATTERN = Pattern.compile(SESSION_ID_REGEX);
+
+ private String sessionID;
private final AtomicInteger messageIdInteger = new AtomicInteger(0);
private Connection netconfConnection;
private NetconfDeviceInfo deviceInfo;
private Session sshSession;
private boolean connectionActive;
- private List<String> deviceCapabilities =
+ private Iterable<String> onosCapabilities =
Collections.singletonList("urn:ietf:params:netconf:base:1.0");
- private String serverCapabilities;
+
+ /* NOTE: the "serverHelloResponseOld" is deprecated in 1.10.0 and should eventually be removed */
+ @Deprecated
+ private String serverHelloResponseOld;
+ private final Set<String> deviceCapabilities = new LinkedHashSet<>();
private NetconfStreamHandler streamHandler;
private Map<Integer, CompletableFuture<String>> replies;
private List<String> errorReplies;
@@ -178,7 +192,7 @@
@Beta
private void startSubscriptionConnection(String filterSchema) throws NetconfException {
- if (!serverCapabilities.contains("interleave")) {
+ if (!deviceCapabilities.contains(INTERLEAVE_CAPABILITY_STRING)) {
throw new NetconfException("Device" + deviceInfo + "does not support interleave");
}
String reply = sendRequest(createSubscriptionString(filterSchema));
@@ -237,7 +251,20 @@
}
private void sendHello() throws NetconfException {
- serverCapabilities = sendRequest(createHelloString());
+ serverHelloResponseOld = sendRequest(createHelloString());
+ Matcher capabilityMatcher = CAPABILITY_REGEX_PATTERN.matcher(serverHelloResponseOld);
+ while (capabilityMatcher.find()) {
+ deviceCapabilities.add(capabilityMatcher.group(1));
+ }
+ sessionID = String.valueOf(-1);
+ Matcher sessionIDMatcher = SESSION_ID_REGEX_PATTERN.matcher(serverHelloResponseOld);
+ if (sessionIDMatcher.find()) {
+ sessionID = sessionIDMatcher.group(1);
+ } else {
+ throw new NetconfException("Missing SessionID in server hello " +
+ "reponse.");
+ }
+
}
private String createHelloString() {
@@ -246,7 +273,7 @@
hellobuffer.append("\n");
hellobuffer.append("<hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\">\n");
hellobuffer.append(" <capabilities>\n");
- deviceCapabilities.forEach(
+ onosCapabilities.forEach(
cap -> hellobuffer.append(" <capability>")
.append(cap)
.append("</capability>\n"));
@@ -594,29 +621,32 @@
@Override
public String getSessionId() {
- if (serverCapabilities.contains("<session-id>")) {
- String[] outer = serverCapabilities.split("<session-id>");
- Preconditions.checkArgument(outer.length != 1,
- "Error in retrieving the session id");
- String[] value = outer[1].split("</session-id>");
- Preconditions.checkArgument(value.length != 1,
- "Error in retrieving the session id");
- return value[0];
- } else {
- return String.valueOf(-1);
- }
+ return sessionID;
}
@Override
+ public Set<String> getDeviceCapabilitiesSet() {
+ return Collections.unmodifiableSet(deviceCapabilities);
+ }
+
+ @Deprecated
+ @Override
public String getServerCapabilities() {
- return serverCapabilities;
+ return serverHelloResponseOld;
+ }
+
+ @Deprecated
+ @Override
+ public void setDeviceCapabilities(List<String> capabilities) {
+ onosCapabilities = capabilities;
}
@Override
- public void setDeviceCapabilities(List<String> capabilities) {
- deviceCapabilities = capabilities;
+ public void setOnosCapabilities(Iterable<String> capabilities) {
+ onosCapabilities = capabilities;
}
+
@Override
public void addDeviceOutputListener(NetconfDeviceOutputEventListener listener) {
streamHandler.addDeviceEventListener(listener);
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfSessionImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfSessionImplTest.java
index 2dcb14f..86822a6 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfSessionImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/NetconfSessionImplTest.java
@@ -15,7 +15,9 @@
*/
package org.onosproject.netconf.ctl;
+import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertFalse;
@@ -24,6 +26,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Callable;
@@ -52,6 +55,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.collect.ImmutableList;
+
/**
* Unit tests for NetconfSession.
*
@@ -86,6 +91,20 @@
+ "</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;
@@ -93,7 +112,7 @@
@BeforeClass
public static void setUp() throws Exception {
sshServerNetconf = SshServer.setUpDefaultServer();
- List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<NamedFactory<UserAuth>>();
+ List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<>();
userAuthFactories.add(new UserAuthPassword.Factory());
sshServerNetconf.setUserAuthFactories(userAuthFactories);
sshServerNetconf.setPasswordAuthenticator(
@@ -120,11 +139,13 @@
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 NetconfSessionImpl(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
@@ -262,8 +283,8 @@
NCCopyConfigCallable testCopyConfig1 = new NCCopyConfigCallable(session1, RUNNING, "candidate");
NCCopyConfigCallable testCopyConfig2 = new NCCopyConfigCallable(session1, RUNNING, "startup");
- FutureTask<Boolean> futureCopyConfig1 = new FutureTask<Boolean>(testCopyConfig1);
- FutureTask<Boolean> futureCopyConfig2 = new FutureTask<Boolean>(testCopyConfig2);
+ 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");
@@ -288,8 +309,8 @@
NCCopyConfigCallable testCopySession1 = new NCCopyConfigCallable(session1, RUNNING, "candidate");
NCCopyConfigCallable testCopySession2 = new NCCopyConfigCallable(session2, RUNNING, "candidate");
- FutureTask<Boolean> futureCopySession1 = new FutureTask<Boolean>(testCopySession1);
- FutureTask<Boolean> futureCopySession2 = new FutureTask<Boolean>(testCopySession2);
+ 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");
@@ -311,20 +332,17 @@
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>");
- sb.append("<capability>urn:ietf:params:netconf:base:1.0</capability>");
- sb.append("<capability>urn:ietf:params:netconf:base:1.1</capability>");
- sb.append("<capability>urn:ietf:params:netconf:capability:writable-running:1.0</capability>");
- sb.append("<capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>");
- sb.append("<capability>urn:ietf:params:netconf:capability:startup:1.0</capability>");
- sb.append("<capability>urn:ietf:params:netconf:capability:rollback-on-error:1.0</capability>");
- sb.append("<capability>urn:ietf:params:netconf:capability:interleave:1.0</capability>");
- sb.append("<capability>urn:ietf:params:netconf:capability:notification:1.0</capability>");
- sb.append("<capability>urn:ietf:params:netconf:capability:validate:1.0</capability>");
- sb.append("<capability>urn:ietf:params:netconf:capability:validate:1.1</capability>");
+ capabilities.forEach(capability -> {
+ sb.append("<capability>").append(capability).append("</capability>");
+ });
sb.append("</capabilities>");
if (sessionId.isPresent()) {
sb.append("<session-id>");