View Javadoc

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