Coverage Report - org.mule.transport.ftp.FtpMessageReceiver
 
Classes in this File Line Coverage Branch Coverage Complexity
FtpMessageReceiver
0%
0/84
0%
0/42
0
FtpMessageReceiver$1
N/A
N/A
0
FtpMessageReceiver$FtpWork
0%
0/14
N/A
0
 
 1  
 /*
 2  
  * $Id: FtpMessageReceiver.java 19191 2010-08-25 21:05:23Z 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.ftp;
 12  
 
 13  
 import org.mule.api.MuleMessage;
 14  
 import org.mule.api.construct.FlowConstruct;
 15  
 import org.mule.api.endpoint.InboundEndpoint;
 16  
 import org.mule.api.lifecycle.CreateException;
 17  
 import org.mule.api.lifecycle.InitialisationException;
 18  
 import org.mule.api.retry.RetryContext;
 19  
 import org.mule.api.transport.Connector;
 20  
 import org.mule.transport.AbstractPollingMessageReceiver;
 21  
 import org.mule.transport.ConnectException;
 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.net.ftp.FTPClient;
 35  
 import org.apache.commons.net.ftp.FTPFile;
 36  
 import org.apache.commons.net.ftp.FTPReply;
 37  
 
 38  
 public class FtpMessageReceiver extends AbstractPollingMessageReceiver
 39  
 {
 40  
     protected final FtpConnector connector;
 41  
     protected final FilenameFilter filenameFilter;
 42  
 
 43  
     // there's nothing like homegrown pseudo-2PC.. :/
 44  
     // shared state management like this should go into the connector and use
 45  
     // something like commons-tx
 46  0
     protected final Set<String> scheduledFiles = Collections.synchronizedSet(new HashSet<String>());
 47  0
     protected final Set<String> currentFiles = Collections.synchronizedSet(new HashSet<String>());
 48  
 
 49  
     public FtpMessageReceiver(Connector connector,
 50  
                               FlowConstruct flowConstruct,
 51  
                               InboundEndpoint endpoint,
 52  
                               long frequency) throws CreateException
 53  
     {
 54  0
         super(connector, flowConstruct, endpoint);
 55  
 
 56  0
         this.setFrequency(frequency);
 57  
 
 58  0
         this.connector = (FtpConnector) connector;
 59  
 
 60  0
         if (endpoint.getFilter() instanceof FilenameFilter)
 61  
         {
 62  0
             this.filenameFilter = (FilenameFilter) endpoint.getFilter();
 63  
         }
 64  
         else
 65  
         {
 66  0
             this.filenameFilter = null;
 67  
         }
 68  0
     }
 69  
 
 70  
     @Override
 71  
     public void poll() throws Exception
 72  
     {
 73  0
         FTPFile[] files = listFiles();
 74  0
         if (logger.isDebugEnabled())
 75  
         {
 76  0
             logger.debug("Poll encountered " + files.length + " new file(s)");
 77  
         }
 78  
 
 79  0
         synchronized (scheduledFiles)
 80  
         {
 81  0
             for (final FTPFile file : files)
 82  
             {
 83  0
                 final String fileName = file.getName();
 84  
 
 85  0
                 if (!scheduledFiles.contains(fileName) && !currentFiles.contains(fileName))
 86  
                 {
 87  0
                     scheduledFiles.add(fileName);
 88  0
                     getWorkManager().scheduleWork(new FtpWork(fileName, file));
 89  
                 }
 90  
             }
 91  0
         }
 92  0
     }
 93  
 
 94  
     protected FTPFile[] listFiles() throws Exception
 95  
     {
 96  0
         FTPClient client = null;
 97  
         try
 98  
         {
 99  
             try
 100  
             {
 101  0
                 client = connector.createFtpClient(endpoint);
 102  
             }
 103  0
             catch (Exception e)
 104  
             {
 105  0
                 throw new ConnectException(e, this);
 106  0
             }
 107  0
             FTPFile[] files = client.listFiles();
 108  
 
 109  0
             if (!FTPReply.isPositiveCompletion(client.getReplyCode()))
 110  
             {
 111  0
                 throw new IOException("Failed to list files. Ftp error: " + client.getReplyCode());
 112  
             }
 113  
 
 114  0
             if (files == null || files.length == 0)
 115  
             {
 116  0
                 return files;
 117  
             }
 118  
 
 119  0
             List<FTPFile> v = new ArrayList<FTPFile>();
 120  
 
 121  0
             for (FTPFile file : files)
 122  
             {
 123  0
                 if (file.isFile())
 124  
                 {
 125  0
                     if (filenameFilter == null || filenameFilter.accept(null, file.getName()))
 126  
                     {
 127  0
                         v.add(file);
 128  
                     }
 129  
                 }
 130  
             }
 131  
 
 132  0
             return v.toArray(new FTPFile[v.size()]);
 133  
         }
 134  
         finally
 135  
         {
 136  0
             if (client != null)
 137  
             {
 138  0
                 connector.releaseFtp(endpoint.getEndpointURI(), client);
 139  
             }
 140  
         }
 141  
     }
 142  
 
 143  
     protected void processFile(FTPFile file) throws Exception
 144  
     {
 145  0
         FTPClient client = null;
 146  
         try
 147  
         {
 148  0
             if (!connector.validateFile(file))
 149  
             {
 150  
                 return;
 151  
             }
 152  
 
 153  
             try
 154  
             {
 155  0
                 client = connector.createFtpClient(endpoint);
 156  
             }
 157  0
             catch (Exception e)
 158  
             {
 159  0
                 throw new ConnectException(e, this);
 160  0
             }
 161  
 
 162  0
             FtpMuleMessageFactory muleMessageFactory = createMuleMessageFactory(client);
 163  0
             MuleMessage message = muleMessageFactory.create(file, endpoint.getEncoding());
 164  
 
 165  0
             routeMessage(message);
 166  0
             postProcess(client, file, message);
 167  
         }
 168  
         finally
 169  
         {
 170  0
             if (client != null)
 171  
             {
 172  0
                 connector.releaseFtp(endpoint.getEndpointURI(), client);
 173  
             }
 174  
         }
 175  0
     }
 176  
 
 177  
     @Override
 178  
     protected void initializeMessageFactory() throws InitialisationException
 179  
     {
 180  
         // Do not initialize the muleMessageFactory instance variable of our super class as 
 181  
         // we're creating MuleMessageFactory instances per request. 
 182  
         // See createMuleMessageFactory(FTPClient) below.
 183  0
     }
 184  
     
 185  
     protected FtpMuleMessageFactory createMuleMessageFactory(FTPClient client) throws CreateException
 186  
     {
 187  0
         FtpMuleMessageFactory factory = (FtpMuleMessageFactory) createMuleMessageFactory();
 188  0
         factory.setStreaming(connector.isStreaming());
 189  0
         factory.setFtpClient(client);    
 190  
         
 191  0
         return factory;
 192  
     }
 193  
 
 194  
     protected void postProcess(FTPClient client, FTPFile file, MuleMessage message) throws Exception
 195  
     {
 196  0
         if (!client.deleteFile(file.getName()))
 197  
         {
 198  0
             throw new IOException(MessageFormat.format("Failed to delete file {0}. Ftp error: {1}",
 199  
                                                        file.getName(), client.getReplyCode()));
 200  
         }
 201  0
         if (logger.isDebugEnabled())
 202  
         {
 203  0
             logger.debug("Deleted processed file " + file.getName());
 204  
         }
 205  
         
 206  0
         if (connector.isStreaming())
 207  
         {
 208  0
             if (!client.completePendingCommand())
 209  
             {
 210  0
                 throw new IOException(MessageFormat.format("Failed to complete a pending command. Retrieveing file {0}. Ftp error: {1}",
 211  
                                                            file.getName(), client.getReplyCode()));
 212  
             }
 213  
         }
 214  0
     }
 215  
     
 216  
     @Override
 217  
     protected void doConnect() throws Exception
 218  
     {
 219  
         // no op
 220  0
     }
 221  
 
 222  
     @Override
 223  
     public RetryContext validateConnection(RetryContext retryContext)
 224  
     {
 225  0
         FTPClient client = null;
 226  
         try
 227  
         {
 228  0
             client = connector.createFtpClient(endpoint);
 229  0
             client.sendNoOp();
 230  0
             client.logout();
 231  0
             client.disconnect();
 232  
 
 233  0
             retryContext.setOk();
 234  
         }
 235  0
         catch (Exception ex)
 236  
         {
 237  0
             retryContext.setFailed(ex);
 238  
         }
 239  
         finally
 240  
         {
 241  0
             try
 242  
             {
 243  0
                 if (client != null)
 244  
                 {
 245  0
                     connector.releaseFtp(endpoint.getEndpointURI(), client);
 246  
                 }
 247  
             }
 248  0
             catch (Exception e)
 249  
             {
 250  0
                 if (logger.isDebugEnabled())
 251  
                 {
 252  0
                     logger.debug("Failed to release ftp client " + client, e);
 253  
                 }
 254  0
             }
 255  0
         }
 256  
 
 257  0
         return retryContext;
 258  
     }
 259  
         
 260  
     @Override
 261  
     protected void doDisconnect() throws Exception
 262  
     {
 263  
         // no op
 264  0
     }
 265  
 
 266  
     @Override
 267  
     protected void doDispose()
 268  
     {
 269  
         // template method
 270  0
     }
 271  
 
 272  0
     private final class FtpWork implements Work
 273  
     {
 274  
         private final String name;
 275  
         private final FTPFile file;
 276  
 
 277  
         private FtpWork(String name, FTPFile file)
 278  0
         {
 279  0
             this.name = name;
 280  0
             this.file = file;
 281  0
         }
 282  
 
 283  
         public void run()
 284  
         {
 285  
             try
 286  
             {
 287  0
                 currentFiles.add(name);
 288  0
                 processFile(file);
 289  
             }
 290  0
             catch (Exception e)
 291  
             {
 292  0
                 getConnector().getMuleContext().getExceptionListener().handleException(e);
 293  
             }
 294  
             finally
 295  
             {
 296  0
                 currentFiles.remove(name);
 297  0
                 scheduledFiles.remove(name);
 298  0
             }
 299  0
         }
 300  
 
 301  
         public void release()
 302  
         {
 303  
             // no op
 304  0
         }
 305  
     }
 306  
 
 307  
 }