Using Ftp with Grails
In one of my Grails project I need to drop files over ftp server. Using JSch one can easily transfer files over sftp. Just follow the below steps.
1. Add the below dependency to Grails project “grails-app/conf/BuildConfig.groovy” file
[sourcecode language=”groovy”]
dependencies {
compile ‘com.jcraft:jsch:0.1.49’
}
[/sourcecode]
2. Create a class for adding ftp credentials information. e.g. “FtpCredentail”
[sourcecode language=”groovy”]
class FtpCredential {
String server
String username
String password
String remoteBaseDir
Integer port
}
[/sourcecode]
3. Create a service named “FtpService” and add the following code into it
[sourcecode language=”groovy”]
import com.jcraft.jsch.Channel
import com.jcraft.jsch.ChannelSftp
import com.jcraft.jsch.JSch
import com.jcraft.jsch.Session
class FtpService {
def grailsApplication
static transactional = true
def save(InputStream inputStream, String fileName, FtpCredential ftpCredential) {
connect(ftpCredential) { ChannelSftp sftp ->
sftp.put inputStream, fileName
}
}
def load(String fileName, FtpCredential ftpCredential) {
connect(ftpCredential, { ChannelSftp sftp ->
File outputFile = File.createTempFile(fileName,”)
outputFile?.newOutputStream() << sftp.get(fileName)
outputFile
}, false)
}
def delete(String fileName, FtpCredential ftpCredential) throws Throwable {
connect(ftpCredential) { ChannelSftp sftp ->
sftp.rm fileName
}
}
def makeDir(String directoryName, FtpCredential ftpCredential) {
connect(ftpCredential) { ChannelSftp sftp ->
sftp.mkdir directoryName
}
}
private def connect(FtpCredential ftpCredential, Closure c, boolean disconnectOnFinish = true) {
Session session = null
ChannelSftp sftp = null
try {
JSch jSch = new JSch()
session = jSch.getSession username, ftpCredential?.server, ftpCredential?.port
session.setConfig "StrictHostKeyChecking", "no"
File keyFile = new File("${grailsApplication.config.pathToKeyFile}")
if (ftpCredential?.password) {
session.password = ftpCredential?.password
} else {
jSch.addIdentity(keyFile?.absolutePath)
}
session.connect()
Channel sFtpChannel = session.openChannel "sftp"
sFtpChannel.connect()
sftp = sFtpChannel as ChannelSftp
sftp.cd ftpCredential?.remoteBaseDir
c.call sftp
} catch (Exception ex) {
ex.printStackTrace()
} finally {
if (disconnectOnFinish) {
sftp?.exit()
session?.disconnect()
}
}
}
}
[/sourcecode]
Note: In the above code at line number 44.
[sourcecode language=”groovy”]
File keyFile = new File("${grailsApplication.config.pathToKeyFile}")
[/sourcecode]
The code looks for private key provided by ftp server for password-less log in. One should define the property named “pathToKeyFile” in “grails-app/conf/Config.groovy” with value equals to the path of key file.
Now you are ready to use the newly created FtpService service methods. Such as:
- save(inputStream, fileName, ftpCredential) for saving file over ftp.
- load(fileName, ftpCredential) for getting file from ftp.
- delete(fileName, ftpCredential) for deleting file over ftp.
- makeDir(directoryName, ftpCredential) for creating directory over ftp.
Example
For saving file over ftp one can use FtpService save method as shown below
[sourcecode language=”groovy”]
File file = File.createTempFile("temp","txt")
FtpCredential ftpCredential = new FtpCredential(server: <server>, username: <username>, password: <password>, port: <server_port>, remoteBaseDir: <remote_base_directory>)
InputStream inputStream = new BufferedInputStream(new FileInputStream(file))
ftpService.save(inputStream, "fileNameToBeSavedOverFTPServer", ftpCredential)
[/sourcecode]
Please share your feedback and suggestions.
You’re missing ftpCredential?.username on line 43. Also I think you should make clear that JSch will only work over an SSH channel using SFTP.
Why not disconnect the session after a get? Won’t this cause a thread leak?
Does not work
Here is the github url for the demo project “git@github.com:puneetbehl/ftpDemo.git”
I can’t even connect to ftp! Timeout error, while I successfully connect by cuteFTP or through browser