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