`
sillycat
  • 浏览: 2552711 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Java and FTP Client

 
阅读更多
Java and FTP Client

The same interface with S3FileOperation. The idea is to load the FTP configuration from properties files, upload and download files from remote FTP. I set up mock FTP server to do integration testing.

pom.xml to add commons-net as my client for FTP, MockFtpServer for mock the testing
<dependency>
      <groupId>commons-net</groupId>
      <artifactId>commons-net</artifactId>
      <version>${commons.net.version}</version>
</dependency>
<commons.net.version>3.6</commons.net.version>
    <dependency>
      <groupId>org.mockftpserver</groupId>
      <artifactId>MockFtpServer</artifactId>
      <version>2.7.1</version>
      <scope>test</scope>
    </dependency>

Here is the same interface for both S3 and FTP
package com.sillycat.transmission;

public interface Transmission
{
  public boolean uploadFile( String bucketName, String key, String fileToUpload );
  public boolean downloadFile( String bucketName, String key, String destFolder );
}

Let’s first talk about the unit test, haha, think in test driving implementation.
This is the mock server for testing, so I put that under the test directory
package com.sillycat.transmission;

import org.mockftpserver.fake.FakeFtpServer;
import org.mockftpserver.fake.UserAccount;
import org.mockftpserver.fake.filesystem.DirectoryEntry;
import org.mockftpserver.fake.filesystem.FileSystem;
import org.mockftpserver.fake.filesystem.UnixFakeFileSystem;

public class FtpServerMock
{

  private FakeFtpServer fakeFtpServer;

  public FtpServerMock( int port, String userName, String password, String homeDir )
  {
    fakeFtpServer = new FakeFtpServer();
    fakeFtpServer.setServerControlPort( port );
    fakeFtpServer.addUserAccount( new UserAccount( userName, password, homeDir ) );
  }

  public void start()
  {
    FileSystem fileSystem = new UnixFakeFileSystem();
    fileSystem.add( new DirectoryEntry( "/home" ) );
    fakeFtpServer.setFileSystem( fileSystem );
    fakeFtpServer.start();
  }

  public void stop()
  {
    fakeFtpServer.stop();
  }
}

This is the Integration Test class
package com.sillycat.transmission;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
* how to run: mvn -Dtest=TransmissionFtpJUnitIntegrationTest test
*
* @author carl
*
*/
public class TransmissionFtpJUnitIntegrationTest
{

  private Transmission transmission;

  private FtpServerMock serverMock;

  @Before
  public void setUp() throws Exception
  {
    transmission = new TransmissionFtpImpl();
    serverMock = new FtpServerMock( 2121, "carl", "supercarl", "/home" );
    serverMock.start();
  }

  @After
  public void tearDown()
  {
    serverMock.stop();
  }

  @Test
  public void ftpFile()
  {
    String localFilePath = this.getClass().getResource( "mock.txt" ).getPath();
    boolean result = transmission.uploadFile( "mockFtp", "mock2.txt", localFilePath );
    Assert.assertTrue( result );
    localFilePath = localFilePath.substring( 0, localFilePath.indexOf( "mock.txt" ) );
    result = transmission.downloadFile( "mockFtp", "mock2.txt", localFilePath );
    Assert.assertTrue( result );
  }

}

For easier to load the properties from files, I create a java POJO, FtpOption.java
package com.sillycat.transmission;

public class FtpOption
{
  private String host;
  private int port;
  private String user;
  private String password;
  private String root;
  ..snip..
}

The properties format will be similar to this file mockFtp.properties
ftp.host=localhost
ftp.user=carl
ftp.password=supercarl
ftp.root=/home/
ftp.port=2121

This is the TransmissionFtpImpl.java class with will load the properties, find the right ftpName
package com.sillycat.transmission;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.util.Properties;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TransmissionFtpImpl implements Transmission
{

  protected final Logger logger = LoggerFactory.getLogger( this.getClass() );

  @Override
  public boolean uploadFile( String ftpName, String path, String fileToUpload )
  {
    boolean result = false;
    FtpOption ftpOption = loadFtpOption( ftpName );
    InputStream input = null;
    FTPClient ftpClient = null;
    try
    {
      ftpClient = loginFtp( ftpOption );
      input = new FileInputStream( fileToUpload );
      ftpClient.storeFile( ftpOption.getRoot() + path, input );
      input.close();
      result = true;
    }
    catch ( IOException e )
    {
      logger.error( "IOException:", e );
    }
    finally
    {
      clearFtpResource( ftpClient );
    }
    return result;
  }

  @Override
  public boolean downloadFile( String ftpName, String path, String destFolder )
  {
    boolean result = false;
    FtpOption ftpOption = loadFtpOption( ftpName );
    FTPClient ftpClient = null;
    try
    {
      ftpClient = loginFtp( ftpOption );
      logger.info( "FTP server " + ftpName + " is " + ftpClient.getSystemType() );
      ftpClient.changeWorkingDirectory( ftpOption.getRoot() );
      FTPFile[] ftpFiles = ftpClient.listFiles();
      if ( ftpFiles != null && ftpFiles.length > 0 )
      {
        for ( FTPFile file : ftpFiles )
        {
          if ( !file.isFile() )
          {
            continue;
          }
          OutputStream output;
          output = new FileOutputStream( destFolder + File.separator + file.getName() );
          //get the file from the remote system
          ftpClient.retrieveFile( file.getName(), output );
          //close output stream
          output.close();
        }
        result = true;
      }
    }
    catch ( IOException e )
    {
      logger.error( "IOException:", e );
    }
    finally
    {
      clearFtpResource( ftpClient );
    }
    return result;
  }

  private FtpOption loadFtpOption( String ftpName )
  {
    FtpOption ftpOption = new FtpOption();
    Properties ftpProperties = new Properties();
    try
    {
      ftpProperties.load( this.getClass().getResourceAsStream( ftpName + ".properties" ) );
    }
    catch ( IOException e )
    {
      logger.error( "IOException:", e );
    }
    String host = ftpProperties.getProperty( "ftp.host" ).trim();
    String user = ftpProperties.getProperty( "ftp.user" ).trim();
    String password = ftpProperties.getProperty( "ftp.password" ).trim();
    String root = ftpProperties.getProperty( "ftp.root" ).trim();
    int port = Integer.valueOf( ftpProperties.getProperty( "ftp.port" ).trim() );

    ftpOption.setHost( host );
    ftpOption.setUser( user );
    ftpOption.setPassword( password );
    ftpOption.setRoot( root );
    ftpOption.setPort( port );
    return ftpOption;
  }

  private FTPClient loginFtp( FtpOption ftpOption ) throws SocketException, IOException
  {
    FTPClient ftpClient = new FTPClient();
    //init connection
    ftpClient.connect( ftpOption.getHost(), ftpOption.getPort() );
    if ( !ftpClient.login( ftpOption.getUser(), ftpOption.getPassword() ) )
    {
      logger.warn( "FTP logging failure with ftpOption:" + ftpOption );
      ftpClient.logout();
    }
    int reply = ftpClient.getReplyCode();
    if ( !FTPReply.isPositiveCompletion( reply ) )
    {
      logger.warn( "FTP did not get positive replay code:" + reply + " ftpOption:" + ftpOption );
      ftpClient.disconnect();
    }
    //enter passive mode
    ftpClient.enterLocalPassiveMode();
    ftpClient.changeWorkingDirectory( ftpOption.getRoot() );
    return ftpClient;
  }

  private void clearFtpResource( FTPClient ftpClient )
  {
    try
    {
      ftpClient.logout();
      ftpClient.disconnect();
    }
    catch ( IOException e )
    {
      logger.error( "IOException:", e );
    }

  }

}

Instead of read the properties files again and again, I may need to add local cache for that as well.
package com.sillycat.cache.guava;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.sillycat.cache.CacheService;

public class CacheServiceGuavaImpl<T> implements CacheService<T>
{

  protected final Logger logger = LoggerFactory.getLogger( this.getClass() );

  Cache<String, T> localCache;

  public CacheServiceGuavaImpl()
  {
    localCache = CacheBuilder.newBuilder().expireAfterWrite( 24, TimeUnit.HOURS ).build();
  }

  @Override
  public T load( String key, Callable<T> callable )
  {
    try
    {
      return localCache.get( key, callable );
    }
    catch ( ExecutionException e )
    {
      logger.error( "cache failure:" + e );
    }
    return null;
  }

}

Unit test for that CacheService
package com.sillycat.cache;

import java.util.concurrent.Callable;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import com.sillycat.cache.guava.CacheServiceGuavaImpl;

/**
* how to run: mvn -Dtest=CacheServiceGuavaJUnitTest test
*
* @author carl
*
*/
public class CacheServiceGuavaJUnitTest
{

  private CacheService<String> cacheService;

  @Before
  public void setUp() throws Exception
  {
    cacheService = new CacheServiceGuavaImpl<String>();
  }

  @Test
  public void cache()
  {
    Assert.assertEquals( cacheService.load( "key1", new Callable<String>()
    {
      @Override
      public String call() throws Exception
      {
        return "value1";
      }
    } ), "value1" );
    for ( int i = 0; i < 10; i++ )
    {
      Assert.assertEquals( cacheService.load( "key1", new Callable<String>()
      {
        @Override
        public String call() throws Exception
        {
          return "value1";
        }
      } ), "value1" );
    }
  }

}



References:
http://www.mysamplecode.com/2012/03/apache-commons-ftpclient-java-example_16.html
https://commons.apache.org/proper/commons-net/examples/ftp/FTPClientExample.java
https://commons.apache.org/proper/commons-net/apidocs/org/apache/commons/net/ftp/FTPClient.html
http://www.mysamplecode.com/2012/03/apache-commons-ftpclient-java-example.html
http://www.baeldung.com/properties-with-spring#xml

Mock ftp Server
http://mockftpserver.sourceforge.net/fakeftpserver-getting-started.html
https://itsiastic.wordpress.com/2012/11/08/how-to-create-a-java-ftp-server-mock/
分享到:
评论

相关推荐

    FTP.rar_FTP server client_ftp_java ftp_java ftp client_java ftp

    ftp server and ftp client

    java代码sftp和ftp上传下载文件

    本文将深入探讨如何使用Java实现SFTP(Secure File Transfer Protocol)和FTP(File Transfer Protocol)进行文件的上传与下载,以满足在Linux服务器上的操作需求。 首先,FTP是一种用于在网络之间传输文件的标准...

    java开源包1

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    android--simple-Server-and-Client.rar_Server_android_android cli

    "android--simple-Server-and-Client.rar" 提供了一个示例,让我们来深入探讨这个主题。 1. **Android 服务器搭建**: - **Socket编程**:在Android中,服务器端通常使用Java的Socket类来创建TCP连接。通过...

    Ftps,SSL的基本用法

    在本文中,我们将详细探讨FTPS和SSL的基本用法,以及如何使用Java的ftp4j库进行FTP操作。 FTPS分为两种模式: Explicit(明示式)和Implicit(隐式)模式。在 Explicit 模式下,客户端先建立一个未加密的FTP连接,...

    java开源包4

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包101

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包6

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包9

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包5

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包8

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包10

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包3

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    Java资源包01

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java jdk实列宝典 光盘源代码

    telnet客户端,访问系统的telnet服务实质上是与telnet服务建立socket连接,默认的telnet服务的端口是23,TelnetClient.java; UDP编程,包括收发udp报文; 聊天室服务器端,Chatserver.java;聊天室客户端,...

    edtftpj.zip

    java中ftp上传下载事例代码 try { // create client log.info("Creating FTP client"); ftp = new FileTransferClient(); // set remote host ftp.setRemoteHost(host); ftp.setUserName(username); ftp.set...

    java开源包2

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包11

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    java开源包7

    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

    SSD8 Networks and Distributed Computing

    SSD8 provides a survey of networking protocols and technology, multimedia networking, client/server design — including thick and thin clients, CORBA and related tools, WWW implementation issues, ...

Global site tag (gtag.js) - Google Analytics