Coverage Report - org.mule.transport.file.FileConnector
 
Classes in this File Line Coverage Branch Coverage Complexity
FileConnector
0%
0/184
0%
0/72
0
 
 1  
 /*
 2  
  * $Id: FileConnector.java 19640 2010-09-13 22:00:05Z tcarlson $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.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  
  * <code>FileConnector</code> is used for setting up listeners on a directory and
 45  
  * for writing files to a directory. The connecotry provides support for defining
 46  
  * file output patterns and filters for receiving files.
 47  
  */
 48  
 
 49  
 public class FileConnector extends AbstractConnector
 50  
 {
 51  
 
 52  0
     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  
     // These are properties that can be overridden on the Receiver by the endpoint declaration
 58  
     // inbound only
 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  
     // outbound only
 65  
     public static final String PROPERTY_OUTPUT_PATTERN = "outputPattern";
 66  
 
 67  
     // message properties
 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  
      * Time in milliseconds to poll. On each poll the poll() method is called
 79  
      */
 80  0
     private long pollingFrequency = 0;
 81  
 
 82  0
     private String moveToPattern = null;
 83  
 
 84  0
     private String writeToDirectoryName = null;
 85  
 
 86  0
     private String moveToDirectoryName = null;
 87  
     
 88  0
     private String workDirectoryName = null;
 89  
 
 90  0
     private String workFileNamePattern = DEFAULT_WORK_FILENAME_PATTERN;
 91  
 
 92  0
     private String readFromDirectoryName = null;
 93  
 
 94  0
     private String outputPattern = null;
 95  
 
 96  0
     private boolean outputAppend = false;
 97  
 
 98  0
     private boolean autoDelete = true;
 99  
 
 100  0
     private boolean checkFileAge = false;
 101  
 
 102  0
     private long fileAge = 0;
 103  
 
 104  0
     private FileOutputStream outputStream = null;
 105  
 
 106  0
     private boolean serialiseObjects = false;
 107  
 
 108  0
     private boolean streaming = true;
 109  
 
 110  
     public FilenameParser filenameParser;
 111  
 
 112  0
     private boolean recursive = false;
 113  
 
 114  
     public FileConnector(MuleContext context)
 115  
     {
 116  0
         super(context);
 117  0
         filenameParser = new ExpressionFilenameParser();
 118  0
     }
 119  
 
 120  
     @Override
 121  
     protected void configureDispatcherPool()
 122  
     {
 123  0
         if (isOutputAppend())
 124  
         {
 125  0
             setMaxDispatchersActive(getDispatcherThreadingProfile().getMaxThreadsActive());
 126  
         }
 127  
         else
 128  
         {
 129  0
             super.configureDispatcherPool();
 130  
         }
 131  0
     }
 132  
 
 133  
     @Override
 134  
     public void setMaxDispatchersActive(int value)
 135  
     {
 136  0
         if (isOutputAppend() && value != 1)
 137  
         {
 138  0
             logger.warn("MULE-1773: cannot configure maxDispatchersActive when using outputAppend. New value not set");
 139  
         }
 140  
         else
 141  
         {
 142  0
             super.setMaxDispatchersActive(value);
 143  
         }
 144  0
     }
 145  
 
 146  
     @Override
 147  
     protected Object getReceiverKey(FlowConstruct flowConstruct, InboundEndpoint endpoint)
 148  
     {
 149  0
         if (endpoint.getFilter() != null && endpoint.getFilter() instanceof FilenameWildcardFilter)
 150  
         {
 151  0
             return endpoint.getEndpointURI().getAddress() + "/"
 152  
                     + ((FilenameWildcardFilter) endpoint.getFilter()).getPattern();
 153  
         }
 154  0
         return endpoint.getEndpointURI().getAddress();
 155  
     }
 156  
 
 157  
     /**
 158  
      * Registers a listener for a particular directory The following properties can
 159  
      * be overriden in the endpoint declaration
 160  
      * <ul>
 161  
      * <li>moveToDirectory</li>
 162  
      * <li>filterPatterns</li>
 163  
      * <li>filterClass</li>
 164  
      * <li>pollingFrequency</li>
 165  
      * </ul>
 166  
      */
 167  
     @Override
 168  
     public MessageReceiver createReceiver(FlowConstruct flowConstruct, InboundEndpoint endpoint) throws Exception
 169  
     {
 170  0
         String readDir = endpoint.getEndpointURI().getAddress();
 171  0
         if (null != getReadFromDirectory())
 172  
         {
 173  0
             readDir = getReadFromDirectory();
 174  
         }
 175  
 
 176  0
         long polling = this.pollingFrequency;
 177  
 
 178  0
         String moveTo = moveToDirectoryName;
 179  0
         String moveToPattern = getMoveToPattern();
 180  
 
 181  0
         Map props = endpoint.getProperties();
 182  0
         if (props != null)
 183  
         {
 184  
             // Override properties on the endpoint for the specific endpoint
 185  0
             String read = (String) props.get(PROPERTY_READ_FROM_DIRECTORY);
 186  0
             if (read != null)
 187  
             {
 188  0
                 readDir = read;
 189  
             }
 190  0
             String move = (String) props.get(PROPERTY_MOVE_TO_DIRECTORY);
 191  0
             if (move != null)
 192  
             {
 193  0
                 moveTo = move;
 194  
             }
 195  0
             String tempMoveToPattern = (String) props.get(PROPERTY_MOVE_TO_PATTERN);
 196  0
             if (tempMoveToPattern != null)
 197  
             {
 198  0
                 if (logger.isDebugEnabled())
 199  
                 {
 200  0
                     logger.debug("set moveTo Pattern to: " + tempMoveToPattern);
 201  
                 }
 202  0
                 moveToPattern = tempMoveToPattern;
 203  
             }
 204  
 
 205  0
             String tempPolling = (String) props.get(PROPERTY_POLLING_FREQUENCY);
 206  0
             if (tempPolling != null)
 207  
             {
 208  0
                 polling = Long.parseLong(tempPolling);
 209  
             }
 210  
 
 211  0
             if (polling <= 0)
 212  
             {
 213  0
                 polling = DEFAULT_POLLING_FREQUENCY;
 214  
             }
 215  
 
 216  0
             if (logger.isDebugEnabled())
 217  
             {
 218  0
                 logger.debug("set polling frequency to: " + polling);
 219  
             }
 220  0
             String tempFileAge = (String) props.get(PROPERTY_FILE_AGE);
 221  0
             if (tempFileAge != null)
 222  
             {
 223  
                 try
 224  
                 {
 225  0
                     setFileAge(Long.parseLong(tempFileAge));
 226  
                 }
 227  0
                 catch (Exception ex1)
 228  
                 {
 229  0
                     logger.error("Failed to set fileAge", ex1);
 230  0
                 }
 231  
             }
 232  
         }
 233  
 
 234  
         try
 235  
         {
 236  0
             return serviceDescriptor.createMessageReceiver(this, flowConstruct, endpoint, new Object[]{readDir,
 237  
                     moveTo, moveToPattern, new Long(polling)});
 238  
 
 239  
         }
 240  0
         catch (Exception e)
 241  
         {
 242  0
             throw new InitialisationException(
 243  
                     CoreMessages.failedToCreateObjectWith("Message Receiver",
 244  
                             serviceDescriptor), e, this);
 245  
         }
 246  
     }
 247  
 
 248  
     public String getProtocol()
 249  
     {
 250  0
         return FILE;
 251  
     }
 252  
 
 253  
     public FilenameParser getFilenameParser()
 254  
     {
 255  0
         return filenameParser;
 256  
     }
 257  
 
 258  
     public void setFilenameParser(FilenameParser filenameParser)
 259  
     {
 260  0
         this.filenameParser = filenameParser;
 261  0
         if (filenameParser != null)
 262  
         {
 263  0
             filenameParser.setMuleContext(muleContext);
 264  
         }
 265  0
     }
 266  
 
 267  
     @Override
 268  
     protected void doDispose()
 269  
     {
 270  
         try
 271  
         {
 272  0
             doStop();
 273  
         }
 274  0
         catch (MuleException e)
 275  
         {
 276  0
             logger.error(e.getMessage(), e);
 277  0
         }
 278  0
     }
 279  
 
 280  
     @Override
 281  
     protected void doInitialise() throws InitialisationException
 282  
     {
 283  0
         if (filenameParser != null)
 284  
         {
 285  0
             filenameParser.setMuleContext(muleContext);
 286  
         }
 287  
 
 288  
         // MULE-1773: limit the number of dispatchers per endpoint to 1 until
 289  
         // there is a proper (Distributed)LockManager in place (MULE-2402).
 290  
         // We also override the setter to prevent "wrong" configuration for now.
 291  0
         if (isOutputAppend())
 292  
         {
 293  0
             super.setMaxDispatchersActive(1);
 294  
         }
 295  0
     }
 296  
 
 297  
     @Override
 298  
     protected void doConnect() throws Exception
 299  
     {
 300  
         // template method, nothing to do
 301  0
     }
 302  
 
 303  
     @Override
 304  
     protected void doDisconnect() throws Exception
 305  
     {
 306  
         // template method, nothing to do
 307  0
     }
 308  
 
 309  
     @Override
 310  
     protected void doStart() throws MuleException
 311  
     {
 312  
         // template method, nothing to do
 313  0
     }
 314  
 
 315  
     @Override
 316  
     protected void doStop() throws MuleException
 317  
     {
 318  0
         if (outputStream != null)
 319  
         {
 320  
             try
 321  
             {
 322  0
                 outputStream.close();
 323  
             }
 324  0
             catch (IOException e)
 325  
             {
 326  0
                 logger.warn("Failed to close file output stream on stop: " + e);
 327  0
             }
 328  
         }
 329  0
     }
 330  
 
 331  
     public String getMoveToDirectory()
 332  
     {
 333  0
         return moveToDirectoryName;
 334  
     }
 335  
 
 336  
     public void setMoveToDirectory(String dir)
 337  
     {
 338  0
         this.moveToDirectoryName = dir;
 339  0
     }
 340  
 
 341  
     public void setWorkDirectory(String workDirectoryName) throws IOException 
 342  
     {
 343  0
         this.workDirectoryName = workDirectoryName;
 344  0
         if (workDirectoryName != null)
 345  
         {
 346  0
             File workDirectory = FileUtils.openDirectory(workDirectoryName);
 347  0
             if (!workDirectory.canWrite())
 348  
             {
 349  0
                 throw new IOException(
 350  
                         "Error on initialization, Work Directory '" + workDirectory +"' is not writeable");
 351  
             }
 352  
         }
 353  0
     }
 354  
     
 355  
     public String getWorkDirectory()
 356  
     {
 357  0
         return workDirectoryName;
 358  
     }
 359  
 
 360  
     public void setWorkFileNamePattern(String workFileNamePattern)
 361  
     {
 362  0
         this.workFileNamePattern = workFileNamePattern;
 363  0
     }
 364  
 
 365  
     public String getWorkFileNamePattern()
 366  
     {
 367  0
         return workFileNamePattern;
 368  
     }
 369  
 
 370  
     public boolean isOutputAppend()
 371  
     {
 372  0
         return outputAppend;
 373  
     }
 374  
 
 375  
     public void setOutputAppend(boolean outputAppend)
 376  
     {
 377  0
         this.outputAppend = outputAppend;
 378  0
     }
 379  
 
 380  
     public String getOutputPattern()
 381  
     {
 382  0
         return outputPattern;
 383  
     }
 384  
 
 385  
     public void setOutputPattern(String outputPattern)
 386  
     {
 387  0
         this.outputPattern = outputPattern;
 388  0
     }
 389  
 
 390  
     public FileOutputStream getOutputStream()
 391  
     {
 392  0
         return outputStream;
 393  
     }
 394  
 
 395  
     public void setOutputStream(FileOutputStream outputStream)
 396  
     {
 397  0
         this.outputStream = outputStream;
 398  0
     }
 399  
 
 400  
     public long getPollingFrequency()
 401  
     {
 402  0
         return pollingFrequency;
 403  
     }
 404  
 
 405  
     public void setPollingFrequency(long pollingFrequency)
 406  
     {
 407  0
         this.pollingFrequency = pollingFrequency;
 408  0
     }
 409  
 
 410  
     public long getFileAge()
 411  
     {
 412  0
         return fileAge;
 413  
     }
 414  
 
 415  
     public boolean getCheckFileAge()
 416  
     {
 417  0
         return checkFileAge;
 418  
     }
 419  
 
 420  
     public void setFileAge(long fileAge)
 421  
     {
 422  0
         this.fileAge = fileAge;
 423  0
         this.checkFileAge = true;
 424  0
     }
 425  
 
 426  
     public String getWriteToDirectory()
 427  
     {
 428  0
         return writeToDirectoryName;
 429  
     }
 430  
 
 431  
     public void setWriteToDirectory(String dir) throws IOException
 432  
     {
 433  0
         this.writeToDirectoryName = dir;
 434  0
         if (writeToDirectoryName != null)
 435  
         {
 436  0
             File writeToDirectory = FileUtils.openDirectory(writeToDirectoryName);
 437  0
             if (!writeToDirectory.canWrite())
 438  
             {
 439  0
                 throw new IOException(
 440  
                         "Error on initialization, " + writeToDirectory 
 441  
                         + " does not exist or is not writeable");
 442  
             }
 443  
         }
 444  0
     }
 445  
 
 446  
     public String getReadFromDirectory()
 447  
     {
 448  0
         return readFromDirectoryName;
 449  
     }
 450  
 
 451  
     public void setReadFromDirectory(String dir) throws IOException
 452  
     {
 453  0
         this.readFromDirectoryName = dir;
 454  0
         if (readFromDirectoryName != null)
 455  
         {
 456  
             // check if the directory exists/can be read
 457  0
             FileUtils.openDirectory((readFromDirectoryName));
 458  
         }
 459  0
     }
 460  
 
 461  
     public boolean isSerialiseObjects()
 462  
     {
 463  0
         return serialiseObjects;
 464  
     }
 465  
 
 466  
     public void setSerialiseObjects(boolean serialiseObjects)
 467  
     {
 468  
         // set serialisable transformers on the connector if this is set
 469  0
         if (serialiseObjects)
 470  
         {
 471  0
             if (serviceOverrides == null)
 472  
             {
 473  0
                 serviceOverrides = new Properties();
 474  
             }
 475  0
             serviceOverrides.setProperty(MuleProperties.CONNECTOR_INBOUND_TRANSFORMER,
 476  
                     ByteArrayToSerializable.class.getName());
 477  0
             serviceOverrides.setProperty(MuleProperties.CONNECTOR_OUTBOUND_TRANSFORMER,
 478  
                     SerializableToByteArray.class.getName());
 479  
         }
 480  
 
 481  0
         this.serialiseObjects = serialiseObjects;
 482  0
     }
 483  
 
 484  
     public boolean isAutoDelete()
 485  
     {
 486  0
         return autoDelete;
 487  
     }
 488  
 
 489  
     public void setAutoDelete(boolean autoDelete)
 490  
     {
 491  0
         this.autoDelete = autoDelete;
 492  0
     }
 493  
 
 494  
     public String getMoveToPattern()
 495  
     {
 496  0
         return moveToPattern;
 497  
     }
 498  
 
 499  
     public void setMoveToPattern(String moveToPattern)
 500  
     {
 501  0
         this.moveToPattern = moveToPattern;
 502  0
     }
 503  
 
 504  
     /**
 505  
      * Well get the output stream (if any) for this type of transport. Typically this
 506  
      * will be called only when Streaming is being used on an outbound endpoint
 507  
      *
 508  
      * @param endpoint the endpoint that releates to this Dispatcher
 509  
      * @param message  the current message being processed
 510  
      * @return the output stream to use for this request or null if the transport
 511  
      *         does not support streaming
 512  
      * @throws org.mule.api.MuleException
 513  
      */
 514  
     public OutputStream getOutputStream(OutboundEndpoint endpoint, MuleEvent event)
 515  
             throws MuleException
 516  
     {
 517  0
         MuleMessage message = event.getMessage();
 518  0
         String address = endpoint.getEndpointURI().getAddress();
 519  0
         String writeToDirectory = message.getOutboundProperty(FileConnector.PROPERTY_WRITE_TO_DIRECTORY);
 520  0
         if (writeToDirectory == null)
 521  
         {
 522  0
             writeToDirectory = getWriteToDirectory();
 523  
         }
 524  0
         if (writeToDirectory != null)
 525  
         {
 526  0
             address = getFilenameParser().getFilename(message, writeToDirectory);
 527  
         }
 528  
 
 529  
         String filename;
 530  0
         String outPattern = (String) endpoint.getProperty(FileConnector.PROPERTY_OUTPUT_PATTERN);
 531  0
         if (outPattern == null)
 532  
         {
 533  0
             outPattern = message.getOutboundProperty(FileConnector.PROPERTY_OUTPUT_PATTERN);
 534  
         }
 535  0
         if (outPattern == null)
 536  
         {
 537  0
             outPattern = getOutputPattern();
 538  
         }
 539  
         try
 540  
         {
 541  0
             if (outPattern != null)
 542  
             {
 543  0
                 filename = generateFilename(message, outPattern);
 544  
             }
 545  
             else
 546  
             {
 547  0
                 filename = message.getOutboundProperty(FileConnector.PROPERTY_FILENAME);
 548  0
                 if (filename == null)
 549  
                 {
 550  0
                     filename = generateFilename(message, null);
 551  
                 }
 552  
             }
 553  
 
 554  0
             if (filename == null)
 555  
             {
 556  0
                 throw new IOException("Filename is null");
 557  
             }
 558  0
             File file = FileUtils.createFile(address + "/" + filename);
 559  0
             if (logger.isInfoEnabled())
 560  
             {
 561  0
                 logger.info("Writing file to: " + file.getAbsolutePath());
 562  
             }
 563  
 
 564  0
             return new FileOutputStream(file, isOutputAppend());
 565  
         }
 566  0
         catch (IOException e)
 567  
         {
 568  0
             throw new DispatchException(CoreMessages.streamingFailedNoStream(), event, endpoint, e);
 569  
         }
 570  
     }
 571  
 
 572  
     private String generateFilename(MuleMessage message, String pattern)
 573  
     {
 574  0
         if (pattern == null)
 575  
         {
 576  0
             pattern = getOutputPattern();
 577  
         }
 578  0
         return getFilenameParser().getFilename(message, pattern);
 579  
     }
 580  
 
 581  
     public boolean isStreaming()
 582  
     {
 583  0
         return streaming;
 584  
     }
 585  
 
 586  
     public void setStreaming(boolean streaming)
 587  
     {
 588  0
         this.streaming = streaming;
 589  0
     }
 590  
         
 591  
     @Override
 592  
     public MuleMessageFactory createMuleMessageFactory() throws CreateException
 593  
     {
 594  
         // See MULE-3209, MULE-3199
 595  0
         if (isStreaming())
 596  
         {
 597  0
             return new FileMuleMessageFactory(muleContext);
 598  
         }
 599  
         else
 600  
         {
 601  0
             return super.createMuleMessageFactory();
 602  
         }
 603  
     }
 604  
     public boolean isRecursive()
 605  
     {
 606  0
         return recursive;
 607  
     }
 608  
 
 609  
     public void setRecursive(boolean recursive)
 610  
     {
 611  0
         this.recursive = recursive;
 612  0
     }
 613  
 }