Package org.mule.transport.ftp

Source Code of org.mule.transport.ftp.FtpMessageReceiver$FtpWork

/*
* $Id: FtpMessageReceiver.java 22033 2011-05-30 17:23:06Z tcarlson $
* --------------------------------------------------------------------------------------
* 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.MessagingException;
import org.mule.api.MuleEvent;
import org.mule.api.MuleMessage;
import org.mule.api.construct.FlowConstruct;
import org.mule.api.endpoint.InboundEndpoint;
import org.mule.api.lifecycle.CreateException;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.retry.RetryContext;
import org.mule.api.transport.Connector;
import org.mule.transport.AbstractPollingMessageReceiver;

import java.io.FilenameFilter;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.resource.spi.work.Work;

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 FtpMessageReceiver extends AbstractPollingMessageReceiver
{
    private final static int FTP_LIST_PAGE_SIZE = 25;
    protected final FtpConnector connector;
    protected final FilenameFilter filenameFilter;

    // there's nothing like homegrown pseudo-2PC.. :/
    // shared state management like this should go into the connector and use
    // something like commons-tx
    protected final Set<String> scheduledFiles = Collections.synchronizedSet(new HashSet<String>());
    protected final Set<String> currentFiles = Collections.synchronizedSet(new HashSet<String>());

    public FtpMessageReceiver(Connector connector,
                              FlowConstruct flowConstruct,
                              InboundEndpoint endpoint,
                              long frequency) throws CreateException
    {
        super(connector, flowConstruct, endpoint);

        this.setFrequency(frequency);

        this.connector = (FtpConnector) connector;

        if (endpoint.getFilter() instanceof FilenameFilter)
        {
            this.filenameFilter = (FilenameFilter) endpoint.getFilter();
        }
        else
        {
            this.filenameFilter = null;
        }
    }

    @Override
    public void poll() throws Exception
    {
        FTPFile[] files = listFiles();
        if (logger.isDebugEnabled())
        {
            logger.debug("Poll encountered " + files.length + " new file(s)");
        }

        synchronized (scheduledFiles)
        {
            for (final FTPFile file : files)
            {
                if (getLifecycleState().isStopping())
                {
                    break;
                }

                final String fileName = file.getName();

                if (!scheduledFiles.contains(fileName) && !currentFiles.contains(fileName))
                {
                    scheduledFiles.add(fileName);
                    getWorkManager().scheduleWork(new FtpWork(fileName, file));
                }
            }
        }
    }

    protected FTPFile[] listFiles() throws Exception
    {
        FTPClient client = null;
        try
        {
            client = connector.createFtpClient(endpoint);
            FTPListParseEngine engine = client.initiateListParsing();
            FTPFile[] files = null;
            List<FTPFile> v = new ArrayList<FTPFile>();
            while (engine.hasNext())
            {
                if (getLifecycleState().isStopping())
                {
                    break;
                }
                files = engine.getNext(FTP_LIST_PAGE_SIZE);
                if (files == null || files.length == 0)
                {
                    return files;
                }
                for (FTPFile file : files)
                {
                    if (file.isFile())
                    {
                        if (filenameFilter == null || filenameFilter.accept(null, file.getName()))
                        {
                            v.add(file);
                        }
                    }
                }
            }

            if (!FTPReply.isPositiveCompletion(client.getReplyCode()))
            {
                throw new IOException("Failed to list files. Ftp error: " + client.getReplyCode());
            }

            return v.toArray(new FTPFile[v.size()]);
        }
        finally
        {
            if (client != null)
            {
                connector.releaseFtp(endpoint.getEndpointURI(), client);
            }
        }
    }

    protected void processFile(FTPFile file) throws Exception
    {
        FTPClient client = null;
        try
        {
            if (!connector.validateFile(file))
            {
                return;
            }

            client = connector.createFtpClient(endpoint);
            FtpMuleMessageFactory muleMessageFactory = createMuleMessageFactory(client);
            MuleMessage message = muleMessageFactory.create(file, endpoint.getEncoding());

            routeMessage(message);
            postProcess(client, file, message);
        }
        finally
        {
            if (client != null)
            {
                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();
        factory.setStreaming(connector.isStreaming());
        factory.setFtpClient(client);   
       
        return factory;
    }

    protected void postProcess(FTPClient client, FTPFile file, MuleMessage message) throws Exception
    {
        if (!client.deleteFile(file.getName()))
        {
            throw new IOException(MessageFormat.format("Failed to delete file {0}. Ftp error: {1}",
                                                       file.getName(), client.getReplyCode()));
        }
        if (logger.isDebugEnabled())
        {
            logger.debug("Deleted processed file " + file.getName());
        }
       
        if (connector.isStreaming())
        {
            if (!client.completePendingCommand())
            {
                throw new IOException(MessageFormat.format("Failed to complete a pending command. Retrieveing file {0}. Ftp error: {1}",
                                                           file.getName(), client.getReplyCode()));
            }
        }
    }
   
    @Override
    protected void doConnect() throws Exception
    {
        // no op
    }

    @Override
    public RetryContext validateConnection(RetryContext retryContext)
    {
        FTPClient client = null;
        try
        {
            client = connector.createFtpClient(endpoint);
            client.sendNoOp();
            client.logout();
            client.disconnect();

            retryContext.setOk();
        }
        catch (Exception ex)
        {
            retryContext.setFailed(ex);
        }
        finally
        {
            try
            {
                if (client != null)
                {
                    connector.releaseFtp(endpoint.getEndpointURI(), client);
                }
            }
            catch (Exception e)
            {
                if (logger.isDebugEnabled())
                {
                    logger.debug("Failed to release ftp client " + client, e);
                }
            }
        }

        return retryContext;
    }
       
    @Override
    protected void doDisconnect() throws Exception
    {
        // no op
    }

    @Override
    protected void doDispose()
    {
        // template method
    }

    private final class FtpWork implements Work
    {
        private final String name;
        private final FTPFile file;

        private FtpWork(String name, FTPFile file)
        {
            this.name = name;
            this.file = file;
        }

        public void run()
        {
            try
            {
                currentFiles.add(name);
                processFile(file);
            }
            catch (Exception e)
            {
                if (e instanceof MessagingException)
                {
                    MuleEvent event = ((MessagingException) e).getEvent();
                    event.getFlowConstruct().getExceptionListener().handleException(e, event);
                }
                else
                {
                    getConnector().getMuleContext().getExceptionListener().handleException(e);
                }
            }
            finally
            {
                currentFiles.remove(name);
                scheduledFiles.remove(name);
            }
        }

        public void release()
        {
            // no op
        }
    }

}
TOP

Related Classes of org.mule.transport.ftp.FtpMessageReceiver$FtpWork

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.