Package org.mule.transport.file

Source Code of org.mule.transport.file.FileConnector

/*
* $Id: FileConnector.java 20813 2010-12-21 11:37:48Z dirk.olmes $
* --------------------------------------------------------------------------------------
* 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.file;

import org.mule.api.MuleContext;
import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.MuleMessage;
import org.mule.api.config.MuleProperties;
import org.mule.api.construct.FlowConstruct;
import org.mule.api.endpoint.InboundEndpoint;
import org.mule.api.endpoint.OutboundEndpoint;
import org.mule.api.lifecycle.CreateException;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.transport.DispatchException;
import org.mule.api.transport.MessageReceiver;
import org.mule.api.transport.MuleMessageFactory;
import org.mule.config.i18n.CoreMessages;
import org.mule.transformer.simple.ByteArrayToSerializable;
import org.mule.transformer.simple.SerializableToByteArray;
import org.mule.transport.AbstractConnector;
import org.mule.transport.file.filters.FilenameWildcardFilter;
import org.mule.util.FileUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* <code>FileConnector</code> is used for setting up listeners on a directory and
* for writing files to a directory. The connecotry provides support for defining
* file output patterns and filters for receiving files.
*/

public class FileConnector extends AbstractConnector
{

    private static Log logger = LogFactory.getLog(FileConnector.class);

    public static final String FILE = "file";
    private static final String DEFAULT_WORK_FILENAME_PATTERN = "#[function:uuid].#[function:systime].#[header:originalFilename]";

    // These are properties that can be overridden on the Receiver by the endpoint declaration
    // inbound only
    public static final String PROPERTY_FILE_AGE = "fileAge";
    public static final String PROPERTY_MOVE_TO_PATTERN = "moveToPattern";
    public static final String PROPERTY_MOVE_TO_DIRECTORY = "moveToDirectory";
    public static final String PROPERTY_READ_FROM_DIRECTORY = "readFromDirectoryName";
    // outbound only
    public static final String PROPERTY_OUTPUT_PATTERN = "outputPattern";

    // message properties
    public static final String PROPERTY_FILENAME = "filename";
    public static final String PROPERTY_ORIGINAL_FILENAME = "originalFilename";
    public static final String PROPERTY_DIRECTORY = "directory";
    public static final String PROPERTY_WRITE_TO_DIRECTORY = "writeToDirectoryName";
    public static final String PROPERTY_FILE_SIZE = "fileSize";
    public static final String PROPERTY_FILE_TIMESTAMP = "timestamp";

    public static final long DEFAULT_POLLING_FREQUENCY = 1000;

    /**
     * Time in milliseconds to poll. On each poll the poll() method is called
     */
    private long pollingFrequency = 0;

    private String moveToPattern = null;

    private String writeToDirectoryName = null;

    private String moveToDirectoryName = null;

    private String workDirectoryName = null;

    private String workFileNamePattern = DEFAULT_WORK_FILENAME_PATTERN;

    private String readFromDirectoryName = null;

    private String outputPattern = null;

    private boolean outputAppend = false;

    private boolean autoDelete = true;

    private boolean checkFileAge = false;

    private long fileAge = 0;

    private FileOutputStream outputStream = null;

    private boolean serialiseObjects = false;

    private boolean streaming = true;

    public FilenameParser filenameParser;

    private boolean recursive = false;

    public FileConnector(MuleContext context)
    {
        super(context);
        filenameParser = new ExpressionFilenameParser();
    }

    @Override
    protected void configureDispatcherPool()
    {
        if (isOutputAppend())
        {
            setMaxDispatchersActive(getDispatcherThreadingProfile().getMaxThreadsActive());
        }
        else
        {
            super.configureDispatcherPool();
        }
    }

    @Override
    public void setMaxDispatchersActive(int value)
    {
        if (isOutputAppend() && value != 1)
        {
            logger.warn("MULE-1773: cannot configure maxDispatchersActive when using outputAppend. New value not set");
        }
        else
        {
            super.setMaxDispatchersActive(value);
        }
    }

    @Override
    protected Object getReceiverKey(FlowConstruct flowConstruct, InboundEndpoint endpoint)
    {
        if (endpoint.getFilter() != null && endpoint.getFilter() instanceof FilenameWildcardFilter)
        {
            return endpoint.getEndpointURI().getAddress() + "/"
                    + ((FilenameWildcardFilter) endpoint.getFilter()).getPattern();
        }
        return endpoint.getEndpointURI().getAddress();
    }

