View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.transport.ftp.server;
8   
9   import org.mule.util.IOUtils;
10  
11  import java.io.File;
12  import java.io.IOException;
13  
14  import org.apache.commons.logging.Log;
15  import org.apache.commons.logging.LogFactory;
16  import org.apache.commons.net.ftp.FTPClient;
17  import org.apache.commons.net.ftp.FTPFile;
18  
19  /**
20   * Ftp client wrapper for working with an FTP server.
21   */
22  public class FTPTestClient
23  {
24      protected final transient Log logger = LogFactory.getLog(this.getClass());
25      FTPClient ftpClient = null;   
26      String server = null;
27      int port;
28      String user = null;
29      String password = null;
30      public static final int TIMEOUT = 5000; // just to make sure we don't hang the test on invalid connection attempts
31          
32      public FTPTestClient(String server, int port, String user, String password)
33      {
34          super();
35          this.server = server;
36          this.port = port;
37          this.user = user;
38          this.password = password;
39          ftpClient = new FTPClient();
40      }
41  
42      public boolean testConnection() throws IOException
43      {
44          connect();
45          return verifyStatusCode(ftpClient.noop());        
46      }
47      
48      /**
49       * Get a list of file names in a given directory for admin
50       * @return List of files/directories
51       * @throws IOException
52       */
53      public String[] getFileList(String path) throws IOException
54      {
55          connect();
56          return ftpClient.listNames(path);
57      }
58  
59      /**
60       * Create a directory
61       * @param dir
62       * @return true if successful, false if not
63       * @throws IOException
64       */
65      public boolean makeDir(String dir) throws IOException
66      {
67          connect();
68          return verifyStatusCode(ftpClient.mkd(dir));
69      }
70      
71      /**
72       * Delete a directory
73       * @param dir The directory to delete
74       * @return true if successful, false if not
75       * @throws IOException
76       */
77      public boolean deleteDir(String dir) throws IOException
78      {
79          connect();
80          return verifyStatusCode(ftpClient.rmd(dir));
81      }
82      
83      /**
84       * Check that the status code is successful (between 200 and 299)
85       * @param status The status code to check
86       * @return true if status is successful, false if not
87       */ 
88      private boolean verifyStatusCode(int status)
89      {
90          if(status >= 200 && status < 300)
91          {
92              return true;
93          }
94          return false;
95      }
96  
97      /**
98       * Upload a file to the ftp server
99       * @param fileName The file to upload
100      * @return true if successful, false if not
101      * @throws IOException
102      */
103     public boolean putFile(String fileName, String targetDir) throws IOException
104     {
105         connect();       
106         File file = new File(IOUtils.getResourceAsUrl(fileName, getClass()).getFile()); //hacky way to get the file shortname        
107         return ftpClient.storeFile(targetDir + "/" + file.getName(), IOUtils.getResourceAsStream(fileName, getClass()));
108     }
109     
110     /**
111      * Check if a directory exists by trying to go to it
112      * @param path The directory to try
113      * @return True if the directory exists, false if not
114      * @throws IOException
115      */
116     public boolean dirExists(String path) throws IOException
117     {
118         connect();
119         String cwd = ftpClient.printWorkingDirectory(); //store the current working dir so we can go back to it
120         boolean dirExists = ftpClient.changeWorkingDirectory(path);
121         ftpClient.changeWorkingDirectory(cwd); // go back to the cwd
122         return dirExists;
123     }
124     
125     /**
126      * Delete all files and subdirectories. Note: extra slashes are ignored by the
127      * ftp server, so I didn't bother to filter them out
128      * 
129      */
130     public void recursiveDelete(String path) throws IOException
131     {
132         connect();
133         String cwd = ftpClient.printWorkingDirectory(); //store the current working dir so we can go back to it
134         System.out.println("CWD: " + cwd);
135         ftpClient.changeWorkingDirectory(path);
136         System.out.println("Changed CWD: " + path);
137         
138         FTPFile[] fileObjs = ftpClient.listFiles();
139         for(int i = 0; i < fileObjs.length; i++)
140         {
141             if(fileObjs[i].isFile()) //delete the file
142             {
143                 ftpClient.deleteFile(fileObjs[i].getName());
144             }
145             else if(fileObjs[i].isDirectory() && (getFileList(ftpClient.printWorkingDirectory() + "/" + fileObjs[i].getName()).length > 0))
146             {
147                 recursiveDelete(ftpClient.printWorkingDirectory() + "/" + fileObjs[i].getName());
148                 deleteDir(ftpClient.printWorkingDirectory() + "/" + fileObjs[i].getName()); //safe to delete dir now that it's empty
149             }
150             else if(fileObjs[i].isDirectory()) //delete the empty directory
151             {
152                 deleteDir(ftpClient.printWorkingDirectory() + "/" + fileObjs[i].getName());                
153             }
154             // ignore file if not a file or a dir
155         }
156         ftpClient.changeWorkingDirectory(cwd); // go back to the cwd
157     }
158     
159     /**
160      * Initiate a connection to the ftp server
161      * @throws IOException
162      */
163     protected void connect() throws IOException
164     {
165         if(!ftpClient.isConnected())
166         {
167             ftpClient = new FTPClient();
168             ftpClient.setDefaultTimeout(TIMEOUT);
169             ftpClient.connect(server, port);
170             ftpClient.login(user, password);
171         }
172     }
173 
174     /**
175      * Check if the ftp client is connected
176      * @return true if connected, false if not
177      */
178     public boolean isConnected()
179     {
180         return ftpClient.isConnected();
181     }
182 
183     /**
184      * Disconnect the ftp client
185      * @throws IOException
186      */
187     public void disconnect() throws IOException
188     {
189         ftpClient.disconnect();
190     }
191 
192     /**
193      * Check if a file exists on the ftp server
194      * @param file The name of the file to check
195      * @return true if file exists, false if not
196      * @throws IOException
197      */
198     public boolean fileExists(String file) throws IOException
199     {
200         return (ftpClient.listFiles(file).length > 0);
201     }
202 
203     /**
204      * Delete a single file.
205      * @param name The file to delete
206      * @return true if successful, false if not
207      * @throws IOException
208      */
209     public boolean deleteFile(String name) throws IOException
210     {
211         return ftpClient.deleteFile(name);
212     }
213 
214     /**
215      * Verify that a number of files exist on the ftp server
216      * @param directory The remote directory to check
217      * @param timeout The max time to wait
218      * @return true if the file count matches before the timeout, false if not
219      */
220     public boolean expectFileCount(String directory, int count, long timeout) throws InterruptedException, IOException
221     {
222         long endTime = System.currentTimeMillis() + timeout;
223         int iteration = 1;
224         while(System.currentTimeMillis() < endTime)
225         {
226             logger.debug("checking file list, iteration :" + iteration);
227             if (getFileList(directory).length == count)
228             {
229                 logger.debug("found expected file count : " + count);
230                 return true;
231             }            
232             Thread.sleep(1000);
233             ++iteration;
234         }
235         return false;
236     }
237 }