From 66bd3fc5062fe4d39bec663e14361c3bf1673712 Mon Sep 17 00:00:00 2001 From: Jonas Glass Date: Thu, 11 Jul 2019 16:21:32 +0200 Subject: [PATCH 1/3] - NETCONF RFC6241 and RFC6242 conformance fixes . xml version conformance . hello message conformance . rpc message conformance . framing protocol conformance - Extracting reused strings to constants - updated gitignore --- .gitignore | 9 + src/main/java/net/juniper/netconf/Device.java | 122 +++-- .../net/juniper/netconf/NetconfConstants.java | 31 ++ .../net/juniper/netconf/NetconfSession.java | 491 +++++++++--------- 4 files changed, 353 insertions(+), 300 deletions(-) create mode 100644 src/main/java/net/juniper/netconf/NetconfConstants.java diff --git a/.gitignore b/.gitignore index 2bec5cf..29195b7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,12 @@ target .settings .project .classpath + +# IntelliJ # +*.iml +.idea/ +.gradle/ +gradle/ +libraries/ +gradlew +gradlew.bat \ No newline at end of file diff --git a/src/main/java/net/juniper/netconf/Device.java b/src/main/java/net/juniper/netconf/Device.java index db990a8..06856db 100644 --- a/src/main/java/net/juniper/netconf/Device.java +++ b/src/main/java/net/juniper/netconf/Device.java @@ -7,11 +7,7 @@ package net.juniper.netconf; -import com.jcraft.jsch.ChannelExec; -import com.jcraft.jsch.ChannelSubsystem; -import com.jcraft.jsch.JSch; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.Session; +import com.jcraft.jsch.*; import lombok.Builder; import lombok.Getter; import lombok.NonNull; @@ -34,7 +30,7 @@ * A Device is used to define a Netconf server. *

* A new device is created using the Device.Builder.build() - * + *

* Example: *

  * {@code}
@@ -121,7 +117,7 @@ public Device(
             throw new NetconfException("Strict Host Key checking requires setting the hostKeysFileName");
         }
 
