1
2
3
4
5
6
7
8
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.endpoint.UMOEndpointURI;
20 import org.mule.umo.lifecycle.InitialisationException;
21 import org.mule.umo.provider.UMOConnector;
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.io.output.ByteArrayOutputStream;
35 import org.apache.commons.net.ftp.FTPClient;
36 import org.apache.commons.net.ftp.FTPFile;
37 import org.apache.commons.net.ftp.FTPReply;
38
39 public class FtpMessageReceiver extends AbstractPollingMessageReceiver
40 {
41 protected final FtpConnector connector;
42 protected final FilenameFilter filenameFilter;
43
44
45
46
47 protected final Set scheduledFiles = Collections.synchronizedSet(new HashSet());
48 protected final Set currentFiles = Collections.synchronizedSet(new HashSet());
49
50 public FtpMessageReceiver(UMOConnector connector,
51 UMOComponent component,
52 UMOEndpoint endpoint,
53 long frequency) throws InitialisationException
54 {
55 super(connector, component, endpoint);
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 public void poll() throws Exception
71 {
72 FTPFile[] files = listFiles();
73
74 synchronized (scheduledFiles)
75 {
76 for (int i = 0; i < files.length; i++)
77 {
78 final FTPFile file = files[i];
79 final String fileName = file.getName();
80
81 if (!scheduledFiles.contains(fileName) && !currentFiles.contains(fileName))
82 {
83 scheduledFiles.add(fileName);
84 getWorkManager().scheduleWork(new FtpWork(fileName, file));
85 }
86 }
87 }
88 }
89
90 protected FTPFile[] listFiles() throws Exception
91 {
92 final UMOEndpointURI uri = endpoint.getEndpointURI();
93 FTPClient client = connector.getFtp(uri);
94
95 try
96 {
97 connector.enterActiveOrPassiveMode(client, endpoint);
98 connector.setupFileType(client, endpoint);
99
100 final String path = uri.getPath();
101 if (!client.changeWorkingDirectory(path))
102 {
103 throw new IOException(MessageFormat.format("Failed to change working directory to {0}. Ftp error: {1}",
104 new Object[] {path, new Integer(client.getReplyCode())}));
105 }
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 v = new ArrayList();
120
121 for (int i = 0; i < files.length; i++)
122 {
123 if (files[i].isFile())
124 {
125 if (filenameFilter == null || filenameFilter.accept(null, files[i].getName()))
126 {
127 v.add(files[i]);
128 }
129 }
130 }
131
132 return (FTPFile[]) v.toArray(new FTPFile[v.size()]);
133 }
134 finally
135 {
136 connector.releaseFtp(uri, client);
137 }
138 }
139
140 protected void processFile(FTPFile file) throws Exception
141 {
142 logger.debug("entering processFile()");
143 UMOEndpointURI uri = endpoint.getEndpointURI();
144 FTPClient client = connector.getFtp(uri);
145
146 try
147 {
148 connector.enterActiveOrPassiveMode(client, endpoint);
149 connector.setupFileType(client, endpoint);
150
151 final String fileName = file.getName();
152 final String path = uri.getPath();
153
154 if (!client.changeWorkingDirectory(path))
155 {
156 throw new IOException(MessageFormat.format("Failed to change working directory to {0}. Ftp error: {1}",
157 new Object[] {path, new Integer(client.getReplyCode())})); }
158
159 UMOMessage message;
160 if (endpoint.isStreaming())
161 {
162 message = new MuleMessage(
163 connector.getStreamMessageAdapter(client.retrieveFileStream(fileName), null));
164 }
165 else
166 {
167 ByteArrayOutputStream baos = new ByteArrayOutputStream();
168 if (!client.retrieveFile(fileName, baos))
169 {
170 throw new IOException(MessageFormat.format("Failed to retrieve file {0}. Ftp error: {1}",
171 new Object[] {fileName, new Integer(client.getReplyCode())}));
172 }
173 message = new MuleMessage(connector.getMessageAdapter(baos.toByteArray()));
174 }
175
176 message.setProperty(FileConnector.PROPERTY_ORIGINAL_FILENAME, fileName);
177 routeMessage(message);
178
179 if (!client.deleteFile(fileName))
180 {
181 throw new IOException(MessageFormat.format("Failed to delete file {0}. Ftp error: {1}",
182 new Object[] {fileName, new Integer(client.getReplyCode())}));
183 }
184 }
185 finally
186 {
187 logger.debug("leaving processFile()");
188 connector.releaseFtp(uri, client);
189 }
190 }
191
192 protected void doConnect() throws Exception
193 {
194
195
196 }
197
198 protected void doDisconnect() throws Exception
199 {
200
201 }
202
203 protected void doDispose()
204 {
205
206 }
207
208 private final class FtpWork implements Work
209 {
210 private final String name;
211 private final FTPFile file;
212
213 private FtpWork(String name, FTPFile file)
214 {
215 this.name = name;
216 this.file = file;
217 }
218
219 public void run()
220 {
221 try
222 {
223 currentFiles.add(name);
224 processFile(file);
225 }
226 catch (Exception e)
227 {
228 connector.handleException(e);
229 }
230 finally
231 {
232 currentFiles.remove(name);
233 scheduledFiles.remove(name);
234 }
235 }
236
237 public void release()
238 {
239
240 }
241 }
242
243 }