1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.file;
12
13 import org.mule.api.MuleContext;
14 import org.mule.api.MuleEvent;
15 import org.mule.api.MuleException;
16 import org.mule.api.MuleMessage;
17 import org.mule.api.config.MuleProperties;
18 import org.mule.api.construct.FlowConstruct;
19 import org.mule.api.endpoint.InboundEndpoint;
20 import org.mule.api.endpoint.OutboundEndpoint;
21 import org.mule.api.lifecycle.CreateException;
22 import org.mule.api.lifecycle.InitialisationException;
23 import org.mule.api.transport.DispatchException;
24 import org.mule.api.transport.MessageReceiver;
25 import org.mule.api.transport.MuleMessageFactory;
26 import org.mule.config.i18n.CoreMessages;
27 import org.mule.transformer.simple.ByteArrayToSerializable;
28 import org.mule.transformer.simple.SerializableToByteArray;
29 import org.mule.transport.AbstractConnector;
30 import org.mule.transport.file.filters.FilenameWildcardFilter;
31 import org.mule.util.FileUtils;
32
33 import java.io.File;
34 import java.io.FileOutputStream;
35 import java.io.IOException;
36 import java.io.OutputStream;
37 import java.util.Map;
38 import java.util.Properties;
39
40 import org.apache.commons.logging.Log;
41 import org.apache.commons.logging.LogFactory;
42
43
44
45
46
47
48
49 public class FileConnector extends AbstractConnector
50 {
51
52 private static Log logger = LogFactory.getLog(FileConnector.class);
53
54 public static final String FILE = "file";
55 private static final String DEFAULT_WORK_FILENAME_PATTERN = "#[function:uuid].#[function:systime].#[header:originalFilename]";
56
57
58
59 public static final String PROPERTY_POLLING_FREQUENCY = "pollingFrequency";
60 public static final String PROPERTY_FILE_AGE = "fileAge";
61 public static final String PROPERTY_MOVE_TO_PATTERN = "moveToPattern";
62 public static final String PROPERTY_MOVE_TO_DIRECTORY = "moveToDirectory";
63 public static final String PROPERTY_READ_FROM_DIRECTORY = "readFromDirectoryName";
64
65 public static final String PROPERTY_OUTPUT_PATTERN = "outputPattern";
66
67
68 public static final String PROPERTY_FILENAME = "filename";
69 public static final String PROPERTY_ORIGINAL_FILENAME = "originalFilename";
70 public static final String PROPERTY_DIRECTORY = "directory";
71 public static final String PROPERTY_WRITE_TO_DIRECTORY = "writeToDirectoryName";
72 public static final String PROPERTY_FILE_SIZE = "fileSize";
73 public static final String PROPERTY_FILE_TIMESTAMP = "timestamp";
74
75 public static final long DEFAULT_POLLING_FREQUENCY = 1000;
76
77
78
79
80 private long pollingFrequency = 0;
81
82 private String moveToPattern = null;
83
84 private String writeToDirectoryName = null;
85
86 private String moveToDirectoryName = null;
87
88 private String workDirectoryName = null;
89
90 private String workFileNamePattern = DEFAULT_WORK_FILENAME_PATTERN;
91
92 private String readFromDirectoryName = null;
93
94 private String outputPattern = null;
95
96 private boolean outputAppend = false;
97
98 private boolean autoDelete = true;
99
100 private boolean checkFileAge = false;
101
102 private long fileAge = 0;
103
104 private FileOutputStream outputStream = null;
105
106 private boolean serialiseObjects = false;
107
108 private boolean streaming = true;
109
110 public FilenameParser filenameParser;
111
112 private boolean recursive = false;
113
114 public FileConnector(MuleContext context)
115 {
116 super(context);
117 filenameParser = new ExpressionFilenameParser();
118 }
119
120 @Override
121 protected void configureDispatcherPool()
122 {
123 if (isOutputAppend())
124 {
125 setMaxDispatchersActive(getDispatcherThreadingProfile().getMaxThreadsActive());
126 }
127 else
128 {
129 super.configureDispatcherPool();
130 }
131 }
132
133 @Override
134 public void setMaxDispatchersActive(int value)
135 {
136 if (isOutputAppend() && value != 1)
137 {
138 logger.warn("MULE-1773: cannot configure maxDispatchersActive when using outputAppend. New value not set");
139 }
140 else
141 {
142 super.setMaxDispatchersActive(value);
143 }
144 }
145
146 @Override
147 protected Object getReceiverKey(FlowConstruct flowConstruct, InboundEndpoint endpoint)
148 {
149 if (endpoint.getFilter() != null && endpoint.getFilter() instanceof FilenameWildcardFilter)
150 {
151 return endpoint.getEndpointURI().getAddress() + "/"
152 + ((FilenameWildcardFilter) endpoint.getFilter()).getPattern();
153 }
154 return endpoint.getEndpointURI().getAddress();
155 }
156
157
158
159
160
161
162
163
164
165
166
167 @Override
168 public MessageReceiver createReceiver(FlowConstruct flowConstruct, InboundEndpoint endpoint) throws Exception
169 {
170 String readDir = endpoint.getEndpointURI().getAddress();
171 if (null != getReadFromDirectory())
172 {
173 readDir = getReadFromDirectory();
174 }
175
176 long polling = this.pollingFrequency;
177
178 String moveTo = moveToDirectoryName;
179 String moveToPattern = getMoveToPattern();
180
181 Map props = endpoint.getProperties();
182 if (props != null)
183 {
184
185 String read = (String) props.get(PROPERTY_READ_FROM_DIRECTORY);
186 if (read != null)
187 {
188 readDir = read;
189 }
190 String move = (String) props.get(PROPERTY_MOVE_TO_DIRECTORY);
191 if (move != null)
192 {
193 moveTo = move;
194 }
195 String tempMoveToPattern = (String) props.get(PROPERTY_MOVE_TO_PATTERN);
196 if (tempMoveToPattern != null)
197 {
198 if (logger.isDebugEnabled())
199 {
200 logger.debug("set moveTo Pattern to: " + tempMoveToPattern);
201 }
202 moveToPattern = tempMoveToPattern;
203 }
204
205 String tempPolling = (String) props.get(PROPERTY_POLLING_FREQUENCY);
206 if (tempPolling != null)
207 {
208 polling = Long.parseLong(tempPolling);
209 }
210
211 if (polling <= 0)
212 {
213 polling = DEFAULT_POLLING_FREQUENCY;
214 }
215
216 if (logger.isDebugEnabled())
217 {
218 logger.debug("set polling frequency to: " + polling);
219 }
220 String tempFileAge = (String) props.get(PROPERTY_FILE_AGE);
221 if (tempFileAge != null)
222 {
223 try
224 {
225 setFileAge(Long.parseLong(tempFileAge));
226 }
227 catch (Exception ex1)
228 {
229 logger.error("Failed to set fileAge", ex1);
230 }
231 }
232 }
233
234 try
235 {
236 return serviceDescriptor.createMessageReceiver(this, flowConstruct, endpoint, new Object[]{readDir,
237 moveTo, moveToPattern, new Long(polling)});
238
239 }
240 catch (Exception e)
241 {
242 throw new InitialisationException(
243 CoreMessages.failedToCreateObjectWith("Message Receiver",
244 serviceDescriptor), e, this);
245 }
246 }
247
248 public String getProtocol()
249 {
250 return FILE;
251 }
252
253 public FilenameParser getFilenameParser()
254 {
255 return filenameParser;
256 }
257
258 public void setFilenameParser(FilenameParser filenameParser)
259 {
260 this.filenameParser = filenameParser;
261 if (filenameParser != null)
262 {
263 filenameParser.setMuleContext(muleContext);
264 }
265 }
266
267 @Override
268 protected void doDispose()
269 {
270 try
271 {
272 doStop();
273 }
274 catch (MuleException e)
275 {
276 logger.error(e.getMessage(), e);
277 }
278 }
279
280 @Override
281 protected void doInitialise() throws InitialisationException
282 {
283 if (filenameParser != null)
284 {
285 filenameParser.setMuleContext(muleContext);
286 }
287
288
289
290
291 if (isOutputAppend())
292 {
293 super.setMaxDispatchersActive(1);
294 }
295 }
296
297 @Override
298 protected void doConnect() throws Exception
299 {
300
301 }
302
303 @Override
304 protected void doDisconnect() throws Exception
305 {
306
307 }
308
309 @Override
310 protected void doStart() throws MuleException
311 {
312
313 }
314
315 @Override
316 protected void doStop() throws MuleException
317 {
318 if (outputStream != null)
319 {
320 try
321 {
322 outputStream.close();
323 }
324 catch (IOException e)
325 {
326 logger.warn("Failed to close file output stream on stop: " + e);
327 }
328 }
329 }
330
331 public String getMoveToDirectory()
332 {
333 return moveToDirectoryName;
334 }
335
336 public void setMoveToDirectory(String dir)
337 {
338 this.moveToDirectoryName = dir;
339 }
340
341 public void setWorkDirectory(String workDirectoryName) throws IOException
342 {
343 this.workDirectoryName = workDirectoryName;
344 if (workDirectoryName != null)
345 {
346 File workDirectory = FileUtils.openDirectory(workDirectoryName);
347 if (!workDirectory.canWrite())
348 {
349 throw new IOException(
350 "Error on initialization, Work Directory '" + workDirectory +"' is not writeable");
351 }
352 }
353 }
354
355 public String getWorkDirectory()
356 {
357 return workDirectoryName;
358 }
359
360 public void setWorkFileNamePattern(String workFileNamePattern)
361 {
362 this.workFileNamePattern = workFileNamePattern;
363 }
364
365 public String getWorkFileNamePattern()
366 {
367 return workFileNamePattern;
368 }
369
370 public boolean isOutputAppend()
371 {
372 return outputAppend;
373 }
374
375 public void setOutputAppend(boolean outputAppend)
376 {
377 this.outputAppend = outputAppend;
378 }
379
380 public String getOutputPattern()
381 {
382 return outputPattern;
383 }
384
385 public void setOutputPattern(String outputPattern)
386 {
387 this.outputPattern = outputPattern;
388 }
389
390 public FileOutputStream getOutputStream()
391 {
392 return outputStream;
393 }
394
395 public void setOutputStream(FileOutputStream outputStream)
396 {
397 this.outputStream = outputStream;
398 }
399
400 public long getPollingFrequency()
401 {
402 return pollingFrequency;
403 }
404
405 public void setPollingFrequency(long pollingFrequency)
406 {
407 this.pollingFrequency = pollingFrequency;
408 }
409
410 public long getFileAge()
411 {
412 return fileAge;
413 }
414
415 public boolean getCheckFileAge()
416 {
417 return checkFileAge;
418 }
419
420 public void setFileAge(long fileAge)
421 {
422 this.fileAge = fileAge;
423 this.checkFileAge = true;
424 }
425
426 public String getWriteToDirectory()
427 {
428 return writeToDirectoryName;
429 }
430
431 public void setWriteToDirectory(String dir) throws IOException
432 {
433 this.writeToDirectoryName = dir;
434 if (writeToDirectoryName != null)
435 {
436 File writeToDirectory = FileUtils.openDirectory(writeToDirectoryName);
437 if (!writeToDirectory.canWrite())
438 {
439 throw new IOException(
440 "Error on initialization, " + writeToDirectory
441 + " does not exist or is not writeable");
442 }
443 }
444 }
445
446 public String getReadFromDirectory()
447 {
448 return readFromDirectoryName;
449 }
450
451 public void setReadFromDirectory(String dir) throws IOException
452 {
453 this.readFromDirectoryName = dir;
454 if (readFromDirectoryName != null)
455 {
456
457 FileUtils.openDirectory((readFromDirectoryName));
458 }
459 }
460
461 public boolean isSerialiseObjects()
462 {
463 return serialiseObjects;
464 }
465
466 public void setSerialiseObjects(boolean serialiseObjects)
467 {
468
469 if (serialiseObjects)
470 {
471 if (serviceOverrides == null)
472 {
473 serviceOverrides = new Properties();
474 }
475 serviceOverrides.setProperty(MuleProperties.CONNECTOR_INBOUND_TRANSFORMER,
476 ByteArrayToSerializable.class.getName());
477 serviceOverrides.setProperty(MuleProperties.CONNECTOR_OUTBOUND_TRANSFORMER,
478 SerializableToByteArray.class.getName());
479 }
480
481 this.serialiseObjects = serialiseObjects;
482 }
483
484 public boolean isAutoDelete()
485 {
486 return autoDelete;
487 }
488
489 public void setAutoDelete(boolean autoDelete)
490 {
491 this.autoDelete = autoDelete;
492 }
493
494 public String getMoveToPattern()
495 {
496 return moveToPattern;
497 }
498
499 public void setMoveToPattern(String moveToPattern)
500 {
501 this.moveToPattern = moveToPattern;
502 }
503
504
505
506
507
508
509
510
511
512
513
514 public OutputStream getOutputStream(OutboundEndpoint endpoint, MuleEvent event)
515 throws MuleException
516 {
517 MuleMessage message = event.getMessage();
518 String address = endpoint.getEndpointURI().getAddress();
519 String writeToDirectory = message.getOutboundProperty(FileConnector.PROPERTY_WRITE_TO_DIRECTORY);
520 if (writeToDirectory == null)
521 {
522 writeToDirectory = getWriteToDirectory();
523 }
524 if (writeToDirectory != null)
525 {
526 address = getFilenameParser().getFilename(message, writeToDirectory);
527 }
528
529 String filename;
530 String outPattern = (String) endpoint.getProperty(FileConnector.PROPERTY_OUTPUT_PATTERN);
531 if (outPattern == null)
532 {
533 outPattern = message.getOutboundProperty(FileConnector.PROPERTY_OUTPUT_PATTERN);
534 }
535 if (outPattern == null)
536 {
537 outPattern = getOutputPattern();
538 }
539 try
540 {
541 if (outPattern != null)
542 {
543 filename = generateFilename(message, outPattern);
544 }
545 else
546 {
547 filename = message.getOutboundProperty(FileConnector.PROPERTY_FILENAME);
548 if (filename == null)
549 {
550 filename = generateFilename(message, null);
551 }
552 }
553
554 if (filename == null)
555 {
556 throw new IOException("Filename is null");
557 }
558 File file = FileUtils.createFile(address + "/" + filename);
559 if (logger.isInfoEnabled())
560 {
561 logger.info("Writing file to: " + file.getAbsolutePath());
562 }
563
564 return new FileOutputStream(file, isOutputAppend());
565 }
566 catch (IOException e)
567 {
568 throw new DispatchException(CoreMessages.streamingFailedNoStream(), event, endpoint, e);
569 }
570 }
571
572 private String generateFilename(MuleMessage message, String pattern)
573 {
574 if (pattern == null)
575 {
576 pattern = getOutputPattern();
577 }
578 return getFilenameParser().getFilename(message, pattern);
579 }
580
581 public boolean isStreaming()
582 {
583 return streaming;
584 }
585
586 public void setStreaming(boolean streaming)
587 {
588 this.streaming = streaming;
589 }
590
591 @Override
592 public MuleMessageFactory createMuleMessageFactory() throws CreateException
593 {
594
595 if (isStreaming())
596 {
597 return new FileMuleMessageFactory(muleContext);
598 }
599 else
600 {
601 return super.createMuleMessageFactory();
602 }
603 }
604 public boolean isRecursive()
605 {
606 return recursive;
607 }
608
609 public void setRecursive(boolean recursive)
610 {
611 this.recursive = recursive;
612 }
613 }