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;
8   
9   import org.mule.api.MuleMessage;
10  import org.mule.api.endpoint.EndpointURI;
11  import org.mule.api.endpoint.InboundEndpoint;
12  import org.mule.api.lifecycle.CreateException;
13  import org.mule.api.lifecycle.InitialisationException;
14  import org.mule.transport.AbstractMessageRequester;
15  
16  import java.io.File;
17  import java.io.FilenameFilter;
18  import java.io.IOException;
19  import java.text.MessageFormat;
20  
21  import org.apache.commons.net.ftp.FTPClient;
22  import org.apache.commons.net.ftp.FTPFile;
23  import org.apache.commons.net.ftp.FTPListParseEngine;
24  import org.apache.commons.net.ftp.FTPReply;
25  
26  public class FtpMessageRequester extends AbstractMessageRequester
27  {
28      private final static int FTP_LIST_PAGE_SIZE = 25;
29      protected final FtpConnector connector;
30  
31      public FtpMessageRequester(InboundEndpoint endpoint)
32      {
33          super(endpoint);
34          this.connector = (FtpConnector) endpoint.getConnector();
35      }
36  
37      @Override
38      protected void doDispose()
39      {
40          // no op
41      }
42  
43      @Override
44      protected void doConnect() throws Exception
45      {
46          // no op
47      }
48  
49      @Override
50      protected void doDisconnect() throws Exception
51      {
52          try
53          {
54              EndpointURI uri = endpoint.getEndpointURI();
55              FTPClient client = connector.getFtp(uri);
56              connector.destroyFtp(uri, client);
57          }
58          catch (Exception e)
59          {
60              // pool may be closed
61          }
62      }
63  
64      /**
65       * Make a specific request to the underlying transport
66       *
67       * @param timeout The maximum time the operation should block before returning.
68       *         The call should return immediately if there is data available. If
69       *         no data becomes available before the timeout elapses, null will be
70       *         returned.
71       * @return The result of the request wrapped in a MuleMessage object. <code>null</code> will be
72       *          returned if no data was avaialable
73       * @throws Exception if the call to the underlying protocol cuases an exception
74       */
75      @Override
76      protected MuleMessage doRequest(long timeout) throws Exception
77      {
78          FTPClient client = null;
79          try
80          {
81              client = connector.createFtpClient(endpoint);
82              FTPFile fileToProcess = findFileToProcess(client);
83              if (fileToProcess == null)
84              {
85                  return null;
86              }
87  
88              fileToProcess = prepareFile(client, fileToProcess);
89  
90              FtpMuleMessageFactory messageFactory = createMuleMessageFactory(client);
91              MuleMessage message = messageFactory.create(fileToProcess, endpoint.getEncoding());
92              postProcess(client, fileToProcess, message);
93              return message;
94          }
95          finally
96          {
97              connector.releaseFtp(endpoint.getEndpointURI(), client);
98          }
99      }
100     
101     protected void postProcess(FTPClient client, FTPFile file, MuleMessage message) throws Exception
102     {
103         if (!connector.isStreaming())
104         {
105             if (!client.deleteFile(file.getName()))
106             {
107                 throw new IOException(MessageFormat.format("Failed to delete file {0}. Ftp error: {1}", file.getName(), client.getReplyCode()));
108             }
109             if (logger.isDebugEnabled())
110             {
111                 logger.debug("Deleted file " + file.getName());
112             }
113         }
114     }
115 
116     @Override
117     protected void initializeMessageFactory() throws InitialisationException
118     {
119         // Do not initialize the muleMessageFactory instance variable of our super class as 
120         // we're creating MuleMessageFactory instances per request. 
121         // See createMuleMessageFactory(FTPClient) below.
122     }
123 
124     protected FtpMuleMessageFactory createMuleMessageFactory(FTPClient client) throws CreateException
125     {
126         FtpMuleMessageFactory factory = (FtpMuleMessageFactory) createMuleMessageFactory();
127         // We might want to use isStreaming from connector, but for now maintain existing behaviour.
128         factory.setStreaming(false);
129         factory.setFtpClient(client);
130         
131         return factory;
132     }
133 
134     protected FTPFile prepareFile(FTPClient client, FTPFile file) throws IOException
135     {
136         return file;
137     }
138 
139     protected FTPFile findFileToProcess(FTPClient client) throws Exception
140     {
141         FTPListParseEngine engine = client.initiateListParsing();
142         FTPFile[] files = null;
143         while (engine.hasNext())
144         {
145             files = engine.getNext(FTP_LIST_PAGE_SIZE);
146             if (files == null)
147             {
148                 break;
149             }
150             FilenameFilter filenameFilter = getFilenameFilter();
151             for (int i = 0; i < files.length; i++)
152             {
153                 FTPFile file = files[i];
154                 if (file.isFile())
155                 {
156                     if (filenameFilter.accept(null, file.getName()))
157                     {
158                         if (connector.validateFile(file))
159                         {
160                             // only read the first one
161                             return file;
162                         }
163                     }
164                 }
165             }
166         }
167         if (!FTPReply.isPositiveCompletion(client.getReplyCode()))
168         {
169             throw new IOException("Ftp error: " + client.getReplyCode());
170         }
171         
172         return null;
173     }
174 
175     protected FTPFile[] listFiles(FTPClient client) throws IOException
176     {
177         // no longer used, only kept to preserve the class protected API
178         return null;
179     }
180 
181     protected FilenameFilter getFilenameFilter()
182     {
183         if (endpoint.getFilter() instanceof FilenameFilter)
184         {
185             return (FilenameFilter) endpoint.getFilter();
186         }
187         
188         return new AcceptAllFilenameFilter();
189     }
190     
191     private static class AcceptAllFilenameFilter implements FilenameFilter
192     {
193         public AcceptAllFilenameFilter()
194         {
195             super();
196         }
197         
198         public boolean accept(File dir, String name)
199         {
200             return true;
201         }
202     }
203 }