SFTP integration throwing error Error in Sftp put: java.lang.NegativeArraySizeException: -168

DionysusOP
Tera Contributor

Hi experts,

 

I'm currently working on to set up SFTP (password) based integration to upload a .csv file from ServiceNow table to first Mid server file and lastly to cloud server. While the first scenario is satisfied, I see the file stored under midserver/work, but later my sftp.put() function is not working throwing 'Sftp put: java.lang.NegativeArraySizeException: -168' (this number is changing sometimeds -175, sometimes -158).

 

Just to add If I'm running it from PowerShell, its working perfectly.

 

I'm pasting the code also, if anyone having any upper-hand please add some comments, been stuck into it for a week now.

 

var SNDataRetriever = Class.create();

SNDataRetriever.prototype = {
    initialize: function() {
        ///// Parameters that can be set from this script
        //
        this.debug = false;

        //If you would like to move processed files to a target location, set the next two parameters.
        //Make sure your file name ends up being unique. We will not overwrite a file by the same name
        //in the target directory...
        this.moveProcessedFiles = false;
        this.MIDSERVER_PROCESSED_FILE_PATH = "processed/";
        //
        /////

        this.resLog = "FTP Log: \n";
        this.log("Initializing SNDataRetriever");
        this.MIDSERVER_FILE_PATH = "work" + Packages.java.io.File.separator;

        this.MIDSERVER_FILE_NAME = probe.getParameter('targetFileName');


        this.useProxy = this.getConfigParameter("mid.proxy.use_proxy");
        if (this.useProxy) {
            this.proxyHost = this.getConfigParameter("mid.proxy.host");
            this.proxyPort = this.getConfigParameter("mid.proxy.port");
            this.proxyUser = this.getConfigParameter("mid.proxy.username");
            this.proxyPass = this.getConfigParameter("mid.proxy.password");
        }
        this.user = this.getConfigParameter("mid.instance.username");
        this.password = this.getConfigParameter("mid.instance.password");

        var ftpCredArr = this.decryptCredentials(probe.getParameter('ftpCred'));
        this.ftpUser = ftpCredArr[0];
        this.ftpPass = ftpCredArr[1];

        this.ftpTargetServer = probe.getParameter('ftpTargetServer');
        this.ftpPort = (this.isANumber(probe.getParameter('ftpPort'))) ? (probe.getParameter('ftpPort')) : null;

        this.targetPath = probe.getParameter('targetPath');
        this.targetFileName = probe.getParameter('targetFileName');

        this.reportURL = probe.getParameter('reportURL');

        this.lastRunDateTime = probe.getParameter('lastRunDateTime');
        if (this.lastRunDateTime) {
            this.reportURL += "&sysparm_query=sys_updated_on>" + this.lastRunDateTime;
        }

        this.host = probe.getParameter('host');
        this.transportMethod = probe.getParameter('transportMethod');

        if (this.debug) {
            this.log("\n**********  Debug Info **********\nuser: " + this.user + "\npass: " + this.password + "\ntransportMethod: " + this.transportMethod + "\nreport: " + this.reportURL + "\nhost: " + this.host);
            this.log("\n**********  Proxy Info **********\nproxyNeeded: " + this.proxyNeeded + "\nproxyUser : " + this.proxyUser + "\nproxyPass :" + this.proxyPass);
            this.log("\nproxyHost: " + this.proxyHost + "\nproxyPort:" + this.proxyPort);
            this.log("\n**********  FTP Info ************\nftpUser: " + this.ftpUser + "\nftpPass: " + this.ftpPass + "\nftpPort: " + this.ftpPort);
            this.log("\n**********  End of Debug ********\n\n");
        }
        this.response = this.execute();

    },

    getConfigParameter: function(parm) {
        var m = Packages.com.service_now.mid.MIDServer.get();
        var config = m.getConfig();
        var res = config.getParameter(parm);
        var res2 = config.getProperty(parm);
        if (res) {
            return res;
        } else if (res2) {
            return res2;
        } else {
            config = Packages.com.service_now.mid.services.Config.get();
            return config.getProperty(parm);
        }

    },

    decryptCredentials: function(data) {
        var cred = new String(data);
        var e = new Packages.com.glide.util.Encrypter();

        var jsCred = cred + '';
        var usernamePass = e.decrypt(jsCred);
        var credArr = usernamePass.split(":", 2);
        return credArr;
    },

    saveToFile: function(data, targetPath) {
        var tmpLoc;
        var result = true;
        try {
            if (this.transportMethod == "Mid Server") {
                tmpLoc = targetPath;
            } else {
                tmpLoc = this.MIDSERVER_FILE_PATH + this.MIDSERVER_FILE_NAME;
            }
            var out = new Packages.java.io.PrintWriter(new Packages.java.io.FileWriter(tmpLoc));
            out.print(data);

            this.log("File saved to: " + tmpLoc);
        } catch (e) {
            this.log("Exception caught in SNDataRetriever->saveToFile: " + e.getMessage());
            result = false;
        }
        out.close();
        return result;
    },


    copyToSFTP: function() {
        this.log('Arriving to function copyToSFTP');

        var tmpLoc;
        var connectionType;
        var connected = true;
        var connectionLog = '';
        var sftpSuccess = true;
        if (this.transportMethod == "SFTP (RSA)") {
            try {
                keyfile = this.MIDSERVER_PRIVATE_KEY_PATH + 'id_rsa';
                sshfile = new Packages.com.sshtools.j2ssh.transport.publickey.SshPrivateKeyFile.parse(new Packages.java.io.File(keyfile));
                //this.log('key format'+sshfile.getFormat());
                //this.log('key value'+sshfile.toString());
                pk = new Packages.com.sshtools.j2ssh.authentication.PublicKeyAuthenticationClient();
                //this.log('PUBLIC KEY METHOD'+pk.getMethodName());
                pk.setUsername(this.ftpUser);
                pk.setKey(sshfile.toPrivateKey(null));
            } catch (e) {
                connectionLog += "\nException Reading RSA Key: " + e;
                sftpSuccess = false;
            }
        } else if (this.transportMethod == "SFTP (DSA)") {
            try {
                keyfile = this.MIDSERVER_PRIVATE_KEY_PATH + 'id_dsa';
                sshfile = new Packages.com.sshtools.j2ssh.transport.publickey.SshPrivateKeyFile.parse(new Packages.java.io.File(keyfile));
                //this.log('key format'+sshfile.getFormat());
                //this.log('key value'+sshfile.toString());
                pk = new Packages.com.sshtools.j2ssh.authentication.PublicKeyAuthenticationClient();
                //this.log('PUBLIC KEY METHOD'+pk.getMethodName());
                pk.setUsername(this.ftpUser);
                pk.setKey(sshfile.toPrivateKey(null));
            } catch (e) {
                this.log("Exception Reading DSA Key: " + e);
                sftpSuccess = false;
            }
        } else if (this.transportMethod == "SFTP (Password)") {
            pk = new Packages.com.sshtools.j2ssh.authentication.PasswordAuthenticationClient();
            pk.setUsername(this.ftpUser);
            pk.setPassword(this.ftpPass);
        }
        var ssh = new Packages.com.sshtools.j2ssh.SshClient();
        var ignoreHost = new Packages.com.sshtools.j2ssh.transport.IgnoreHostKeyVerification();
        try {
            //ssh.setSocketTimeout(15000); // 15 second timeout
            ssh.connect(this.ftpTargetServer, this.ftpPort, ignoreHost);
        } catch (e) {
            this.log("Exception Connecting to SFTP Host: " + e);
            sftpSuccess = false;
        }
        authState = new Packages.com.sshtools.j2ssh.authentication.AuthenticationProtocolState();
        if (ssh.authenticate(pk) == authState.COMPLETE) {
            this.log('SSH REMOTE AUTHENTICATE==TRUE');
            var sftp = ssh.openSftpClient();
            if (sftp == null) {
                this.log("SFTP Client initialization failed. Check network/firewall from MID Server host.");
                return false;
            }
            try {
                var pwd = new Packages.java.io.File(".").getAbsolutePath(); // Work directory
                pwd = pwd.slice(0, -1);
                sftp.lcd(pwd + this.MIDSERVER_FILE_PATH);
                this.log(pwd);
                this.log(this.MIDSERVER_FILE_PATH);
                this.log(pwd + this.MIDSERVER_FILE_PATH);
                //sftp.lcd("C:\\agent\\work");
            } catch (e) {
                this.log('Error in Sftp set local directory: ' + e);
                sftpSuccess = false;
            }
            try {
                sftp.cd(this.targetPath);
                this.log(this.targetPath);
            } catch (e) {
                this.log('Error in Sftp set remote directory: ' + e);
                sftpSuccess = false;
            }
            if (sftpSuccess == true) {
                try {
                    this.log(this.MIDSERVER_FILE_NAME);
                    sftp.put(this.MIDSERVER_FILE_NAME);
                    this.log('Successfully copied file: ' + this.MIDSERVER_FILE_NAME + ' to ' + this.ftpTargetServer + ':' + this.targetPath); // File (or directory) to be moved
                } catch (e) {
                    this.log('Error in Sftp put: ' + e);
                    sftpSuccess = false;
                }
            }
        } else {
            connectionLog += "\n**********FAILURE: Connection to SFTP server failed**************\n";
        }
        this.log(connectionLog);
        return sftpSuccess;

    },



    copyToFTP: function() {
        var tmpLoc;
        var connectionType;
        var ftpSuccess = false;

        if (this.transportMethod == "FTPS (Auth SSL)") {
            connectionType = "AUTH_SSL_FTP_CONNECTION";
            if (!this.ftpPort) {
                this.ftpPort = 21;
            }
        } else if (this.transportMethod == "FTPS (Auth TLS)") {
            connectionType = "AUTH_TLS_FTP_CONNECTION";
            if (!this.ftpPort) {
                this.ftpPort = 21;
            }
        } else if (this.transportMethod == "FTPS (Implicit SSL)") {
            connectionType = "IMPLICIT_SSL_FTP_CONNECTION";
            if (!this.ftpPort) {
                this.ftpPort = 990;
            }
        } else if (this.transportMethod == "FTPS (Implicit TLS)") {
            connectionType = "IMPLICIT_TLS_FTP_CONNECTION";
            if (!this.ftpPort) {
                this.ftpPort = 990;
            }
        } else {
            connectionType = "FTP_CONNECTION";
            if (!this.ftpPort) {
                this.ftpPort = 21;
            }
        }
        this.log("ConnectionType: " + connectionType + " and port: " + this.ftpPort);

        var pt = new Packages.java.util.Properties();
        pt.setProperty("connection.host", this.ftpTargetServer);
        pt.setProperty("connection.port", this.ftpPort);
        pt.setProperty("user.login", this.ftpUser);
        pt.setProperty("user.password", this.ftpPass);
        pt.setProperty("connection.type", connectionType);
        pt.setProperty("connection.timeout", "10000");
        pt.setProperty("connection.passive", "true");

        try {
            var connection = Packages.org.ftp4che.FTPConnectionFactory.getInstance(pt);

            var fromFile = new Packages.org.ftp4che.util.ftpfile.FTPFile(this.MIDSERVER_FILE_PATH, this.MIDSERVER_FILE_NAME);
            var toFile = new Packages.org.ftp4che.util.ftpfile.FTPFile(this.targetPath, this.targetFileName);
        } catch (e) {

        }
        var connectionLog = "Connection Log:\n";
        var connected = false;
        try {
            connection.connect();
            this.log("Connecting to " + this.ftpTargetServer + " on port " + this.ftpPort);

            connection.noOperation();
            connected = true;
        } catch (e) {
            connectionLog += "\nException in block B: " + e;
            connected = false;
        }

        if (connected == true) {
            try {
                this.log("Connected...");
                this.log("Uploading " + fromFile + " to " + toFile);
                connection.uploadFile(fromFile, toFile);
                this.log("File successfully uploaded\n\n");
                connection.disconnect();
                ftpSuccess = true;
            } catch (e) {
                connectionLog += "\n**********FAILURE: Connection to FTP server failed**************\n";
                connectionLog += "\nException in block C: \n" + e;
            }
        } else {
            connectionLog += "\n**********FAILURE: Connection to FTP server failed**************\n";
        }

        this.log(connectionLog);
        return ftpSuccess;
    },

    moveProcessedFile: function() {

        file = new Packages.java.io.File(this.MIDSERVER_FILE_PATH + this.MIDSERVER_FILE_NAME); // Work directory
        dir = new Packages.java.io.File(this.MIDSERVER_PROCESSED_FILE_PATH); // Move file to new (processed) directory
        success = file.renameTo(new Packages.java.io.File(dir, file.getName()));

        if (!success) {
            this.log('File was not successfully moved!');
        } else {
            this.log("File was moved from TMP directory to a processed directory");
        }
    },

    getReport: function() {
        this.log("Arriving to getReport function");
        var client = new Packages.org.apache.commons.httpclient.HttpClient();
        ////Set Proxy if (if there is one)
        if (this.useProxy && this.useProxy.toLowerCase() == "true") {
            client.getHostConfiguration().setProxy(this.proxyHost, this.proxyPort);
            if (this.proxyUser) {
                client.getState().setProxyCredentials(new Packages.org.apache.commons.httpclient.auth.AuthScope(this.proxyHost, this.proxyPort), new Packages.org.apache.commons.httpclient.UsernamePasswordCredentials(this.proxyUser, this.proxyPass));
            }
        }

        client.getState().setCredentials(new Packages.org.apache.commons.httpclient.auth.AuthScope(null, 443, null), new Packages.org.apache.commons.httpclient.UsernamePasswordCredentials(this.user, this.password));

        var method = new Packages.org.apache.commons.httpclient.methods.GetMethod((this.reportURL.replace(">", "%3E").replace(" ", "%20")));
        method.setDoAuthentication(true);
        try {
            var statusCode = client.executeMethod(method);

            if (statusCode != Packages.org.apache.commons.httpclient.HttpStatus.SC_OK) {
                this.log("Method failed: " + method.getStatusLine());
            }

            // Read the response body.
            var responseBody = method.getResponseBodyAsString();
            //this.log("responseBody: " +responseBody);
        } catch (e) {
            this.log("Exception caught in SNDataRetriever->getReport: " + e.getMessage());
        }

        method.releaseConnection();
        this.log("Releasing Connection");
        return responseBody;

    },

    getLog: function() {
        return this.resLog;
    },

    log: function(data) {
        ms.log(data);
        this.resLog += "\n" + data;
    },

    isANumber: function(data) {
        data = data + '';
        return ((data - 0) == data && data.length > 0);
    },


    execute: function() {
        this.log("Running SNDataRetriever execute");
        var pushRes = true;
        var reportContents = this.getReport();
        if (reportContents) {
            var saveRes = this.saveToFile(reportContents, this.targetPath + this.targetFileName);
            if (this.transportMethod.indexOf('SFTP') != -1) {
                pushRes = this.copyToSFTP();
            } else if (this.transportMethod.indexOf('FTP') != -1) {
                pushRes = this.copyToFTP();
            }
            //Move tmp file to a processed directory
            if (saveRes && pushRes && this.moveProcessedFiles && this.transportMethod.indexOf('Mid') == -1) {
                this.moveProcessedFile();
            }
        } else {
            this.log("The report was empty?");
        }
    },

    type: 'SNDataRetriever'
};
 
 
Thank You
AD
2 REPLIES 2

Ankur Bawiskar
Tera Patron

@DionysusOP 

this is very much custom code so you will have to debug by adding log statements

Regards,
Ankur
Certified Technical Architect  ||  10x ServiceNow MVP  ||  ServiceNow Community Leader

Tanushree Maiti
Mega Patron

Hi @DionysusOP 

 

1. Ensure in the midserver/work directory is not empty or inaccessible when the put() function is called,

If not , the length attribute might return a value that Java cannot handle during array allocation.

 

2. If you are using custom MID Server Script Includes that call com.sshtools.j2ssh, update them to use the modern ServiceNow (SNC) SSH library. This library is more robust and specifically designed to handle modern SFTP requirements without these legacy Java errors.

 

3. Ensure the MID Server service user has explicit "Read" and "Execute" permissions for the work directory and the specific .csv file. 

 

Please mark this response as Helpful & Accept it as solution if it assisted you with your question.
Regards
Tanushree Maiti
ServiceNow Technical Architect
Linkedin: