View Javadoc

1   /*
2    * $Id: FtpMessageReceiver.java 9388 2007-10-26 09:57:08Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.providers.ftp;
12  
13  import org.mule.impl.MuleMessage;
14  import org.mule.providers.AbstractPollingMessageReceiver;
15  import org.mule.providers.file.FileConnector;
16  import org.mule.umo.UMOComponent;
17  import org.mule.umo.UMOMessage;
18  import org.mule.umo.endpoint.UMOEndpoint;
19  import org.mule.umo.lifecycle.InitialisationException;
20  import org.mule.umo.provider.UMOConnector;
21  
22  import java.io.FilenameFilter;
23  import java.io.IOException;
24  import java.text.MessageFormat;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Set;
30  
31  import javax.resource.spi.work.Work;
32  
33  import org.apache.commons.io.output.ByteArrayOutputStream;
34  import org.apache.commons.net.ftp.FTPClient;
35  import org.apache.commons.net.ftp.FTPFile;
36  import org.apache.commons.net.ftp.FTPReply;
37  
38  public class FtpMessageReceiver extends AbstractPollingMessageReceiver
39  {
40      protected final FtpConnector connector;
41      protected final FilenameFilter filenameFilter;
42  
43      // there's nothing like homegrown pseudo-2PC.. :/
44      // shared state management like this should go into the connector and use
45      // something like commons-tx
46      protected final Set scheduledFiles = Collections.synchronizedSet(new HashSet());
47      protected final Set currentFiles = Collections.synchronizedSet(new HashSet());
48  
49      public FtpMessageReceiver(UMOConnector connector,
50                                UMOComponent component,
51                                UMOEndpoint endpoint,
52                                long frequency) throws InitialisationException
53      {
54          super(connector, component, endpoint);
55          this.setFrequency(frequency);
56  
57          this.connector = (FtpConnector)connector;
58  
59          if (endpoint.getFilter() instanceof FilenameFilter)
60          {
61              this.filenameFilter = (FilenameFilter)endpoint.getFilter();
62          }
63          else
64          {
65              this.filenameFilter = null;
66          }
67      }
68  
69      public void poll() throws Exception
70      {
71          FTPFile[] files = listFiles();
72  
73          synchronized (scheduledFiles)
74          {
75              for (int i = 0; i < files.length; i++)
76              {
77                  final FTPFile file = files[i];
78                  final String fileName = file.getName();
79  
80                  if (!scheduledFiles.contains(fileName) && !currentFiles.contains(fileName))
81                  {
82                      scheduledFiles.add(fileName);
83                      getWorkManager().scheduleWork(new FtpWork(fileName, file));
84                  }
85              }
86          }
87      }
88  
89      protected FTPFile[] listFiles() throws Exception
90      {
91          FTPClient client = null;
92          try
93          {
94              client = connector.createFtpClient(endpoint);
95              FTPFile[] files = client.listFiles();
96  
97              if (!FTPReply.isPositiveCompletion(client.getReplyCode()))
98              {
99                  throw new IOException("Failed to list files. Ftp error: " + client.getReplyCode());
100             }
101 
102             if (files == null || files.length == 0)
103             {
104                 return files;
105             }
106 
107             List v = new ArrayList();
108 
109             for (int i = 0; i < files.length; i++)
110             {
111                 if (files[i].isFile())
112                 {
113                     if (filenameFilter == null || filenameFilter.accept(null, files[i].getName()))
114                     {
115                         v.add(files[i]);
116                     }
117                 }
118             }
119 
120             return (FTPFile[]) v.toArray(new FTPFile[v.size()]);
121         }
122         finally
123         {
124             if (client != null)
125             {
126                 connector.releaseFtp(endpoint.getEndpointURI(), client);
127             }
128         }
129     }
130 
131     protected void processFile(FTPFile file) throws Exception
132     {
133         logger.debug("entering processFile()");
134         
135         FTPClient client = null;
136         try
137         {
138             client = connector.createFtpClient(endpoint);
139             
140             final String fileName = file.getName();
141             
142             UMOMessage message;
143             if (endpoint.isStreaming())
144             {
145                 message = new MuleMessage(
146                         connector.getStreamMessageAdapter(client.retrieveFileStream(fileName), null));
147             }
148             else
149             {
150                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
151                 if (!client.retrieveFile(fileName, baos))
152                 {
153                     throw new IOException(MessageFormat.format("Failed to retrieve file {0}. Ftp error: {1}",
154                                                                new Object[] {fileName, new Integer(client.getReplyCode())}));
155                 }
156                 message = new MuleMessage(connector.getMessageAdapter(baos.toByteArray()));
157             }
158 
159             message.setProperty(FileConnector.PROPERTY_ORIGINAL_FILENAME, fileName);
160             message.setProperty(FileConnector.PROPERTY_FILE_SIZE, new Long(file.getSize()));
161             routeMessage(message);
162 
163             if (!client.deleteFile(fileName))
164             {
165                 throw new IOException(MessageFormat.format("Failed to delete file {0}. Ftp error: {1}",
166                                                            new Object[] {fileName, new Integer(client.getReplyCode())}));
167             }
168         }
169         finally
170         {
171             logger.debug("leaving processFile()");
172             if (client != null)
173             {
174                 connector.releaseFtp(endpoint.getEndpointURI(), client);
175             }
176         }
177     }
178 
179     protected void doConnect() throws Exception
180     {
181         // why?!
182         //connector.releaseFtp(getEndpointURI());
183     }
184 
185     protected void doDisconnect() throws Exception
186     {
187         // no op
188     }
189 
190     protected void doDispose()
191     {
192         // template method
193     }
194 
195     private final class FtpWork implements Work
196     {
197         private final String name;
198         private final FTPFile file;
199 
200         private FtpWork(String name, FTPFile file)
201         {
202             this.name = name;
203             this.file = file;
204         }
205 
206         public void run()
207         {
208             try
209             {
210                 currentFiles.add(name);
211                 processFile(file);
212             }
213             catch (Exception e)
214             {
215                 connector.handleException(e);
216             }
217             finally
218             {
219                 currentFiles.remove(name);
220                 scheduledFiles.remove(name);
221             }
222         }
223 
224         public void release()
225         {
226             // no op
227         }
228     }
229 
230 }