Search code examples
apache-commons-net

Apache commons net FTP clients hangs unpredictably


We tried all the solutions provided in this post (FTP client hangs) but none of them is working. We are using version 3.6 of commons net. Sometimes it hangs while uploading a file, sometimes will checking existence of a directory. Max. file size is around 400 MB. But sometime it hangs even for a small file size < 1KB. Below is the fragment of code:

        public boolean uploadData(String inputFilePath, String destinationFolderName) {
                    if (StringUtil.isNullOrBlank(inputFilePath) || StringUtil.isNullOrBlank(destinationFolderName)) {
                        LOGGER.error("Invalid parameters to uploadData. Aborting...");
                        return false;
                    }
                    boolean result = false;
                    FTPSClient ftpClient = getFTPSClient();
                    if (ftpClient == null) {
                        logFTPConnectionError();
                        return false;
                    }
                     try {
                        loginToFTPServer(ftpClient);
                        result = uploadFileToFTPServer(ftpClient, inputFilePath, destinationFolderName);
                    } catch (Exception e) {
                        logErrorUploadingFile(inputFilePath, e);
                        return false;
                    } finally {
                        try {
                            logoutFromFTPServer(ftpClient);
                        } catch (Exception e) {
                            logErrorUploadingFile(inputFilePath, e);
                            result = false;
                        }
                    }
                    return result;
                }

    private FTPSClient getFTPSClient() {
            FTPSClient ftpClient = null;
            try {
                ftpClient = new FTPSClient();
                LOGGER.debug("Connecting to FTP server...");
                ftpClient.setConnectTimeout(connectTimeOut);
                ftpClient.connect(server);
                int reply = ftpClient.getReplyCode();
                if (!FTPReply.isPositiveCompletion(reply)) {
                    ftpClient.disconnect();
                    LOGGER.error("Could not connect to FTP server. Aborting.");
                    return null;
                }
            } catch (Exception e) {
                LOGGER.error("Could not connect to FTP server.", e);
                return null;
            }
            return ftpClient;
        }

    private void loginToFTPServer(FTPSClient ftpClient) throws Exception {
            ftpClient.setDataTimeout(DATA_TIMEOUT);
            ftpClient.login(ftpUserName, ftpPassword);
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            LOGGER.debug("FTP Client Buffer Size Before:" + ftpClient.getBufferSize());
            ftpClient.setBufferSize(BUFFER_SIZE);
            LOGGER.debug("FTP Client Buffer Size After:" + ftpClient.getBufferSize());
            ftpClient.execPBSZ(0);
            ftpClient.execPROT("P");
            ftpClient.setControlKeepAliveTimeout(300);
            LOGGER.debug("Logged into FTP server.");
        }

    private void logoutFromFTPServer(FTPSClient ftpClient) throws Exception {
            LOGGER.debug("Logging out from FTP server.");
            ftpClient.logout();
            ftpClient.disconnect();
            LOGGER.debug("FTP server connection closed.");
        }

private boolean uploadFileToFTPServer(FTPSClient ftpClient, String inputFilePath, String destinationFolderName) {
        boolean result = false;
        String remoteLocationFile;
        File ftpFile = new File(inputFilePath);
        try (InputStream inputStream = new FileInputStream(ftpFile)) {
            String fileName = ftpFile.getName();
            remoteLocationFile = (destinationFolderName == null || destinationFolderName.isEmpty())
                    ? ftpFile.getName()
                    : destinationFolderName + File.separator + fileName;
            LOGGER.info("Storing file " + ftpFile.getName() + " of size "
                    + ftpFile.length() + " in folder " + remoteLocationFile);
            result = ftpClient.storeFile(remoteLocationFile, inputStream);
            if(result) {
                LOGGER.info("Successfully stored file " + ftpFile.getName() + " in folder " + remoteLocationFile);
            } else {
                LOGGER.error("Unable to store file " + ftpFile.getName() + " in folder " + remoteLocationFile);
            }
            return result;
        } catch (Exception e) {
            logErrorUploadingFile(inputFilePath, e);
        }
        return result;
    }

The application is hosted in apache tomcat 8. What could be other causes of this issue and how should we fix them? This is crucial functionality of our application and we may even consider to use alternate API if that is stable. Please suggest.


Solution

  • Adding ftpClient.setSoTimeout(20000); has fixed the issue.