    /**
     * Registers a listener for a particular directory The following properties can
     * be overriden in the endpoint declaration
     * <ul>
     * <li>moveToDirectory</li>
     * <li>filterPatterns</li>
     * <li>filterClass</li>
     * <li>pollingFrequency</li>
     * </ul>
     */
    @Override
    public MessageReceiver createReceiver(FlowConstruct flowConstruct, InboundEndpoint endpoint) throws Exception
    {
        String readDir = endpoint.getEndpointURI().getAddress();
        if (null != getReadFromDirectory())
        {
            readDir = getReadFromDirectory();
        }

        long polling = this.pollingFrequency;

        String moveTo = moveToDirectoryName;
        String moveToPattern = getMoveToPattern();

        Map props = endpoint.getProperties();
        if (props != null)
        {
            // Override properties on the endpoint for the specific endpoint
            String read = (String) props.get(PROPERTY_READ_FROM_DIRECTORY);
            if (read != null)
            {
                readDir = read;
            }
            String move = (String) props.get(PROPERTY_MOVE_TO_DIRECTORY);
            if (move != null)
            {
                moveTo = move;
            }
            String tempMoveToPattern = (String) props.get(PROPERTY_MOVE_TO_PATTERN);
            if (tempMoveToPattern != null)
            {
                if (logger.isDebugEnabled())
                {
                    logger.debug("set moveTo Pattern to: " + tempMoveToPattern);
                }
                moveToPattern = tempMoveToPattern;
            }

            String tempPolling = (String) props.get(PROPERTY_POLLING_FREQUENCY);
            if (tempPolling != null)
            {
                polling = Long.parseLong(tempPolling);
            }

            if (polling <= 0)
            {
                polling = DEFAULT_POLLING_FREQUENCY;
            }

            if (logger.isDebugEnabled())
            {
                logger.debug("set polling frequency to: " + polling);
            }
            String tempFileAge = (String) props.get(PROPERTY_FILE_AGE);
            if (tempFileAge != null)
            {
                try
                {
                    setFileAge(Long.parseLong(tempFileAge));
                }
                catch (Exception ex1)
                {
                    logger.error("Failed to set fileAge", ex1);
                }
            }
        }

        try
        {
            return serviceDescriptor.createMessageReceiver(this, flowConstruct, endpoint, new Object[]{readDir,
                    moveTo, moveToPattern, new Long(polling)});

        }
        catch (Exception e)
        {
            throw new InitialisationException(
                    CoreMessages.failedToCreateObjectWith("Message Receiver",
                            serviceDescriptor), e, this);
        }
    }

    public String getProtocol()
    {
        return FILE;
    }

    public FilenameParser getFilenameParser()
    {
        return filenameParser;
    }

    public void setFilenameParser(FilenameParser filenameParser)
    {
        this.filenameParser = filenameParser;
        if (filenameParser != null)
        {
            filenameParser.setMuleContext(muleContext);
        }
    }

    @Override
    protected void doDispose()
    {
        try
        {
            doStop();
        }
        catch (MuleException e)
        {
            logger.error(e.getMessage(), e);
        }
    }

    @Override
    protected void doInitialise() throws InitialisationException
    {
        if (filenameParser != null)
        {
            filenameParser.setMuleContext(muleContext);
        }

        // MULE-1773: limit the number of dispatchers per endpoint to 1 until
        // there is a proper (Distributed)LockManager in place (MULE-2402).
        // We also override the setter to prevent "wrong" configuration for now.
        if (isOutputAppend())
        {
            super.setMaxDispatchersActive(1);
        }
    }

    @Override
    protected void doConnect() throws Exception
    {
        // template method, nothing to do
    }

    @Override
    protected void doDisconnect() throws Exception
    {
        // template method, nothing to do
    }

    @Override
    protected void doStart() throws MuleException
    {
        // template method, nothing to do
    }

    @Override
    protected void doStop() throws MuleException
    {
        if (outputStream != null)
        {
            try
            {
                outputStream.close();
            }
            catch (IOException e)
            {
                logger.warn("Failed to close file output stream on stop: " + e);
            }
        }
    }

    public String getMoveToDirectory()
    {
        return moveToDirectoryName;
    }

    public void setMoveToDirectory(String dir)
    {
        this.moveToDirectoryName = dir;
    }

    public void setWorkDirectory(String workDirectoryName) throws IOException
    {
        this.workDirectoryName = workDirectoryName;
        if (workDirectoryName != null)
        {
            File workDirectory = FileUtils.openDirectory(workDirectoryName);
            if (!workDirectory.canWrite())
            {
                throw new IOException(
                        "Error on initialization, Work Directory '" + workDirectory +"' is not writeable");
            }
        }
    }

    public String getWorkDirectory()
    {
        return workDirectoryName;
    }

    public void setWorkFileNamePattern(String workFileNamePattern)
    {
        this.workFileNamePattern = workFileNamePattern;
    }

    public String getWorkFileNamePattern()
    {
        return workFileNamePattern;
    }

    public boolean isOutputAppend()
    {
        return outputAppend;
    }

    public void setOutputAppend(boolean outputAppend)
    {
        this.outputAppend = outputAppend;
    }

    public String getOutputPattern()
    {
        return outputPattern;
    }

    public void setOutputPattern(String outputPattern)
    {
        this.outputPattern = outputPattern;
    }

    public FileOutputStream getOutputStream()
    {
        return outputStream;
    }

    public void setOutputStream(FileOutputStream outputStream)
    {
        this.outputStream = outputStream;
    }

    public long getPollingFrequency()
    {
        return pollingFrequency;
    }

    public void setPollingFrequency(long pollingFrequency)
    {
        this.pollingFrequency = pollingFrequency;
    }

