1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.ftp;
12
13 import org.mule.api.MuleMessage;
14 import org.mule.api.construct.FlowConstruct;
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.api.retry.RetryContext;
19 import org.mule.api.transport.Connector;
20 import org.mule.transport.AbstractPollingMessageReceiver;
21 import org.mule.transport.ConnectException;
22
23 import java.io.FilenameFilter;
24 import java.io.IOException;
25 import java.text.MessageFormat;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Set;
31
32 import javax.resource.spi.work.Work;
33
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
44
45
46 protected final Set<String> scheduledFiles = Collections.synchronizedSet(new HashSet<String>());
47 protected final Set<String> currentFiles = Collections.synchronizedSet(new HashSet<String>());
48
49 public FtpMessageReceiver(Connector connector,
50 FlowConstruct flowConstruct,
51 InboundEndpoint endpoint,
52 long frequency) throws CreateException
53 {
54 super(connector, flowConstruct, endpoint);
55
56 this.setFrequency(frequency);
57
58 this.connector = (FtpConnector) connector;
59
60 if (endpoint.getFilter() instanceof FilenameFilter)
61 {
62 this.filenameFilter = (FilenameFilter) endpoint.getFilter();
63 }
64 else
65 {
66 this.filenameFilter = null;
67 }
68 }
69
70 @Override
71 public void poll() throws Exception
72 {
73 FTPFile[] files = listFiles();
74 if (logger.isDebugEnabled())
75 {
76 logger.debug("Poll encountered " + files.length + " new file(s)");
77 }
78
79 synchronized (scheduledFiles)
80 {
81 for (final FTPFile file : files)
82 {
83 final String fileName = file.getName();
84
85 if (!scheduledFiles.contains(fileName) && !currentFiles.contains(fileName))
86 {
87 scheduledFiles.add(fileName);
88 getWorkManager().scheduleWork(new FtpWork(fileName, file));
89 }
90 }
91 }
92 }
93
94 protected FTPFile[] listFiles() throws Exception
95 {
96 FTPClient client = null;
97 try
98 {
99 try
100 {
101 client = connector.createFtpClient(endpoint);
102 }
103 catch (Exception e)
104 {
105 throw new ConnectException(e, this);
106 }
107 FTPFile[] files = client.listFiles();
108
109 if (!FTPReply.isPositiveCompletion(client.getReplyCode()))
110 {
111 throw new IOException("Failed to list files. Ftp error: " + client.getReplyCode());
112 }
113
114 if (files == null || files.length == 0)
115 {
116 return files;
117 }
118
119 List<FTPFile> v = new ArrayList<FTPFile>();
120
121 for (FTPFile file : files)
122 {
123 if (file.isFile())
124 {
125 if (filenameFilter == null || filenameFilter.accept(null, file.getName()))
126 {
127 v.add(file);
128 }
129 }
130 }
131
132 return v.toArray(new FTPFile[v.size()]);
133 }
134 finally
135 {
136 if (client != null)
137 {
138 connector.releaseFtp(endpoint.getEndpointURI(), client);
139 }
140 }
141 }
142
143 protected void processFile(FTPFile file) throws Exception
144 {
145 FTPClient client = null;
146 try
147 {
148 if (!connector.validateFile(file))
149 {
150 return;
151 }
152
153 try
154 {
155 client = connector.createFtpClient(endpoint);
156 }
157 catch (Exception e)
158 {
159 throw new ConnectException(e, this);
160 }
161
162 FtpMuleMessageFactory muleMessageFactory = createMuleMessageFactory(client);
163 MuleMessage message = muleMessageFactory.create(file, endpoint.getEncoding());
164
165 routeMessage(message);
166 postProcess(client, file, message);
167 }
168 finally
169 {
170 if (client != null)
171 {
172 connector.releaseFtp(endpoint.getEndpointURI(), client);
173 }
174 }
175 }
176
177 @Override
178 protected void initializeMessageFactory() throws InitialisationException
179 {
180
181
182
183 }
184
185 protected FtpMuleMessageFactory createMuleMessageFactory(FTPClient client) throws CreateException
186 {
187 FtpMuleMessageFactory factory = (FtpMuleMessageFactory) createMuleMessageFactory();
188 factory.setStreaming(connector.isStreaming());
189 factory.setFtpClient(client);
190
191 return factory;
192 }
193
194 protected void postProcess(FTPClient client, FTPFile file, MuleMessage message) throws Exception
195 {
196 if (!client.deleteFile(file.getName()))
197 {
198 throw new IOException(MessageFormat.format("Failed to delete file {0}. Ftp error: {1}",
199 file.getName(), client.getReplyCode()));
200 }
201 if (logger.isDebugEnabled())
202 {
203 logger.debug("Deleted processed file " + file.getName());
204 }
205
206 if (connector.isStreaming())
207 {
208 if (!client.completePendingCommand())
209 {
210 throw new IOException(MessageFormat.format("Failed to complete a pending command. Retrieveing file {0}. Ftp error: {1}",
211 file.getName(), client.getReplyCode()));
212 }
213 }
214 }
215
216 @Override
217 protected void doConnect() throws Exception
218 {
219
220 }
221
222 @Override
223 public RetryContext validateConnection(RetryContext retryContext)
224 {
225 FTPClient client = null;
226 try
227 {
228 client = connector.createFtpClient(endpoint);
229 client.sendNoOp();
230 client.logout();
231 client.disconnect();
232
233 retryContext.setOk();
234 }
235 catch (Exception ex)
236 {
237 retryContext.setFailed(ex);
238 }
239 finally
240 {
241 try
242 {
243 if (client != null)
244 {
245 connector.releaseFtp(endpoint.getEndpointURI(), client);
246 }
247 }
248 catch (Exception e)
249 {
250 if (logger.isDebugEnabled())
251 {
252 logger.debug("Failed to release ftp client " + client, e);
253 }
254 }
255 }
256
257 return retryContext;
258 }
259
260 @Override
261 protected void doDisconnect() throws Exception
262 {
263
264 }
265
266 @Override
267 protected void doDispose()
268 {
269
270 }
271
272 private final class FtpWork implements Work
273 {
274 private final String name;
275 private final FTPFile file;
276
277 private FtpWork(String name, FTPFile file)
278 {
279 this.name = name;
280 this.file = file;
281 }
282
283 public void run()
284 {
285 try
286 {
287 currentFiles.add(name);
288 processFile(file);
289 }
290 catch (Exception e)
291 {
292 getConnector().getMuleContext().getExceptionListener().handleException(e);
293 }
294 finally
295 {
296 currentFiles.remove(name);
297 scheduledFiles.remove(name);
298 }
299 }
300
301 public void release()
302 {
303
304 }
305 }
306
307 }