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