/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.functional.util.ftp; import org.mule.runtime.core.util.IOUtils; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Ftp client wrapper for working with an FTP server. */ public class FtpClient { protected final transient Logger logger = LoggerFactory.getLogger(this.getClass()); FTPClient ftpClient = null; String server = null; int port; String user = null; String password = null; public static final int TIMEOUT = 5000; // just to make sure we don't hang the test on invalid connection attempts public FtpClient(String server, int port, String user, String password) { super(); this.server = server; this.port = port; this.user = user; this.password = password; ftpClient = new FTPClient(); } public boolean testConnection() throws IOException { connect(); return verifyStatusCode(ftpClient.noop()); } /** * Get a list of file names in a given directory for admin * * @return List of files/directories * @throws java.io.IOException */ public String[] getFileList(String path) throws IOException { connect(); return ftpClient.listNames(path); } /** * Create a directory * * @param dir * @return true if successful, false if not * @throws java.io.IOException */ public boolean makeDir(String dir) throws IOException { connect(); return verifyStatusCode(ftpClient.mkd(dir)); } /** * Delete a directory * * @param dir The directory to delete * @return true if successful, false if not * @throws java.io.IOException */ public boolean deleteDir(String dir) throws IOException { connect(); return verifyStatusCode(ftpClient.rmd(dir)); } /** * Check that the status code is successful (between 200 and 299) * * @param status The status code to check * @return true if status is successful, false if not */ private boolean verifyStatusCode(int status) { if (status >= 200 && status < 300) { return true; } return false; } /** * Upload a file to the ftp server * * @param fileName The file to upload * @return true if successful, false if not * @throws java.io.IOException */ public boolean putFile(String fileName, String targetDir) throws IOException { connect(); File file = new File(IOUtils.getResourceAsUrl(fileName, getClass()).getFile()); // hacky way to get the file shortname return ftpClient.storeFile(targetDir + "/" + file.getName(), IOUtils.getResourceAsStream(fileName, getClass())); } /** * Upload a file to the ftp server * * @param fileName The file to upload * @return true if successful, false if not * @throws java.io.IOException */ public boolean putFile(String fileName, String targetDir, String fileContent) throws IOException { connect(); return ftpClient.storeFile(targetDir + "/" + fileName, new ByteArrayInputStream(fileContent.getBytes())); } /** * Check if a directory exists by trying to go to it * * @param path The directory to try * @return True if the directory exists, false if not * @throws java.io.IOException */ public boolean dirExists(String path) throws IOException { connect(); String cwd = ftpClient.printWorkingDirectory(); // store the current working dir so we can go back to it boolean dirExists = ftpClient.changeWorkingDirectory(path); ftpClient.changeWorkingDirectory(cwd); // go back to the cwd return dirExists; } /** * Delete all files and subdirectories. Note: extra slashes are ignored by the ftp server, so I didn't bother to filter them out * */ public void recursiveDelete(String path) throws IOException { connect(); String cwd = ftpClient.printWorkingDirectory(); // store the current working dir so we can go back to it System.out.println("CWD: " + cwd); ftpClient.changeWorkingDirectory(path); System.out.println("Changed CWD: " + path); FTPFile[] fileObjs = ftpClient.listFiles(); for (int i = 0; i < fileObjs.length; i++) { if (fileObjs[i].isFile()) // delete the file { ftpClient.deleteFile(fileObjs[i].getName()); } else if (fileObjs[i].isDirectory() && (getFileList(ftpClient.printWorkingDirectory() + "/" + fileObjs[i].getName()).length > 0)) { recursiveDelete(ftpClient.printWorkingDirectory() + "/" + fileObjs[i].getName()); deleteDir(ftpClient.printWorkingDirectory() + "/" + fileObjs[i].getName()); // safe to delete dir now that it's empty } else if (fileObjs[i].isDirectory()) // delete the empty directory { deleteDir(ftpClient.printWorkingDirectory() + "/" + fileObjs[i].getName()); } // ignore file if not a file or a dir } ftpClient.changeWorkingDirectory(cwd); // go back to the cwd } /** * Initiate a connection to the ftp server * * @throws java.io.IOException */ protected void connect() throws IOException { if (!ftpClient.isConnected()) { ftpClient = new FTPClient(); ftpClient.setDefaultTimeout(TIMEOUT); ftpClient.connect(server, port); ftpClient.login(user, password); } } /** * Check if the ftp client is connected * * @return true if connected, false if not */ public boolean isConnected() { return ftpClient.isConnected(); } /** * Disconnect the ftp client * * @throws java.io.IOException */ public void disconnect() throws IOException { ftpClient.disconnect(); } /** * Check if a file exists on the ftp server * * @param file The name of the file to check * @return true if file exists, false if not * @throws java.io.IOException */ public boolean fileExists(String file) throws IOException { return (ftpClient.listFiles(file).length > 0); } /** * Delete a single file. * * @param name The file to delete * @return true if successful, false if not * @throws java.io.IOException */ public boolean deleteFile(String name) throws IOException { return ftpClient.deleteFile(name); } /** * Verify that a number of files exist on the ftp server * * @param directory The remote directory to check * @param timeout The max time to wait * @return true if the file count matches before the timeout, false if not */ public boolean expectFileCount(String directory, int count, long timeout) throws InterruptedException, IOException { long endTime = System.currentTimeMillis() + timeout; int iteration = 1; while (System.currentTimeMillis() < endTime) { logger.debug("checking file list, iteration :" + iteration); if (getFileList(directory).length == count) { logger.debug("found expected file count : " + count); return true; } Thread.sleep(1000); ++iteration; } return false; } }