/*
* $Id: FtpMessageRequester.java 21434 2011-03-03 17:23:37Z svacas $
* --------------------------------------------------------------------------------------
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
*
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.transport.ftp;
import org.mule.api.MuleMessage;
import org.mule.api.endpoint.EndpointURI;
import org.mule.api.endpoint.InboundEndpoint;
import org.mule.api.lifecycle.CreateException;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.transport.AbstractMessageRequester;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPListParseEngine;
import org.apache.commons.net.ftp.FTPReply;
public class FtpMessageRequester extends AbstractMessageRequester
{
private final static int FTP_LIST_PAGE_SIZE = 25;
protected final FtpConnector connector;
public FtpMessageRequester(InboundEndpoint endpoint)
{
super(endpoint);
this.connector = (FtpConnector) endpoint.getConnector();
}
@Override
protected void doDispose()
{
// no op
}
@Override
protected void doConnect() throws Exception
{
// no op
}
@Override
protected void doDisconnect() throws Exception
{
try
{
EndpointURI uri = endpoint.getEndpointURI();
FTPClient client = connector.getFtp(uri);
connector.destroyFtp(uri, client);
}
catch (Exception e)
{
// pool may be closed
}
}
/**
* Make a specific request to the underlying transport
*
* @param timeout The maximum time the operation should block before returning.
* The call should return immediately if there is data available. If
* no data becomes available before the timeout elapses, null will be
* returned.
* @return The result of the request wrapped in a MuleMessage object. <code>null</code> will be
* returned if no data was avaialable
* @throws Exception if the call to the underlying protocol cuases an exception
*/
@Override
protected MuleMessage doRequest(long timeout) throws Exception
{
FTPClient client = null;
try
{
client = connector.createFtpClient(endpoint);
FTPFile fileToProcess = findFileToProcess(client);
if (fileToProcess == null)
{
return null;
}
fileToProcess = prepareFile(client, fileToProcess);
FtpMuleMessageFactory messageFactory = createMuleMessageFactory(client);
return messageFactory.create(fileToProcess, endpoint.getEncoding());
}
finally
{
connector.releaseFtp(endpoint.getEndpointURI(), client);
}
}
@Override
protected void initializeMessageFactory() throws InitialisationException
{
// Do not initialize the muleMessageFactory instance variable of our super class as
// we're creating MuleMessageFactory instances per request.
// See createMuleMessageFactory(FTPClient) below.
}
protected FtpMuleMessageFactory createMuleMessageFactory(FTPClient client) throws CreateException
{
FtpMuleMessageFactory factory = (FtpMuleMessageFactory) createMuleMessageFactory();
// We might want to use isStreaming from connector, but for now maintain existing behaviour.
factory.setStreaming(false);
factory.setFtpClient(client);
return factory;
}
protected FTPFile prepareFile(FTPClient client, FTPFile file) throws IOException
{
return file;
}
protected FTPFile findFileToProcess(FTPClient client) throws Exception
{
FTPListParseEngine engine = client.initiateListParsing();
FTPFile[] files = null;
while (engine.hasNext())
{
files = engine.getNext(FTP_LIST_PAGE_SIZE);
if (files == null)
{
break;
}
FilenameFilter filenameFilter = getFilenameFilter();
for (int i = 0; i < files.length; i++)
{
FTPFile file = files[i];
if (file.isFile())
{
if (filenameFilter.accept(null, file.getName()))
{
if (connector.validateFile(file))
{
// only read the first one
return file;
}
}
}
}
}
if (!FTPReply.isPositiveCompletion(client.getReplyCode()))
{
throw new IOException("Ftp error: " + client.getReplyCode());
}
return null;
}
protected FTPFile[] listFiles(FTPClient client) throws IOException
{
// no longer used, only kept to preserve the class protected API
return null;
}
protected FilenameFilter getFilenameFilter()
{
if (endpoint.getFilter() instanceof FilenameFilter)
{
return (FilenameFilter) endpoint.getFilter();
}
return new AcceptAllFilenameFilter();
}
private static class AcceptAllFilenameFilter implements FilenameFilter
{
public AcceptAllFilenameFilter()
{
super();
}
public boolean accept(File dir, String name)
{
return true;
}
}
}