I recently had a requirement to write some ssjs utilities to handle basic SFTP functions. I’m not FTP expert so it was new to me that FTPS has functions built into the Apache Commons FTP library but SFTP does not. (For more on FTP vs FTP/S vs SFTP, check out this article.)
To create the desired library I found Java Secure Channel by JCraft.com that would allow me to use java libraries in my ssjs to create the desired utility functions. Using java classes in ssjs is a useful way to extend the functionality of ssjs if your requirements are such that you can’t have your business logic in java.
- Import the file into your NSF
- Download the .jar file for JSch.
- Right-click on your file in Package Explorer
- Choose Build P ath –> Configure Build Path
- Choose the “Add JARs” button
- Navigate to your .jar file from step 1 and select OK
- Create a ssjs library for your utility functions. I’ve functions to do the following tasks:
- Connect to a server
- Close the connection
- Put a file on the server
- Delete a file from the server
- Get a list of file names from the server that match a pattern
- Get a file from the server and return the contents as an input stream
The time consuming part here was in the conversion of the java objects to ssjs. Aside from that the code is mostly straightforward.
var utilFTP = {
/*
* Initialize global variables used in all FTP methods
* Code uses Java Secure Channel from JCraft
* Shean McManus | PSC Group | September 2016
*/
ftp:org.apache.commons.net.ftp.FTP,
ftpClient:org.apache.commons.net.ftp.FTPClient,
ftpClientConfig:org.apache.commons.net.ftp.FTPClientConfig,
ssh:com.jcraft.jsch.JSch,
sftpSession:com.jcraft.jsch.Session,
sftpChannel:com.jcraft.jsch.ChannelSftp,
/*
* Initialize FTP session
*/
connect: function(ftpServer:string, ftpUsername:string, ftpPassword:string, ftpKeyChecking:boolean, ftpKeyString:string) {
try {
// initialize JSCH object
this.ssh = new com.jcraft.jsch.JSch();
// create sftp session
this.sftpSession = this.ssh.getSession(ftpUsername,ftpServer);
// set the password
this.sftpSession.setPassword(ftpPassword);
// read boolean to implement key checking or not
if (ftpKeyChecking == true) {
// get host key string from calling function
var his:java.io.InputStream = new java.io.ByteArrayInputStream(ftpKeyString.getBytes());
// add key to known hosts
this.ssh.setKnownHosts(his);
} else {
// disable key checking
var config:java.util.Properties = new java.util.Properties();
config.put("StrictHostKeyChecking","no");
this.sftpSession.setConfig(config);
}
// connect to server
this.sftpSession.connect();
// get sftp channel
this.sftpChannel = this.sftpSession.openChannel("sftp");
// connect
this.sftpChannel.connect();
// return value
return true;
} catch(e) {
// INSERT YOUR ERROR LOGGING CODE HERE
return false;
}
},
/*
* Close FTP session
*/
close: function() {
try {
// disconnect channel
if (this.sftpChannel != null) {
this.sftpChannel.disconnect();
}
// disconnect session
if (this.sftpSession != null) {
this.sftpSession.disconnect();
}
return true;
} catch(e) {
// INSERT YOUR ERROR LOGGING CODE HERE
return false;
}
},
/*
* Delete file on FTP Server
*/
deleteFile: function(ftpFilePath,ftpFileName) {
try {
this.sftpChannel.rm(ftpFilePath + "\\" + ftpFileName);
return true;
} catch(e) {
// INSERT YOUR ERROR LOGGING CODE HERE
return false;
}
},
/*
* Transfer file to FTP server
*/
putFile: function(ftpFromFilePath:string, ftpFileName:string, ftpToFilePath:string) {
try {
// add the file to the ftp server, using double slashes to account for escaping
this.sftpChannel.put(ftpFromFilePath + "\\" + ftpFileName, ftpToFilePath + "\\" + ftpFileName);
return true;
} catch (e) {
// INSERT YOUR ERROR LOGGING CODE HERE return false;
}
},
/*
* Retrieve file from FTP server and return the input stream of the file
*/
getFile: function(ftpFilePath:string,ftpFileName:string) {
try {
// get the file and return it into an input stream
var myInputStream:java.io.FileInputStream = this.sftpChannel.get(ftpFilePath + "\\" + ftpFileName);
return myInputStream
} catch(e) {
// INSERT YOUR ERROR LOGGING CODE HERE return false;
}
},
/*
* Returns an array of file names that match the prefix string
*/
getFileNames: function(ftpMode:string,ftpFilePath:string,ftpFilePrefix:string) {
try {
// get a list of files that are in the file path
var ls:java.util.Vector = this.sftpChannel.ls(ftpFilePath);
var matchedFiles = [];
// loop through list
for (entry in ls) {
// set up pattern to match
var thisPattern:java.util.regex.Pattern = java.util.regex.Pattern.compile(ftpFilePrefix + '[0-9]{8}.csv');
// get each entry
var thisEntry:java.lang.String = entry.getFilename();
// check if the entry matches the pattern
var m:java.util.regex.Matcher = thisPattern.matcher(thisEntry);
// initialize the temporary sequence input stream
var sis:java.io.SequenceInputStream = null;
if (m.matches()) {
// if the file matches, push the contents into the matched files array
matchedFiles.push(thisEntry)
}
}
// sort the files by filename - most recent will be last
return matchedFiles.sort();
} catch(e) {
// INSERT YOUR ERROR LOGGING CODE HERE return false;
}
}
}