    public long getFileAge()
    {
        return fileAge;
    }

    public boolean getCheckFileAge()
    {
        return checkFileAge;
    }

    public void setFileAge(long fileAge)
    {
        this.fileAge = fileAge;
        this.checkFileAge = true;
    }

    public String getWriteToDirectory()
    {
        return writeToDirectoryName;
    }

    public void setWriteToDirectory(String dir) throws IOException
    {
        this.writeToDirectoryName = dir;
        if (writeToDirectoryName != null)
        {
            File writeToDirectory = FileUtils.openDirectory(writeToDirectoryName);
            if (!writeToDirectory.canWrite())
            {
                throw new IOException(
                        "Error on initialization, " + writeToDirectory
                        + " does not exist or is not writeable");
            }
        }
    }

    public String getReadFromDirectory()
    {
        return readFromDirectoryName;
    }

    public void setReadFromDirectory(String dir) throws IOException
    {
        this.readFromDirectoryName = dir;
        if (readFromDirectoryName != null)
        {
            // check if the directory exists/can be read
            FileUtils.openDirectory((readFromDirectoryName));
        }
    }

    public boolean isSerialiseObjects()
    {
        return serialiseObjects;
    }

    public void setSerialiseObjects(boolean serialiseObjects)
    {
        // set serialisable transformers on the connector if this is set
        if (serialiseObjects)
        {
            if (serviceOverrides == null)
            {
                serviceOverrides = new Properties();
            }
            serviceOverrides.setProperty(MuleProperties.CONNECTOR_INBOUND_TRANSFORMER,
                    ByteArrayToSerializable.class.getName());
            serviceOverrides.setProperty(MuleProperties.CONNECTOR_OUTBOUND_TRANSFORMER,
                    SerializableToByteArray.class.getName());
        }

        this.serialiseObjects = serialiseObjects;
    }

    public boolean isAutoDelete()
    {
        return autoDelete;
    }

    public void setAutoDelete(boolean autoDelete)
    {
        this.autoDelete = autoDelete;
    }

    public String getMoveToPattern()
    {
        return moveToPattern;
    }

    public void setMoveToPattern(String moveToPattern)
    {
        this.moveToPattern = moveToPattern;
    }

    /**
     * Well get the output stream (if any) for this type of transport. Typically this
     * will be called only when Streaming is being used on an outbound endpoint
     *
     * @param endpoint the endpoint that releates to this Dispatcher
     * @param event  the current event being processed
     * @return the output stream to use for this request or null if the transport
     *         does not support streaming
     * @throws org.mule.api.MuleException
     */
    @Override
    public OutputStream getOutputStream(OutboundEndpoint endpoint, MuleEvent event) throws MuleException
    {
        MuleMessage message = event.getMessage();
        String address = endpoint.getEndpointURI().getAddress();
        String writeToDirectory = message.getOutboundProperty(FileConnector.PROPERTY_WRITE_TO_DIRECTORY);
        if (writeToDirectory == null)
        {
            writeToDirectory = getWriteToDirectory();
        }
        if (writeToDirectory != null)
        {
            address = getFilenameParser().getFilename(message, writeToDirectory);
        }

        String filename;
        String outPattern = (String) endpoint.getProperty(FileConnector.PROPERTY_OUTPUT_PATTERN);
        if (outPattern == null)
        {
            outPattern = message.getOutboundProperty(FileConnector.PROPERTY_OUTPUT_PATTERN);
        }
        if (outPattern == null)
        {
            outPattern = getOutputPattern();
        }
        try
        {
            if (outPattern != null)
            {
                filename = generateFilename(message, outPattern);
            }
            else
            {
                filename = message.getOutboundProperty(FileConnector.PROPERTY_FILENAME);
                if (filename == null)
                {
                    filename = generateFilename(message, null);
                }
            }

            if (filename == null)
            {
                throw new IOException("Filename is null");
            }
            File file = FileUtils.createFile(address + "/" + filename);
            if (logger.isInfoEnabled())
            {
                logger.info("Writing file to: " + file.getAbsolutePath());
            }

            return new FileOutputStream(file, isOutputAppend());
        }
        catch (IOException e)
        {
            throw new DispatchException(CoreMessages.streamingFailedNoStream(), event, endpoint, e);
        }
    }

    private String generateFilename(MuleMessage message, String pattern)
    {
        if (pattern == null)
        {
            pattern = getOutputPattern();
        }
        return getFilenameParser().getFilename(message, pattern);
    }

    public boolean isStreaming()
    {
        return streaming;
    }

    public void setStreaming(boolean streaming)
    {
        this.streaming = streaming;
    }

    @Override
    public MuleMessageFactory createMuleMessageFactory() throws CreateException
    {
        // See MULE-3209, MULE-3199
        if (isStreaming())
        {
            return new FileMuleMessageFactory(muleContext);
        }
        else
        {
            return super.createMuleMessageFactory();
        }
    }
    public boolean isRecursive()
    {
        return recursive;
    }

    public void setRecursive(boolean recursive)
    {
        this.recursive = recursive;
    }
}
TOP

Related Classes of org.mule.transport.file.FileConnector

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.