-        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance() ;
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         try {
             builder = factory.newDocumentBuilder();
         } catch (ParserConfigurationException e) {
@@ -143,23 +139,24 @@ public Device(
      */
     private List getDefaultClientCapabilities() {
         List defaultCap = new ArrayList<>();
-        defaultCap.add("urn:ietf:params:xml:ns:netconf:base:1.0");
-        defaultCap.add("urn:ietf:params:xml:ns:netconf:base:1.0#candidate");
-        defaultCap.add("urn:ietf:params:xml:ns:netconf:base:1.0#confirmed-commit");
-        defaultCap.add("urn:ietf:params:xml:ns:netconf:base:1.0#validate");
-        defaultCap.add("urn:ietf:params:xml:ns:netconf:base:1.0#url?protocol=http,ftp,file");
+        defaultCap.add(NetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0);
+        defaultCap.add(NetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0 + "#candidate");
+        defaultCap.add(NetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0 + "#confirmed-commit");
+        defaultCap.add(NetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0 + "#validate");
+        defaultCap.add(NetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0 + "#url?protocol=http,ftp,file");
         return defaultCap;
     }
 
     /**
      * Given a list of netconf capabilities, generate the netconf hello rpc message.
+     * https://tools.ietf.org/html/rfc6241#section-8.1
      *
      * @param capabilities A list of netconf capabilities
      * @return the hello RPC that represents those capabilities.
      */
     private String createHelloRPC(List capabilities) {
         StringBuilder helloRPC = new StringBuilder();
-        helloRPC.append("\n");
+        helloRPC.append("\n");
         helloRPC.append("\n");
         for (Object o : capabilities) {
             String capability = (String) o;
@@ -170,17 +167,17 @@ private String createHelloRPC(List capabilities) {
         }
         helloRPC.append("\n");
         helloRPC.append("\n");
-        helloRPC.append("]]>]]>\n");
+        helloRPC.append(NetconfConstants.DEVICE_PROMPT);
         return helloRPC.toString();
     }
 
     /**
-         * Create a new Netconf session.
-         *
-         * @return NetconfSession
-         * @throws NetconfException if there are issues communicating with the Netconf server.
-         */
-        private NetconfSession createNetconfSession() throws NetconfException {
+     * Create a new Netconf session.
+     *
+     * @return NetconfSession
+     * @throws NetconfException if there are issues communicating with the Netconf server.
+     */
+    private NetconfSession createNetconfSession() throws NetconfException {
         if (!isConnected()) {
             sshClient = new JSch();
 
@@ -308,7 +305,6 @@ private boolean isSessionConnected() {
      * Close the connection to the Netconf server. All associated Netconf
      * sessions will be closed, too. Can be called at any time. Don't forget to
      * call this once you don't need the device anymore.
-     *
      */
     public void close() {
         if (!isConnected()) {
@@ -331,7 +327,7 @@ public String runShellCommand(String command) throws IOException {
         }
         ChannelExec channel;
         try {
-            channel = (ChannelExec)sshSession.openChannel("exec");
+            channel = (ChannelExec) sshSession.openChannel("exec");
         } catch (JSchException e) {
             throw new NetconfException(String.format("Failed to open exec session: %s", e.getMessage()));
         }
@@ -376,7 +372,7 @@ public BufferedReader runShellCommandRunning(String command)
         }
         ChannelExec channel;
         try {
-            channel = (ChannelExec)sshSession.openChannel("exec");
+            channel = (ChannelExec) sshSession.openChannel("exec");
         } catch (JSchException e) {
             throw new NetconfException(String.format("Failed to open exec session: %s", e.getMessage()));
         }
@@ -396,7 +392,7 @@ public BufferedReader runShellCommandRunning(String command)
      *                   "get-chassis-inventory" OR
      *                   "<rpc><get-chassis-inventory/></rpc>"
      * @return RPC reply sent by Netconf server
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public XML executeRPC(String rpcContent) throws SAXException, IOException {
@@ -415,7 +411,7 @@ public XML executeRPC(String rpcContent) throws SAXException, IOException {
      * @param rpc RPC to be sent. Use the XMLBuilder to create RPC as an
      *            XML object.
      * @return RPC reply sent by Netconf server
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public XML executeRPC(XML rpc) throws SAXException, IOException {
@@ -433,7 +429,7 @@ public XML executeRPC(XML rpc) throws SAXException, IOException {
      *
      * @param rpcDoc RPC content to be sent, as a org.w3c.dom.Document object.
      * @return RPC reply sent by Netconf server
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public XML executeRPC(Document rpcDoc) throws SAXException, IOException {
@@ -525,8 +521,8 @@ public String getSessionId() {
      * Check if the last RPC reply returned from Netconf server has any error.
      *
      * @return true if any errors are found in last RPC reply.
-     * @throws SAXException if there are issues parsing XML from the device.
-     * @throws IOException if there are issues communicating with the device.
+     * @throws SAXException          if there are issues parsing XML from the device.
+     * @throws IOException           if there are issues communicating with the device.
      * @throws IllegalStateException if the connection is not established
      */
     public boolean hasError() throws SAXException, IOException {
@@ -542,7 +538,7 @@ public boolean hasError() throws SAXException, IOException {
      *
      * @return true if any errors are found in last RPC reply.
      * @throws SAXException if there are issues parsing XML from the device.
-     * @throws IOException if there are issues communicating with the device.
+     * @throws IOException  if there are issues communicating with the device.
      */
     public boolean hasWarning() throws SAXException, IOException {
         if (netconfSession == null) {
@@ -571,9 +567,9 @@ public boolean isOK() {
      * Locks the candidate configuration.
      *
      * @return true if successful.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
-     * @throws IllegalStateException if the connection is not established
+     * @throws IllegalStateException    if the connection is not established
      */
     public boolean lockConfig() throws IOException, SAXException {
         if (netconfSession == null) {
@@ -587,7 +583,7 @@ public boolean lockConfig() throws IOException, SAXException {
      * Unlocks the candidate configuration.
      *
      * @return true if successful.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public boolean unlockConfig() throws IOException, SAXException {
@@ -606,7 +602,7 @@ public boolean unlockConfig() throws IOException, SAXException {
      *                      <services/></system></configuration/>"
      *                      will load 'ftp' under the 'systems services' hierarchy.
      * @param loadType      You can choose "merge" or "replace" as the loadType.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public void loadXMLConfiguration(String configuration, String loadType)
@@ -630,7 +626,7 @@ public void loadXMLConfiguration(String configuration, String loadType)
      *                      }"
      *                      will load 'ftp' under the 'systems services' hierarchy.
      * @param loadType      You can choose "merge" or "replace" as the loadType.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public void loadTextConfiguration(String configuration, String loadType)
@@ -651,7 +647,7 @@ public void loadTextConfiguration(String configuration, String loadType)
      *                      "set system services ftp"
      *                      will load 'ftp' under the 'systems services' hierarchy.
      *                      To load multiple set statements, separate them by '\n' character.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public void loadSetConfiguration(String configuration) throws
@@ -671,7 +667,7 @@ public void loadSetConfiguration(String configuration) throws
      * @param configFile Path name of file containing configuration,in xml format,
      *                   to be loaded.
      * @param loadType   You can choose "merge" or "replace" as the loadType.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public void loadXMLFile(String configFile, String loadType)
@@ -690,7 +686,7 @@ public void loadXMLFile(String configFile, String loadType)
      * @param configFile Path name of file containing configuration,in xml format,
      *                   to be loaded.
      * @param loadType   You can choose "merge" or "replace" as the loadType.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public void loadTextFile(String configFile, String loadType)
@@ -709,7 +705,7 @@ public void loadTextFile(String configFile, String loadType)
      *
      * @param configFile Path name of file containing configuration,in set format,
      *                   to be loaded.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public void loadSetFile(String configFile) throws
@@ -725,8 +721,8 @@ public void loadSetFile(String configFile) throws
      * Commit the candidate configuration.
      *
      * @throws net.juniper.netconf.CommitException if there was an error committing the configuration.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
-     * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
+     * @throws java.io.IOException                 If there are errors communicating with the netconf server.
+     * @throws org.xml.sax.SAXException            If there are errors parsing the XML reply.
      */
     public void commit() throws CommitException, IOException, SAXException {
         if (netconfSession == null) {
@@ -743,8 +739,8 @@ public void commit() throws CommitException, IOException, SAXException {
      * @param seconds Time in seconds, after which the previous active configuration
      *                is reverted back to.
      * @throws net.juniper.netconf.CommitException if there was an error committing the configuration.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
-     * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
+     * @throws java.io.IOException                 If there are errors communicating with the netconf server.
+     * @throws org.xml.sax.SAXException            If there are errors parsing the XML reply.
      */
     public void commitConfirm(long seconds) throws CommitException, IOException,
             SAXException {
@@ -760,8 +756,8 @@ public void commitConfirm(long seconds) throws CommitException, IOException,
      * check the configuration for changes. A normal commit only signals processes where there data has been modified.
      *
      * @throws CommitException if there is an error committing the config.
-     * @throws IOException if there is an error communicating with the Netconf server.
-     * @throws SAXException if there is an error parsing the XML Netconf response.
+     * @throws IOException     if there is an error communicating with the Netconf server.
+     * @throws SAXException    if there is an error parsing the XML Netconf response.
      */
     public void commitFull() throws CommitException, IOException, SAXException {
         if (netconfSession == null) {
@@ -776,21 +772,21 @@ public void commitFull() throws CommitException, IOException, SAXException {
      * text/xml format.
      *
      * @param configFile Path name of file containing configuration,in text/xml format,
-     *  to be loaded. For example,
-     *  " system {
-     *      services {
-     *        ftp;
-     *      }
-     *    }"
-     *  will load 'ftp' under the 'systems services' hierarchy.
-     *  OR
-     *  "<configuration><system><services><ftp/><
-     *  services/></system></configuration/>"
-     *  will load 'ftp' under the 'systems services' hierarchy.
+     *                   to be loaded. For example,
+     *                   " system {
+     *                   services {
+     *                   ftp;
+     *                   }
+     *                   }"
+     *                   will load 'ftp' under the 'systems services' hierarchy.
+     *                   OR
+     *                   "<configuration><system><services><ftp/><
+     *                   services/></system></configuration/>"
+     *                   will load 'ftp' under the 'systems services' hierarchy.
      * @param loadType   You can choose "merge" or "replace" as the loadType.
      * @throws net.juniper.netconf.CommitException if there was an error committing the configuration.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
-     * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
+     * @throws java.io.IOException                 If there are errors communicating with the netconf server.
+     * @throws org.xml.sax.SAXException            If there are errors parsing the XML reply.
      */
     public void commitThisConfiguration(String configFile, String loadType)
             throws CommitException, IOException, SAXException {
@@ -808,7 +804,7 @@ public void commitThisConfiguration(String configFile, String loadType)
      *                   For example, to get the whole configuration, argument should be
      *                   <configuration></configuration>
      * @return configuration data as XML object.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public XML getCandidateConfig(String configTree) throws SAXException,
@@ -827,7 +823,7 @@ public XML getCandidateConfig(String configTree) throws SAXException,
      *                   For example, to get the whole configuration, argument should be
      *                   <configuration></configuration>
      * @return configuration data as XML object.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public XML getRunningConfig(String configTree) throws SAXException,
@@ -843,7 +839,7 @@ public XML getRunningConfig(String configTree) throws SAXException,
      * Retrieve the whole candidate configuration.
      *
      * @return configuration data as XML object.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public XML getCandidateConfig() throws SAXException, IOException {
@@ -858,7 +854,7 @@ public XML getCandidateConfig() throws SAXException, IOException {
      * Retrieve the whole running configuration.
      *
      * @return configuration data as XML object.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public XML getRunningConfig() throws SAXException, IOException {
@@ -873,7 +869,7 @@ public XML getRunningConfig() throws SAXException, IOException {
      * Validate the candidate configuration.
      *
      * @return true if validation successful.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public boolean validate() throws IOException, SAXException {
@@ -890,7 +886,7 @@ public boolean validate() throws IOException, SAXException {
      *
      * @param command the cli command to be executed.
      * @return result of the command.
-     * @throws java.io.IOException If there are errors communicating with the netconf server.
+     * @throws java.io.IOException      If there are errors communicating with the netconf server.
      * @throws org.xml.sax.SAXException If there are errors parsing the XML reply.
      */
     public String runCliCommand(String command) throws IOException, SAXException {
diff --git a/src/main/java/net/juniper/netconf/NetconfConstants.java b/src/main/java/net/juniper/netconf/NetconfConstants.java
new file mode 100644
index 0000000..607c073
--- /dev/null
+++ b/src/main/java/net/juniper/netconf/NetconfConstants.java
@@ -0,0 +1,31 @@
+package net.juniper.netconf;
+
+/**
+ * @author Jonas Glass
+ */
+public class NetconfConstants {
+
+    /**
+     * Device prompt for the framing protocol.
+     * https://tools.ietf.org/html/rfc6242#section-4.1
+     */
+    public static final String DEVICE_PROMPT = "]]>]]>";
+
+    /**
+     * XML Schema prefix.
+     */
+    public static final String XML_VERSION = "";
+
+    /**
+     * XML Namespace for NETCONF Base 1.0
+     * https://tools.ietf.org/html/rfc6241#section-8.1
+     */
+    public static final String URN_XML_NS_NETCONF_BASE_1_0 = "urn:ietf:params:xml:ns:netconf:base:1.0";
+
+    /**
+     * URN for NETCONF Base 1.0
+     * https://tools.ietf.org/html/rfc6241#section-8.1
+     */
+    public static final String URN_IETF_PARAMS_NETCONF_BASE_1_0 = "urn:ietf:params:netconf:base:1.0";
+
+}
diff --git a/src/main/java/net/juniper/netconf/NetconfSession.java b/src/main/java/net/juniper/netconf/NetconfSession.java
index 621fde3..9fce237 100644
--- a/src/main/java/net/juniper/netconf/NetconfSession.java
+++ b/src/main/java/net/juniper/netconf/NetconfSession.java
@@ -8,24 +8,19 @@
 
 package net.juniper.netconf;
 
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Charsets;
+import com.jcraft.jsch.Channel;
 import com.jcraft.jsch.JSchException;
 import lombok.NonNull;
 import lombok.extern.slf4j.Slf4j;
-import com.jcraft.jsch.Channel;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
-import com.google.common.annotations.VisibleForTesting;
 
 import javax.xml.parsers.DocumentBuilder;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.StringReader;
+import java.io.*;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
 import java.nio.file.Paths;
@@ -33,7 +28,7 @@
 import java.util.List;
 
 /**
- * A NetconfSession object is used to call the Netconf driver 
+ * A NetconfSession object is used to call the Netconf driver
  * methods.
  * This is derived by creating a Device first,
  * and calling createNetconfSession().
@@ -41,16 +36,16 @@
  * Typically, one
  * 
    *
  1. creates a Device object.
  2. - *
  3. calls the createNetconfSession() method to get a NetconfSession + *
  4. calls the createNetconfSession() method to get a NetconfSession * object.
  5. *
  6. perform operations on the NetconfSession object.
  7. - *
  8. finally, one must close the NetconfSession and release resources with + *
  9. finally, one must close the NetconfSession and release resources with * the {@link #close() close()} method.
  10. *
*/ @Slf4j public class NetconfSession { - + private final Channel netconfChannel; private String serverCapability; @@ -59,16 +54,15 @@ public class NetconfSession { private String lastRpcReply; private final DocumentBuilder builder; + private int messageId = 0; private static final String CANDIDATE_CONFIG = "candidate"; private static final String EMPTY_CONFIGURATION_TAG = ""; private static final String RUNNING_CONFIG = "running"; - private static final String DEVICE_PROMPT = "]]>]]>"; - private static final String NETCONF_SYNTAX_ERROR_MSG_FROM_DEVICE = "netconf error: syntax error"; - + NetconfSession(Channel netconfChannel, int timeout, String hello, - DocumentBuilder builder) throws IOException{ + DocumentBuilder builder) throws IOException { stdInStreamFromDevice = netconfChannel.getInputStream(); stdOutStreamToDevice = netconfChannel.getOutputStream(); @@ -83,18 +77,17 @@ public class NetconfSession { sendHello(hello); } - + private XML convertToXML(String xml) throws SAXException, IOException { if (xml.contains(NETCONF_SYNTAX_ERROR_MSG_FROM_DEVICE)) { throw new NetconfException(String.format("Netconf server detected an error: %s", xml)); } Document doc = builder.parse(new InputSource(new StringReader(xml))); - Element root = doc.getDocumentElement(); + Element root = doc.getDocumentElement(); return new XML(root); } - + private void sendHello(String hello) throws IOException { - log.debug("Sending Netconf Capabilities Hello message. {}", hello); String reply = getRpcReply(hello); serverCapability = reply; lastRpcReply = reply; @@ -102,48 +95,58 @@ private void sendHello(String hello) throws IOException { @VisibleForTesting String getRpcReply(String rpc) throws IOException { - stdOutStreamToDevice.write(rpc.getBytes(Charset.defaultCharset())); - stdOutStreamToDevice.flush(); - StringBuilder rpcReply = new StringBuilder(); - BufferedReader bufferReader = new BufferedReader( - new InputStreamReader(stdInStreamFromDevice, Charset.defaultCharset())); - while (true) { + // write the rpc to the device + BufferedReader bufferedReader = getRpcReplyRunning(rpc); - String line = bufferReader.readLine(); - if (line == null || line.equals(DEVICE_PROMPT)) { - break; + // reading the rpc reply from the device + StringBuilder rpcReply = new StringBuilder(); + while (!rpcReply.toString().contains(NetconfConstants.DEVICE_PROMPT)) { + int line = bufferedReader.read(); + if (line == -1) { + throw new NetconfException("Input Stream has been closed during reading."); } - rpcReply.append(line).append("\n"); + rpcReply.append((char) line); } - return rpcReply.toString(); + + // fixing the rpc reply by removing device prompt + String reply = rpcReply.toString().replace(NetconfConstants.DEVICE_PROMPT, ""); + log.debug("Received Netconf RPC-Reply\n{}", reply); + return reply; } - private BufferedReader getRpcReplyRunning(String rpc) throws IOException { - stdOutStreamToDevice.write(rpc.getBytes(Charset.defaultCharset())); + // RFC conformance for XML type, namespaces and message ids for RPCs + messageId++; + rpc = rpc.replace("", "").trim(); + if (!rpc.contains(NetconfConstants.XML_VERSION)) { + rpc = NetconfConstants.XML_VERSION + rpc; + } + + // writing the rpc to the device + log.debug("Sending Netconf RPC\n{}", rpc); + stdOutStreamToDevice.write(rpc.getBytes(Charsets.UTF_8)); stdOutStreamToDevice.flush(); return new BufferedReader( - new InputStreamReader(stdInStreamFromDevice, Charset.defaultCharset())); + new InputStreamReader(stdInStreamFromDevice, Charsets.UTF_8)); } /** * Loads the candidate configuration, Configuration should be in XML format. - * @param configuration - * Configuration,in XML format, to be loaded. For example, - * "<configuration><system><services><ftp/>< - * services/></system></configuration/>" - * will load 'ftp' under the 'systems services' hierarchy. - * @param loadType - * You can choose "merge" or "replace" as the loadType. + * + * @param configuration Configuration,in XML format, to be loaded. For example, + * "<configuration><system><services><ftp/>< + * services/></system></configuration/>" + * will load 'ftp' under the 'systems services' hierarchy. + * @param loadType You can choose "merge" or "replace" as the loadType. * @throws org.xml.sax.SAXException If there are issues parsing the config file. - * @throws java.io.IOException If there are issues reading the config file. + * @throws java.io.IOException If there are issues reading the config file. */ public void loadXMLConfiguration(String configuration, String loadType) throws IOException, SAXException { validateLoadType(loadType); configuration = configuration.trim(); if (!configuration.startsWith(""; } String rpc = "" + @@ -159,7 +162,7 @@ public void loadXMLConfiguration(String configuration, String loadType) throws I "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); if (hasError() || !isOK()) throw new LoadException("Load operation returned error."); @@ -168,18 +171,17 @@ public void loadXMLConfiguration(String configuration, String loadType) throws I /** * Loads the candidate configuration, Configuration should be in text/tree * format. - * @param configuration - * Configuration,in text/tree format, to be loaded. For example, - * " system { - * services { - * ftp; - * } - * }" - * will load 'ftp' under the 'systems services' hierarchy. - * @param loadType - * You can choose "merge" or "replace" as the loadType. + * + * @param configuration Configuration,in text/tree format, to be loaded. For example, + * " system { + * services { + * ftp; + * } + * }" + * will load 'ftp' under the 'systems services' hierarchy. + * @param loadType You can choose "merge" or "replace" as the loadType. * @throws org.xml.sax.SAXException If there are issues parsing the config file. - * @throws java.io.IOException If there are issues reading the config file. + * @throws java.io.IOException If there are issues reading the config file. */ public void loadTextConfiguration(String configuration, String loadType) throws IOException, SAXException { String rpc = "" + @@ -197,12 +199,12 @@ public void loadTextConfiguration(String configuration, String loadType) throws "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); if (hasError() || !isOK()) throw new LoadException("Load operation returned error"); } - + private String getConfig(String configTree) throws IOException { String rpc = "" + @@ -215,7 +217,7 @@ private String getConfig(String configTree) throws IOException { "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); return lastRpcReply; } @@ -233,33 +235,34 @@ private String getConfig(String target, String configTree) "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); return lastRpcReply; } /** * Get capability of the Netconf server. + * * @return server capability */ public String getServerCapability() { return serverCapability; } - + /** - * Send an RPC(as String object) over the default Netconf session and get + * Send an RPC(as String object) over the default Netconf session and get * the response as an XML object. *

- * @param rpcContent - * RPC content to be sent. For example, to send an rpc - * <rpc><get-chassis-inventory/></rpc>, the - * String to be passed can be - * "<get-chassis-inventory/>" OR - * "get-chassis-inventory" OR - * "<rpc><get-chassis-inventory/></rpc>" + * + * @param rpcContent RPC content to be sent. For example, to send an rpc + * <rpc><get-chassis-inventory/></rpc>, the + * String to be passed can be + * "<get-chassis-inventory/>" OR + * "get-chassis-inventory" OR + * "<rpc><get-chassis-inventory/></rpc>" * @return RPC reply sent by Netconf server * @throws org.xml.sax.SAXException If the XML Reply cannot be parsed. - * @throws java.io.IOException If there are issues communicating with the netconf server. + * @throws java.io.IOException If there are issues communicating with the netconf server. */ public XML executeRPC(String rpcContent) throws SAXException, IOException { String rpcReply = getRpcReply(fixupRpc(rpcContent)); @@ -271,12 +274,12 @@ public XML executeRPC(String rpcContent) throws SAXException, IOException { * Send an RPC(as XML object) over the Netconf session and get the response * as an XML object. *

- * @param rpc - * RPC to be sent. Use the XMLBuilder to create RPC as an - * XML object. + * + * @param rpc RPC to be sent. Use the XMLBuilder to create RPC as an + * XML object. * @return RPC reply sent by Netconf server * @throws org.xml.sax.SAXException If the XML Reply cannot be parsed. - * @throws java.io.IOException If there are issues communicating with the netconf server. + * @throws java.io.IOException If there are issues communicating with the netconf server. */ public XML executeRPC(XML rpc) throws SAXException, IOException { return executeRPC(rpc.toString()); @@ -286,11 +289,11 @@ public XML executeRPC(XML rpc) throws SAXException, IOException { * Send an RPC(as Document object) over the Netconf session and get the * response as an XML object. *

- * @param rpcDoc - * RPC content to be sent, as a org.w3c.dom.Document object. + * + * @param rpcDoc RPC content to be sent, as a org.w3c.dom.Document object. * @return RPC reply sent by Netconf server * @throws org.xml.sax.SAXException If the XML Reply cannot be parsed. - * @throws java.io.IOException If there are issues communicating with the netconf server. + * @throws java.io.IOException If there are issues communicating with the netconf server. */ public XML executeRPC(Document rpcDoc) throws SAXException, IOException { Element root = rpcDoc.getDocumentElement(); @@ -301,6 +304,7 @@ public XML executeRPC(Document rpcDoc) throws SAXException, IOException { /** * Given an RPC command, wrap it in RPC tags. + * https://tools.ietf.org/html/rfc6241#section-4.1 * * @param rpcContent an RPC command that may or may not be wrapped in < or > * @return a string of the RPC command wrapped in <rpc>< ></rpc> @@ -318,65 +322,66 @@ static String fixupRpc(@NonNull String rpcContent) throws IllegalArgumentExcepti else rpcContent = "" + "<" + rpcContent + "/>" + ""; } - return rpcContent + DEVICE_PROMPT; + return rpcContent + NetconfConstants.DEVICE_PROMPT; } /** - * Send an RPC(as String object) over the default Netconf session and get + * Send an RPC(as String object) over the default Netconf session and get * the response as a BufferedReader. *

- * @param rpcContent - * RPC content to be sent. For example, to send an rpc - * <rpc><get-chassis-inventory/></rpc>, the - * String to be passed can be - * "<get-chassis-inventory/>" OR - * "get-chassis-inventory" OR - * "<rpc><get-chassis-inventory/></rpc>" - * @return RPC reply sent by Netconf server as a BufferedReader. This is - * useful if we want continuous stream of output, rather than wait - * for whole output till command execution completes. + * + * @param rpcContent RPC content to be sent. For example, to send an rpc + * <rpc><get-chassis-inventory/></rpc>, the + * String to be passed can be + * "<get-chassis-inventory/>" OR + * "get-chassis-inventory" OR + * "<rpc><get-chassis-inventory/></rpc>" + * @return RPC reply sent by Netconf server as a BufferedReader. This is + * useful if we want continuous stream of output, rather than wait + * for whole output till command execution completes. * @throws java.io.IOException If there are issues communicating with the netconf server. */ public BufferedReader executeRPCRunning(String rpcContent) throws IOException { return getRpcReplyRunning(fixupRpc(rpcContent)); } - + /** - * Send an RPC(as XML object) over the Netconf session and get the response + * Send an RPC(as XML object) over the Netconf session and get the response * as a BufferedReader. *

- * @param rpc - * RPC to be sent. Use the XMLBuilder to create RPC as an - * XML object. - * @return RPC reply sent by Netconf server as a BufferedReader. This is - * useful if we want continuous stream of output, rather than wait - * for whole output till command execution completes. + * + * @param rpc RPC to be sent. Use the XMLBuilder to create RPC as an + * XML object. + * @return RPC reply sent by Netconf server as a BufferedReader. This is + * useful if we want continuous stream of output, rather than wait + * for whole output till command execution completes. * @throws java.io.IOException If there are issues communicating with the netconf server. - * */ + */ public BufferedReader executeRPCRunning(XML rpc) throws IOException { return executeRPCRunning(rpc.toString()); } - + /** - * Send an RPC(as Document object) over the Netconf session and get the + * Send an RPC(as Document object) over the Netconf session and get the * response as a BufferedReader. *

- * @param rpcDoc - * RPC content to be sent, as a org.w3c.dom.Document object. - * @return RPC reply sent by Netconf server as a BufferedReader. This is - * useful if we want continuous stream of output, rather than wait - * for whole output till command execution completes. + * + * @param rpcDoc RPC content to be sent, as a org.w3c.dom.Document object. + * @return RPC reply sent by Netconf server as a BufferedReader. This is + * useful if we want continuous stream of output, rather than wait + * for whole output till command execution completes. * @throws java.io.IOException If there are issues communicating with the netconf server. - * */ + */ public BufferedReader executeRPCRunning(Document rpcDoc) throws IOException { Element root = rpcDoc.getDocumentElement(); XML xml = new XML(root); return executeRPCRunning(xml); } - + /** * Get the session ID of the Netconf session. + * * @return Session ID as a string. */ public String getSessionId() { @@ -388,26 +393,28 @@ public String getSessionId() { return null; return idSplit[0]; } - + /** - * Close the Netconf session. You should always call this once you don't + * Close the Netconf session. You should always call this once you don't * need the session anymore. + * * @throws IOException if there are errors communicating with the Device */ public void close() throws IOException { String rpc = "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); netconfChannel.disconnect(); } /** * Check if the last RPC reply returned from Netconf server has any error. + * * @return true if any errors are found in last RPC reply. * @throws org.xml.sax.SAXException If the XML Reply cannot be parsed. - * @throws java.io.IOException If there are issues communicating with the netconf server. + * @throws java.io.IOException If there are issues communicating with the netconf server. */ public boolean hasError() throws SAXException, IOException { if (lastRpcReply == null || !(lastRpcReply.contains(""))) @@ -426,9 +433,10 @@ private String parseForErrors(String inputXmlReply) throws IOException, SAXExcep /** * Check if the last RPC reply returned from Netconf server has any warning. + * * @return true if any errors are found in last RPC reply. * @throws org.xml.sax.SAXException If the XML Reply cannot be parsed. - * @throws java.io.IOException If there are issues communicating with the netconf server. + * @throws java.io.IOException If there are issues communicating with the netconf server. */ public boolean hasWarning() throws SAXException, IOException { if (lastRpcReply == null || !(lastRpcReply.contains(""))) @@ -436,21 +444,23 @@ public boolean hasWarning() throws SAXException, IOException { String errorSeverity = parseForErrors(lastRpcReply); return errorSeverity != null && errorSeverity.equals("warning"); } - + /** - * Check if the last RPC reply returned from Netconf server, + * Check if the last RPC reply returned from Netconf server, * contains <ok/> tag. + * * @return true if <ok/> tag is found in last RPC reply. */ public boolean isOK() { return lastRpcReply != null && lastRpcReply.contains(""); } - + /** * Locks the candidate configuration. + * * @return true if successful. * @throws org.xml.sax.SAXException If the XML Reply cannot be parsed. - * @throws java.io.IOException If there are issues communicating with the netconf server. + * @throws java.io.IOException If there are issues communicating with the netconf server. */ public boolean lockConfig() throws IOException, SAXException { String rpc = "" + @@ -460,16 +470,17 @@ public boolean lockConfig() throws IOException, SAXException { "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); return !hasError() && isOK(); } - + /** * Unlocks the candidate configuration. + * * @return true if successful. * @throws org.xml.sax.SAXException If the XML Reply cannot be parsed. - * @throws java.io.IOException If there are issues communicating with the netconf server. + * @throws java.io.IOException If there are issues communicating with the netconf server. */ public boolean unlockConfig() throws IOException, SAXException { String rpc = "" + @@ -479,22 +490,22 @@ public boolean unlockConfig() throws IOException, SAXException { "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); return !hasError() && isOK(); } - + /** - * Loads the candidate configuration, Configuration should be in set + * Loads the candidate configuration, Configuration should be in set * format. * NOTE: This method is applicable only for JUNOS release 11.4 and above. - * @param configuration - * Configuration,in set format, to be loaded. For example, - * "set system services ftp" - * will load 'ftp' under the 'systems services' hierarchy. - * To load multiple set statements, separate them by '\n' character. + * + * @param configuration Configuration,in set format, to be loaded. For example, + * "set system services ftp" + * will load 'ftp' under the 'systems services' hierarchy. + * To load multiple set statements, separate them by '\n' character. * @throws org.xml.sax.SAXException If there are issues parsing the config file. - * @throws java.io.IOException If there are issues reading the config file. + * @throws java.io.IOException If there are issues reading the config file. */ public void loadSetConfiguration(String configuration) throws IOException, SAXException { String rpc = "" + @@ -510,15 +521,14 @@ public void loadSetConfiguration(String configuration) throws IOException, SAXEx } /** - * Loads the candidate configuration from file, + * Loads the candidate configuration from file, * configuration should be in XML format. - * @param configFile - * Path name of file containing configuration,in xml format, - * to be loaded. - * @param loadType - * You can choose "merge" or "replace" as the loadType. + * + * @param configFile Path name of file containing configuration,in xml format, + * to be loaded. + * @param loadType You can choose "merge" or "replace" as the loadType. * @throws org.xml.sax.SAXException If there are issues parsing the config file. - * @throws java.io.IOException If there are issues reading the config file. + * @throws java.io.IOException If there are issues reading the config file. */ public void loadXMLFile(String configFile, String loadType) throws IOException, SAXException { validateLoadType(loadType); @@ -540,10 +550,11 @@ private void validateLoadType(String loadType) throws IllegalArgumentException { /** * Read the config file and return as a string. + * * @param configFile The name of the configuration file * @return a string of the config file. * @throws java.io.IOException If there are issues reading the config file. - * */ + */ private String readConfigFile(String configFile) throws IOException { try { return new String(Files.readAllBytes(Paths.get(configFile)), Charset.defaultCharset().name()); @@ -554,60 +565,58 @@ private String readConfigFile(String configFile) throws IOException { /** - * Loads the candidate configuration from file, + * Loads the candidate configuration from file, * configuration should be in text/tree format. - * @param configFile - * Path name of file containing configuration,in xml format, - * to be loaded. - * @param loadType - * You can choose "merge" or "replace" as the loadType. + * + * @param configFile Path name of file containing configuration,in xml format, + * to be loaded. + * @param loadType You can choose "merge" or "replace" as the loadType. * @throws org.xml.sax.SAXException If there are issues parsing the config file. - * @throws java.io.IOException If there are issues reading the config file. + * @throws java.io.IOException If there are issues reading the config file. */ public void loadTextFile(String configFile, String loadType) throws IOException, SAXException { validateLoadType(loadType); - loadTextConfiguration(readConfigFile(configFile),loadType); + loadTextConfiguration(readConfigFile(configFile), loadType); } - + /** * Loads the candidate configuration from file, * configuration should be in set format. * NOTE: This method is applicable only for JUNOS release 11.4 and above. - * @param configFile - * Path name of file containing configuration,in set format, - * to be loaded. + * + * @param configFile Path name of file containing configuration,in set format, + * to be loaded. * @throws org.xml.sax.SAXException If there are issues parsing the config file. - * @throws java.io.IOException If there are issues reading the config file. + * @throws java.io.IOException If there are issues reading the config file. */ - public void loadSetFile(String configFile) throws + public void loadSetFile(String configFile) throws IOException, SAXException { loadSetConfiguration(readConfigFile(configFile)); } - + /** - * Loads and commits the candidate configuration, Configuration can be in + * Loads and commits the candidate configuration, Configuration can be in * text/xml/set format. - * @param configFile - * Path name of file containing configuration,in text/xml/set format, - * to be loaded. For example, - * " system { - * services { - * ftp; - * } - * }" - * will load 'ftp' under the 'systems services' hierarchy. - * OR - * "<configuration><system><services><ftp/>< - * services/></system></configuration/>" - * will load 'ftp' under the 'systems services' hierarchy. - * OR - * "set system services ftp" - * will load 'ftp' under the 'systems services' hierarchy. - * @param loadType - * You can choose "merge" or "replace" as the loadType. - * NOTE: This parameter's value is redundant in case the file contains - * configuration in 'set' format. - * @throws java.io.IOException if there are errors communication with the netconf server. + * + * @param configFile Path name of file containing configuration,in text/xml/set format, + * to be loaded. For example, + * " system { + * services { + * ftp; + * } + * }" + * will load 'ftp' under the 'systems services' hierarchy. + * OR + * "<configuration><system><services><ftp/>< + * services/></system></configuration/>" + * will load 'ftp' under the 'systems services' hierarchy. + * OR + * "set system services ftp" + * will load 'ftp' under the 'systems services' hierarchy. + * @param loadType You can choose "merge" or "replace" as the loadType. + * NOTE: This parameter's value is redundant in case the file contains + * configuration in 'set' format. + * @throws java.io.IOException if there are errors communication with the netconf server. * @throws org.xml.sax.SAXException if there are errors parsing the XML reply. */ public void commitThisConfiguration(String configFile, String loadType) throws IOException, SAXException { @@ -628,31 +637,32 @@ public void commitThisConfiguration(String configFile, String loadType) throws I } this.unlockConfig(); } - + /** * Commit the candidate configuration. - * @throws java.io.IOException If there are errors communicating with the netconf server. + * + * @throws java.io.IOException If there are errors communicating with the netconf server. * @throws org.xml.sax.SAXException If there are errors parsing the XML reply. */ public void commit() throws IOException, SAXException { String rpc = "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); if (hasError() || !isOK()) throw new CommitException("Commit operation returned error."); } - + /** - * Commit the candidate configuration, temporarily. This is equivalent of + * Commit the candidate configuration, temporarily. This is equivalent of * 'commit confirm' - * @param seconds - * Time in seconds, after which the previous active configuration - * is reverted back to. - * @throws java.io.IOException If there are errors communicating with the netconf server. + * + * @param seconds Time in seconds, after which the previous active configuration + * is reverted back to. + * @throws java.io.IOException If there are errors communicating with the netconf server. * @throws org.xml.sax.SAXException If there are errors parsing the XML reply. - */ + */ public void commitConfirm(long seconds) throws IOException, SAXException { String rpc = "" + "" + @@ -660,7 +670,7 @@ public void commitConfirm(long seconds) throws IOException, SAXException { "" + seconds + "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); if (hasError() || !isOK()) throw new CommitException("Commit operation returned " + @@ -669,9 +679,10 @@ public void commitConfirm(long seconds) throws IOException, SAXException { /** * Commit the candidate configuration and rebuild the config database. + * * @throws net.juniper.netconf.CommitException if there is an error committing the config. - * @throws java.io.IOException If there are errors communicating with the netconf server. - * @throws org.xml.sax.SAXException If there are errors parsing the XML reply. + * @throws java.io.IOException If there are errors communicating with the netconf server. + * @throws org.xml.sax.SAXException If there are errors parsing the XML reply. */ public void commitFull() throws CommitException, IOException, SAXException { String rpc = "" + @@ -679,7 +690,7 @@ public void commitFull() throws CommitException, IOException, SAXException { "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); if (hasError() || !isOK()) throw new CommitException("Commit operation returned error."); @@ -688,58 +699,61 @@ public void commitFull() throws CommitException, IOException, SAXException { /** * Retrieve the candidate configuration, or part of the configuration. - * @param configTree - * configuration hierarchy to be retrieved as the argument. - * For example, to get the whole configuration, argument should be - * <configuration></configuration> + * + * @param configTree configuration hierarchy to be retrieved as the argument. + * For example, to get the whole configuration, argument should be + * <configuration></configuration> * @return configuration data as XML object. - * @throws java.io.IOException If there are errors communicating with the netconf server. + * @throws java.io.IOException If there are errors communicating with the netconf server. * @throws org.xml.sax.SAXException If there are errors parsing the XML reply. */ - public XML getCandidateConfig(String configTree) throws SAXException, + public XML getCandidateConfig(String configTree) throws SAXException, IOException { return convertToXML(getConfig(configTree)); } - + /** * Retrieve the running configuration, or part of the configuration. - * @param configTree - * configuration hierarchy to be retrieved as the argument. - * For example, to get the whole configuration, argument should be - * <configuration></configuration> + * + * @param configTree configuration hierarchy to be retrieved as the argument. + * For example, to get the whole configuration, argument should be + * <configuration></configuration> * @return configuration data as XML object. - * @throws java.io.IOException If there are errors communicating with the netconf server. + * @throws java.io.IOException If there are errors communicating with the netconf server. * @throws org.xml.sax.SAXException If there are errors parsing the XML reply. */ - public XML getRunningConfig(String configTree) throws SAXException, + public XML getRunningConfig(String configTree) throws SAXException, IOException { return convertToXML(getConfig(RUNNING_CONFIG, configTree)); } - + /** * Retrieve the whole candidate configuration. + * * @return configuration data as XML object. - * @throws java.io.IOException If there are errors communicating with the netconf server. + * @throws java.io.IOException If there are errors communicating with the netconf server. * @throws org.xml.sax.SAXException If there are errors parsing the XML reply. */ public XML getCandidateConfig() throws SAXException, IOException { return convertToXML(getConfig(EMPTY_CONFIGURATION_TAG)); } - + /** * Retrieve the whole running configuration. + * * @return configuration data as XML object. - * @throws java.io.IOException If there are errors communicating with the netconf server. + * @throws java.io.IOException If there are errors communicating with the netconf server. * @throws org.xml.sax.SAXException If there are errors parsing the XML reply. */ public XML getRunningConfig() throws SAXException, IOException { return convertToXML(getConfig(RUNNING_CONFIG, EMPTY_CONFIGURATION_TAG)); } - + /** * Validate the candidate configuration. + * * @return true if validation successful. - * @throws java.io.IOException If there are errors communicating with the netconf server. + * @throws java.io.IOException If there are errors communicating with the netconf server. * @throws org.xml.sax.SAXException If there are errors parsing the XML reply. */ public boolean validate() throws IOException, SAXException { @@ -751,41 +765,42 @@ public boolean validate() throws IOException, SAXException { "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); return !hasError() && isOK(); } - + /** * Reboot the device corresponding to the Netconf Session. + * * @return RPC reply sent by Netconf server. * @throws java.io.IOException If there are errors communicating with the netconf server. - * */ + */ public String reboot() throws IOException { String rpc = "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; return getRpcReply(rpc); } - + /** * Run a cli command. * NOTE: The text output is supported for JUNOS 11.4 and later. - * @param command - * the cli command to be executed. + * + * @param command the cli command to be executed. * @return result of the command, as a String. - * @throws java.io.IOException If there are errors communicating with the netconf server. + * @throws java.io.IOException If there are errors communicating with the netconf server. * @throws org.xml.sax.SAXException If there are errors parsing the XML reply. */ - public String runCliCommand(String command) throws IOException, SAXException { + public String runCliCommand(String command) throws IOException, SAXException { String rpc = "" + "" + command + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; String rpcReply = getRpcReply(rpc); lastRpcReply = rpcReply; XML xmlReply = convertToXML(rpcReply); @@ -797,16 +812,16 @@ public String runCliCommand(String command) throws IOException, SAXException { else return rpcReply; } - + /** * Run a cli command. - * @param command - * the cli command to be executed. - * @return result of the command, as a BufferedReader. This is - * useful if we want continuous stream of output, rather than wait - * for whole output till command execution completes. + * + * @param command the cli command to be executed. + * @return result of the command, as a BufferedReader. This is + * useful if we want continuous stream of output, rather than wait + * for whole output till command execution completes. * @throws java.io.IOException If there are errors communicating with the netconf server. - * */ + */ public BufferedReader runCliCommandRunning(String command) throws IOException { @@ -815,49 +830,51 @@ public BufferedReader runCliCommandRunning(String command) throws ""; return executeRPCRunning(rpc); } - + /** - * This method should be called for load operations to happen in 'private' + * This method should be called for load operations to happen in 'private' * mode. - * @param mode - * Mode in which to open the configuration. - * Permissible mode(s): "private" + * + * @param mode Mode in which to open the configuration. + * Permissible mode(s): "private" * @throws java.io.IOException If there are errors communicating with the netconf server. - * */ + */ public void openConfiguration(String mode) throws IOException { - + StringBuilder rpc = new StringBuilder(); rpc.append(""); rpc.append(""); if (mode.startsWith("<")) - rpc.append(mode); + rpc.append(mode); else rpc.append("<").append(mode).append("/>"); rpc.append(""); rpc.append(""); - rpc.append(DEVICE_PROMPT); + rpc.append(NetconfConstants.DEVICE_PROMPT); lastRpcReply = getRpcReply(rpc.toString()); } - + /** * This method should be called to close a private session, in case its * started. + * * @throws java.io.IOException If there are errors communicating with the netconf server. - * */ + */ public void closeConfiguration() throws IOException { String rpc = "" + "" + "" + - DEVICE_PROMPT; + NetconfConstants.DEVICE_PROMPT; lastRpcReply = getRpcReply(rpc); } - + /** * Returns the last RPC reply sent by Netconf server. + * * @return Last RPC reply, as a string. */ public String getLastRPCReply() { return this.lastRpcReply; } - + } From b9093743922a9e0fc787ee1c13cb0d1b0fc578a3 Mon Sep 17 00:00:00 2001 From: Jonas Glass Date: Mon, 15 Jul 2019 11:34:07 +0200 Subject: [PATCH 2/3] - used single imports - fixed broken idents caused by auto-formatting --- src/main/java/net/juniper/netconf/Device.java | 16 +++++--- .../net/juniper/netconf/NetconfSession.java | 38 +++++++++++-------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/main/java/net/juniper/netconf/Device.java b/src/main/java/net/juniper/netconf/Device.java index 06856db..797c856 100644 --- a/src/main/java/net/juniper/netconf/Device.java +++ b/src/main/java/net/juniper/netconf/Device.java @@ -7,7 +7,11 @@ package net.juniper.netconf; -import com.jcraft.jsch.*; +import com.jcraft.jsch.ChannelExec; +import com.jcraft.jsch.ChannelSubsystem; +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; import lombok.Builder; import lombok.Getter; import lombok.NonNull; @@ -773,11 +777,11 @@ public void commitFull() throws CommitException, IOException, SAXException { * * @param configFile Path name of file containing configuration,in text/xml format, * to be loaded. For example, - * " system { - * services { - * ftp; - * } - * }" + * "system { + * services { + * ftp; + * } + * }" * will load 'ftp' under the 'systems services' hierarchy. * OR * "<configuration><system><services><ftp/>< diff --git a/src/main/java/net/juniper/netconf/NetconfSession.java b/src/main/java/net/juniper/netconf/NetconfSession.java index 9fce237..bbc7e08 100644 --- a/src/main/java/net/juniper/netconf/NetconfSession.java +++ b/src/main/java/net/juniper/netconf/NetconfSession.java @@ -20,7 +20,13 @@ import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; -import java.io.*; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.StringReader; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; @@ -173,11 +179,11 @@ public void loadXMLConfiguration(String configuration, String loadType) throws I * format. * * @param configuration Configuration,in text/tree format, to be loaded. For example, - * " system { - * services { - * ftp; - * } - * }" + * "system { + * services { + * ftp; + * } + * }" * will load 'ftp' under the 'systems services' hierarchy. * @param loadType You can choose "merge" or "replace" as the loadType. * @throws org.xml.sax.SAXException If there are issues parsing the config file. @@ -257,9 +263,9 @@ public String getServerCapability() { * @param rpcContent RPC content to be sent. For example, to send an rpc * <rpc><get-chassis-inventory/></rpc>, the * String to be passed can be - * "<get-chassis-inventory/>" OR - * "get-chassis-inventory" OR - * "<rpc><get-chassis-inventory/></rpc>" + * "<get-chassis-inventory/>" OR + * "get-chassis-inventory" OR + * "<rpc><get-chassis-inventory/></rpc>" * @return RPC reply sent by Netconf server * @throws org.xml.sax.SAXException If the XML Reply cannot be parsed. * @throws java.io.IOException If there are issues communicating with the netconf server. @@ -334,9 +340,9 @@ static String fixupRpc(@NonNull String rpcContent) throws IllegalArgumentExcepti * @param rpcContent RPC content to be sent. For example, to send an rpc * <rpc><get-chassis-inventory/></rpc>, the * String to be passed can be - * "<get-chassis-inventory/>" OR - * "get-chassis-inventory" OR - * "<rpc><get-chassis-inventory/></rpc>" + * "<get-chassis-inventory/>" OR + * "get-chassis-inventory" OR + * "<rpc><get-chassis-inventory/></rpc>" * @return RPC reply sent by Netconf server as a BufferedReader. This is * useful if we want continuous stream of output, rather than wait * for whole output till command execution completes. @@ -600,10 +606,10 @@ public void loadSetFile(String configFile) throws * * @param configFile Path name of file containing configuration,in text/xml/set format, * to be loaded. For example, - * " system { - * services { - * ftp; - * } + * "system { + * services { + * ftp; + * } * }" * will load 'ftp' under the 'systems services' hierarchy. * OR From b72f0029311c57fedfe6b24e6aa84c1eb1bc51d0 Mon Sep 17 00:00:00 2001 From: Jonas Glass Date: Mon, 15 Jul 2019 11:35:27 +0200 Subject: [PATCH 3/3] increased version to 2.0.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1129af2..255f71f 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ net.juniper.netconf netconf-java - 2.0.0 + 2.0.1 jar