Coverage Report - org.mule.providers.file.FileConnector
 
Classes in this File Line Coverage Branch Coverage Complexity
FileConnector
45%
68/150
26%
18/70
2.167
 
 1  
 /*
 2  
  * $Id: FileConnector.java 10483 2008-01-23 11:57:53Z holger $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.providers.file;
 12  
 
 13  
 import org.mule.config.MuleProperties;
 14  
 import org.mule.config.i18n.CoreMessages;
 15  
 import org.mule.providers.AbstractConnector;
 16  
 import org.mule.providers.file.filters.FilenameWildcardFilter;
 17  
 import org.mule.transformers.NoActionTransformer;
 18  
 import org.mule.transformers.simple.ByteArrayToSerializable;
 19  
 import org.mule.transformers.simple.SerializableToByteArray;
 20  
 import org.mule.umo.UMOComponent;
 21  
 import org.mule.umo.UMOException;
 22  
 import org.mule.umo.UMOMessage;
 23  
 import org.mule.umo.endpoint.UMOEndpoint;
 24  
 import org.mule.umo.endpoint.UMOImmutableEndpoint;
 25  
 import org.mule.umo.lifecycle.InitialisationException;
 26  
 import org.mule.umo.provider.DispatchException;
 27  
 import org.mule.umo.provider.UMOMessageReceiver;
 28  
 import org.mule.util.FileUtils;
 29  
 import org.mule.util.MapUtils;
 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  
  * <code>FileConnector</code> is used for setting up listeners on a directory and
 43  
  * for writing files to a directory. The connecotry provides support for defining
 44  
  * file output patterns and filters for receiving files.
 45  
  */
 46  
 
 47  
 public class FileConnector extends AbstractConnector
 48  
 {
 49  
     /**
 50  
      * logger used by this class
 51  
      */
 52  6
     private static Log logger = LogFactory.getLog(FileConnector.class);
 53  
 
 54  
     // These are properties that can be overridden on the Receiver by the endpoint
 55  
     // declaration
 56  
     public static final String PROPERTY_POLLING_FREQUENCY = "pollingFrequency";
 57  
     public static final String PROPERTY_FILE_AGE = "fileAge";
 58  
     public static final String PROPERTY_FILENAME = "filename";
 59  
     public static final String PROPERTY_ORIGINAL_FILENAME = "originalFilename";
 60  
     public static final String PROPERTY_OUTPUT_PATTERN = "outputPattern";
 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_DELETE_ON_READ = "autoDelete";
 64  
     public static final String PROPERTY_DIRECTORY = "directory";
 65  
     public static final String PROPERTY_SERVICE_OVERRIDE = "serviceOverrides";
 66  
     public static final String PROPERTY_WRITE_TO_DIRECTORY = "writeToDirectoryName";
 67  
     public static final String PROPERTY_FILE_SIZE = "fileSize";
 68  
 
 69  
     public static final long DEFAULT_POLLING_FREQUENCY = 1000;
 70  
 
 71  
 
 72  
     /**
 73  
      * Time in milliseconds to poll. On each poll the poll() method is called
 74  
      */
 75  48
     private long pollingFrequency = 0;
 76  
 
 77  48
     private String moveToPattern = null;
 78  
 
 79  48
     private String writeToDirectoryName = null;
 80  
 
 81  48
     private String moveToDirectoryName = null;
 82  
 
 83  48
     private String outputPattern = null;
 84  
 
 85  48
     private boolean outputAppend = false;
 86  
 
 87  48
     private boolean autoDelete = true;
 88  
 
 89  48
     private boolean checkFileAge = false;
 90  
 
 91  48
     private long fileAge = 0;
 92  
 
 93  48
     private FileOutputStream outputStream = null;
 94  
 
 95  48
     private boolean serialiseObjects = false;
 96  
 
 97  
     public FilenameParser filenameParser;
 98  
 
 99  
     /*
 100  
      * (non-Javadoc)
 101  
      * 
 102  
      * @see org.mule.providers.AbstractConnector#doInitialise()
 103  
      */
 104  
     public FileConnector()
 105  
     {
 106  48
         super();
 107  
         // MULE-1773: limit the number of dispatchers per endpoint to 1 until
 108  
         // there is a proper (Distributed)LockManager in place (MULE-2402).
 109  
         // We also override the setter to prevent "wrong" configuration for now.
 110  48
         super.setMaxDispatchersActive(1);
 111  48
         filenameParser = new SimpleFilenameParser();
 112  48
     }
 113  
 
 114  
     // @Override
 115  
     public void setMaxDispatchersActive(int value)
 116  
     {
 117  2
         if (value != 1)
 118  
         {
 119  2
             throw new IllegalArgumentException("MULE-1773: cannot configure maxDispatchersActive");
 120  
         }
 121  0
     }
 122  
 
 123  
     // @Override
 124  
     protected Object getReceiverKey(UMOComponent component, UMOEndpoint endpoint)
 125  
     {
 126  16
         if (endpoint.getFilter() != null)
 127  
         {
 128  0
             return endpoint.getEndpointURI().getAddress() + "/"
 129  
                    + ((FilenameWildcardFilter) endpoint.getFilter()).getPattern();
 130  
         }
 131  16
         return endpoint.getEndpointURI().getAddress();
 132  
     }
 133  
 
 134  
     /**
 135  
      * Registers a listener for a particular directory The following properties can
 136  
      * be overriden in the endpoint declaration
 137  
      * <ul>
 138  
      * <li>moveToDirectory</li>
 139  
      * <li>filterPatterns</li>
 140  
      * <li>filterClass</li>
 141  
      * <li>pollingFrequency</li>
 142  
      * </ul>
 143  
      */
 144  
     public UMOMessageReceiver createReceiver(UMOComponent component, UMOEndpoint endpoint) throws Exception
 145  
     {
 146  8
         String readDir = endpoint.getEndpointURI().getAddress();
 147  8
         long polling = this.pollingFrequency;
 148  
 
 149  8
         String moveTo = moveToDirectoryName;
 150  8
         String moveToPattern = getMoveToPattern();
 151  
 
 152  8
         Map props = endpoint.getProperties();
 153  8
         if (props != null)
 154  
         {
 155  
             // Override properties on the endpoint for the specific endpoint
 156  8
             String move = (String) props.get(PROPERTY_MOVE_TO_DIRECTORY);
 157  8
             if (move != null)
 158  
             {
 159  0
                 moveTo = move;
 160  
             }
 161  8
             String tempMoveToPattern = (String) props.get(PROPERTY_MOVE_TO_PATTERN);
 162  8
             if (tempMoveToPattern != null)
 163  
             {
 164  0
                 if (logger.isDebugEnabled())
 165  
                 {
 166  0
                     logger.debug("set moveTo Pattern to: " + tempMoveToPattern);
 167  
                 }
 168  0
                 moveToPattern = tempMoveToPattern;
 169  
             }
 170  
 
 171  8
             String tempPolling = (String) props.get(PROPERTY_POLLING_FREQUENCY);
 172  8
             if (tempPolling != null)
 173  
             {
 174  2
                 polling = Long.parseLong(tempPolling);
 175  
             }
 176  
 
 177  8
             if (polling <= 0)
 178  
             {
 179  4
                 polling = DEFAULT_POLLING_FREQUENCY;
 180  
             }
 181  
 
 182  8
             if (logger.isDebugEnabled())
 183  
             {
 184  0
                 logger.debug("set polling frequency to: " + polling);
 185  
             }
 186  8
             String tempFileAge = (String) props.get(PROPERTY_FILE_AGE);
 187  8
             if (tempFileAge != null)
 188  
             {
 189  
                 try
 190  
                 {
 191  0
                     setFileAge(Long.parseLong(tempFileAge));
 192  
                 }
 193  0
                 catch (Exception ex1)
 194  
                 {
 195  0
                     logger.error("Failed to set fileAge", ex1);
 196  0
                 }
 197  
             }
 198  8
             Map srvOverride = (Map) props.get(PROPERTY_SERVICE_OVERRIDE);
 199  8
             if (srvOverride != null) 
 200  
             {
 201  0
                 if (serviceOverrides == null) 
 202  
                 {
 203  0
                     serviceOverrides = new Properties();
 204  
                 }
 205  0
                 serviceOverrides.setProperty(MuleProperties.CONNECTOR_INBOUND_TRANSFORMER,
 206  
                     NoActionTransformer.class.getName());
 207  0
                 serviceOverrides.setProperty(MuleProperties.CONNECTOR_OUTBOUND_TRANSFORMER,
 208  
                     NoActionTransformer.class.getName());
 209  
             }
 210  
         }
 211  
 
 212  
         try
 213  
         {
 214  8
             return serviceDescriptor.createMessageReceiver(this, component, endpoint, new Object[]{readDir,
 215  
                 moveTo, moveToPattern, new Long(polling)});
 216  
 
 217  
         }
 218  0
         catch (Exception e)
 219  
         {
 220  0
             throw new InitialisationException(
 221  
                 CoreMessages.failedToCreateObjectWith("Message Receiver", 
 222  
                     serviceDescriptor.getMessageReceiver()), e, this);
 223  
         }
 224  
     }
 225  
 
 226  
     public String getProtocol()
 227  
     {
 228  150
         return "file";
 229  
     }
 230  
 
 231  
     public FilenameParser getFilenameParser()
 232  
     {
 233  0
         return filenameParser;
 234  
     }
 235  
 
 236  
     public void setFilenameParser(FilenameParser filenameParser)
 237  
     {
 238  0
         this.filenameParser = filenameParser;
 239  0
     }
 240  
 
 241  
     protected void doDispose()
 242  
     {
 243  
         try
 244  
         {
 245  48
             doStop();
 246  
         }
 247  0
         catch (UMOException e)
 248  
         {
 249  0
             logger.error(e.getMessage(), e);
 250  48
         }
 251  48
     }
 252  
 
 253  
 
 254  
     protected void doInitialise() throws InitialisationException
 255  
     {
 256  
         // template method, nothing to do
 257  44
     }
 258  
 
 259  
     protected void doConnect() throws Exception
 260  
     {
 261  
         // template method, nothing to do
 262  30
     }
 263  
 
 264  
     protected void doDisconnect() throws Exception
 265  
     {
 266  
         // template method, nothing to do
 267  30
     }
 268  
 
 269  
     protected void doStart() throws UMOException
 270  
     {
 271  
         // template method, nothing to do
 272  30
     }
 273  
 
 274  
     protected void doStop() throws UMOException
 275  
     {
 276  78
         if (outputStream != null)
 277  
         {
 278  
             try
 279  
             {
 280  0
                 outputStream.close();
 281  
             }
 282  0
             catch (IOException e)
 283  
             {
 284  0
                 logger.warn("Failed to close file output stream on stop: " + e);
 285  0
             }
 286  
         }
 287  78
     }
 288  
 
 289  
     /**
 290  
      * @return Returns the moveToDirectoryName.
 291  
      */
 292  
     public String getMoveToDirectory()
 293  
     {
 294  4
         return moveToDirectoryName;
 295  
     }
 296  
 
 297  
     /**
 298  
      * @param dir The moveToDirectoryName to set.
 299  
      */
 300  
     public void setMoveToDirectory(String dir)
 301  
     {
 302  0
         this.moveToDirectoryName = dir;
 303  0
     }
 304  
 
 305  
     /**
 306  
      * @return Returns the outputAppend.
 307  
      */
 308  
     public boolean isOutputAppend()
 309  
     {
 310  0
         return outputAppend;
 311  
     }
 312  
 
 313  
     /**
 314  
      * @param outputAppend The outputAppend to set.
 315  
      */
 316  
     public void setOutputAppend(boolean outputAppend)
 317  
     {
 318  0
         this.outputAppend = outputAppend;
 319  0
     }
 320  
 
 321  
     /**
 322  
      * @return Returns the outputPattern.
 323  
      */
 324  
     public String getOutputPattern()
 325  
     {
 326  0
         return outputPattern;
 327  
     }
 328  
 
 329  
     /**
 330  
      * @param outputPattern The outputPattern to set.
 331  
      */
 332  
     public void setOutputPattern(String outputPattern)
 333  
     {
 334  0
         this.outputPattern = outputPattern;
 335  0
     }
 336  
 
 337  
     /**
 338  
      * @return Returns the outputStream.
 339  
      */
 340  
     public FileOutputStream getOutputStream()
 341  
     {
 342  0
         return outputStream;
 343  
     }
 344  
 
 345  
     /**
 346  
      * @param outputStream The outputStream to set.
 347  
      */
 348  
     public void setOutputStream(FileOutputStream outputStream)
 349  
     {
 350  0
         this.outputStream = outputStream;
 351  0
     }
 352  
 
 353  
     /**
 354  
      * @return Returns the pollingFrequency.
 355  
      */
 356  
     public long getPollingFrequency()
 357  
     {
 358  0
         return pollingFrequency;
 359  
     }
 360  
 
 361  
     /**
 362  
      * @param pollingFrequency The pollingFrequency to set.
 363  
      */
 364  
     public void setPollingFrequency(long pollingFrequency)
 365  
     {
 366  4
         this.pollingFrequency = pollingFrequency;
 367  4
     }
 368  
 
 369  
     /**
 370  
      * @return Returns the fileAge.
 371  
      */
 372  
     public long getFileAge()
 373  
     {
 374  4
         return fileAge;
 375  
     }
 376  
 
 377  
     public boolean getCheckFileAge()
 378  
     {
 379  8
         return checkFileAge;
 380  
     }
 381  
 
 382  
     /**
 383  
      * @param fileAge The fileAge in milliseconds to set.
 384  
      */
 385  
     public void setFileAge(long fileAge)
 386  
     {
 387  2
         this.fileAge = fileAge;
 388  2
         this.checkFileAge = true;
 389  2
     }
 390  
 
 391  
     /**
 392  
      * @return Returns the writeToDirectory.
 393  
      */
 394  
     public String getWriteToDirectory()
 395  
     {
 396  0
         return writeToDirectoryName;
 397  
     }
 398  
 
 399  
     /**
 400  
      * @param dir The writeToDirectory to set.
 401  
      */
 402  
     public void setWriteToDirectory(String dir) throws IOException
 403  
     {
 404  0
         this.writeToDirectoryName = dir;
 405  0
         if (writeToDirectoryName != null)
 406  
         {
 407  0
             File writeToDirectory = FileUtils.openDirectory((writeToDirectoryName));
 408  0
             if (!(writeToDirectory.canRead()) || !writeToDirectory.canWrite())
 409  
             {
 410  0
                 throw new IOException(
 411  
                     "Error on initialization, Write To directory does not exist or is not read/write");
 412  
             }
 413  
         }
 414  0
     }
 415  
 
 416  
     public boolean isSerialiseObjects()
 417  
     {
 418  0
         return serialiseObjects;
 419  
     }
 420  
 
 421  
     public void setSerialiseObjects(boolean serialiseObjects)
 422  
     {
 423  
         // set serialisable transformers on the connector if this is set
 424  0
         if (serialiseObjects)
 425  
         {
 426  0
             if (serviceOverrides == null)
 427  
             {
 428  0
                 serviceOverrides = new Properties();
 429  
             }
 430  0
             serviceOverrides.setProperty(MuleProperties.CONNECTOR_INBOUND_TRANSFORMER,
 431  
                 ByteArrayToSerializable.class.getName());
 432  0
             serviceOverrides.setProperty(MuleProperties.CONNECTOR_OUTBOUND_TRANSFORMER,
 433  
                 SerializableToByteArray.class.getName());
 434  
         }
 435  
 
 436  0
         this.serialiseObjects = serialiseObjects;
 437  0
     }
 438  
 
 439  
     public boolean isAutoDelete()
 440  
     {
 441  8
         return autoDelete;
 442  
     }
 443  
 
 444  
     public void setAutoDelete(boolean autoDelete)
 445  
     {
 446  6
         this.autoDelete = autoDelete;
 447  6
         if (!autoDelete)
 448  
         {
 449  2
             if (serviceOverrides == null)
 450  
             {
 451  2
                 serviceOverrides = new Properties();
 452  
             }
 453  2
             if (serviceOverrides.getProperty(MuleProperties.CONNECTOR_MESSAGE_ADAPTER) == null)
 454  
             {
 455  2
                 serviceOverrides.setProperty(MuleProperties.CONNECTOR_MESSAGE_ADAPTER,
 456  
                     FileMessageAdapter.class.getName());
 457  
             }
 458  
         }
 459  6
     }
 460  
 
 461  
     public String getMoveToPattern()
 462  
     {
 463  8
         return moveToPattern;
 464  
     }
 465  
 
 466  
     public void setMoveToPattern(String moveToPattern)
 467  
     {
 468  0
         this.moveToPattern = moveToPattern;
 469  0
     }
 470  
 
 471  
     /**
 472  
      * Well get the output stream (if any) for this type of transport. Typically this
 473  
      * will be called only when Streaming is being used on an outbound endpoint
 474  
      *
 475  
      * @param endpoint the endpoint that releates to this Dispatcher
 476  
      * @param message the current message being processed
 477  
      * @return the output stream to use for this request or null if the transport
 478  
      *         does not support streaming
 479  
      * @throws org.mule.umo.UMOException
 480  
      */
 481  
     public OutputStream getOutputStream(UMOImmutableEndpoint endpoint, UMOMessage message)
 482  
         throws UMOException
 483  
     {
 484  0
         String address = endpoint.getEndpointURI().getAddress();
 485  0
         String writeToDirectory = message.getStringProperty(
 486  
             FileConnector.PROPERTY_WRITE_TO_DIRECTORY, null);
 487  0
         if (writeToDirectory == null)
 488  
         {
 489  0
             writeToDirectory = getWriteToDirectory();
 490  
         }
 491  0
         if (writeToDirectory != null)
 492  
         {
 493  0
             address = getFilenameParser().getFilename(message, writeToDirectory);
 494  
         }
 495  
 
 496  
         String filename;
 497  0
         String outPattern = (String)endpoint.getProperty(FileConnector.PROPERTY_OUTPUT_PATTERN);
 498  0
         if (outPattern == null)
 499  
         {
 500  0
             outPattern = message.getStringProperty(FileConnector.PROPERTY_OUTPUT_PATTERN, null);
 501  
         }
 502  0
         if (outPattern == null)
 503  
         {
 504  0
             outPattern = getOutputPattern();
 505  
         }
 506  
         try
 507  
         {
 508  0
             if (outPattern != null)
 509  
             {
 510  0
                 filename = generateFilename(message, outPattern);
 511  
             }
 512  
             else
 513  
             {
 514  0
                 filename = message.getStringProperty(FileConnector.PROPERTY_FILENAME, null);
 515  0
                 if (filename == null)
 516  
                 {
 517  0
                     filename = generateFilename(message, null);
 518  
                 }
 519  
             }
 520  
 
 521  0
             if (filename == null)
 522  
             {
 523  0
                 throw new IOException("Filename is null");
 524  
             }
 525  0
             File file = FileUtils.createFile(address + "/" + filename);
 526  0
             if (logger.isInfoEnabled())
 527  
             {
 528  0
                 logger.info("Writing file to: " + file.getAbsolutePath());
 529  
             }
 530  
 
 531  0
             return new FileOutputStream(file, MapUtils.getBooleanValue(endpoint.getProperties(),
 532  
                 "outputAppend", isOutputAppend()));
 533  
         }
 534  0
         catch (IOException e)
 535  
         {
 536  0
             throw new DispatchException(CoreMessages.streamingFailedNoStream(), message,
 537  
                 endpoint, e);
 538  
         }
 539  
     }
 540  
 
 541  
     private String generateFilename(UMOMessage message, String pattern)
 542  
     {
 543  0
         if (pattern == null)
 544  
         {
 545  0
             pattern = getOutputPattern();
 546  
         }
 547  0
         return getFilenameParser().getFilename(message, pattern);
 548  
     }
 549  
 }