net.seedboxer.camel.component.file.remote.ftp2.Ftp2Operations.java Source code

Java tutorial

Introduction

Here is the source code for net.seedboxer.camel.component.file.remote.ftp2.Ftp2Operations.java

Source

/*******************************************************************************
 * Ftp2Operations.java
 * 
 * Copyright (c) 2012 SeedBoxer Team.
 * 
 * This file is part of SeedBoxer.
 * 
 * SeedBoxer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * SeedBoxer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with SeedBoxer.  If not, see <http ://www.gnu.org/licenses/>.
 ******************************************************************************/
package net.seedboxer.camel.component.file.remote.ftp2;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import net.seedboxer.camel.component.file.remote.TransferListener;

import org.apache.camel.Exchange;
import org.apache.camel.InvalidPayloadException;
import org.apache.camel.component.file.GenericFileExist;
import org.apache.camel.component.file.GenericFileOperationFailedException;
import org.apache.camel.component.file.remote.FtpOperations;
import org.apache.camel.component.file.remote.RemoteFileConfiguration;
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.IOHelper;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.io.CopyStreamEvent;
import org.apache.commons.net.io.CopyStreamException;
import org.apache.commons.net.io.CopyStreamListener;

import com.google.common.io.Files;

/**
 * @author Jorge Davison (jdavisonc)
 *
 */
public class Ftp2Operations extends FtpOperations {

    private final FileFilter directoryFileFilter = new DirectoryFileFilter();

    private final FileFilter normalFileFilter = new NormalFileFilter();

    public Ftp2Operations(FTPClient client, FTPClientConfig clientConfig) {
        super(client, clientConfig);
    }

    private class TransferStreamListener implements CopyStreamListener {

        private String source;

        TransferListener transferListener;

        public TransferStreamListener(TransferListener transferListener) {
            this.transferListener = transferListener;
        }

        public void setSource(String source) {
            this.source = source;
        }

        @Override
        public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, long streamSize) {
            transferListener.bytesTransfered(source, bytesTransferred);
        }

        @Override
        public void bytesTransferred(CopyStreamEvent event) {
            transferListener.bytesTransfered(source, event.getBytesTransferred());
        }
    };

    @SuppressWarnings("rawtypes")
    @Override
    public boolean connect(RemoteFileConfiguration configuration) throws GenericFileOperationFailedException {
        boolean res = super.connect(configuration);

        final TransferListener transferListener = ((Ftp2Endpoint) endpoint).getConfiguration()
                .getTransferListener();
        client.setCopyStreamListener(new TransferStreamListener(transferListener));
        return res;
    }

    @Override
    public boolean storeFile(String name, Exchange exchange) throws GenericFileOperationFailedException {
        // must normalize name first
        name = endpoint.getConfiguration().normalizePath(name);

        log.trace("storeFile({})", name);

        boolean answer = false;
        String currentDir = null;
        String path = FileUtil.onlyPath(name);
        String targetName = name;

        try {
            if (path != null && endpoint.getConfiguration().isStepwise()) {
                // must remember current dir so we stay in that directory after the write
                currentDir = getCurrentDirectory();

                // change to path of name
                changeCurrentDirectory(path);

                // the target name should be without path, as we have changed directory
                targetName = FileUtil.stripPath(name);
            }

            // store the file
            answer = doStoreFile(name, targetName, exchange);
        } finally {
            // change back to current directory if we changed directory
            if (currentDir != null) {
                changeCurrentDirectory(currentDir);
            }
        }

        return answer;
    }

    private void setSourceCopyStreamListener(String source) {
        CopyStreamListener copyStreamListener = client.getCopyStreamListener();
        ((TransferStreamListener) copyStreamListener).setSource(source);
    }

    private boolean doStoreFile(String name, String targetName, Exchange exchange)
            throws GenericFileOperationFailedException {
        log.trace("doStoreFile({})", targetName);

        setSourceCopyStreamListener(targetName);

        // if an existing file already exists what should we do?
        if (endpoint.getFileExist() == GenericFileExist.Ignore
                || endpoint.getFileExist() == GenericFileExist.Fail) {
            boolean existFile = existsFile(targetName);
            if (existFile && endpoint.getFileExist() == GenericFileExist.Ignore) {
                // ignore but indicate that the file was written
                log.trace("An existing file already exists: {}. Ignore and do not override it.", name);
                return true;
            } else if (existFile && endpoint.getFileExist() == GenericFileExist.Fail) {
                throw new GenericFileOperationFailedException(
                        "File already exist: " + name + ". Cannot write new file.");
            }
        }

        try {

            Object body = exchange.getIn().getMandatoryBody();
            if (body instanceof InputStream) {
                return doStoreFileFromIS(name, targetName, (InputStream) body);
            } else if (body instanceof File) {
                return doStoreFileFromFile(name, targetName, (File) body);
            } else {
                throw new InvalidPayloadException(exchange, InputStream.class);
            }

        } catch (IOException e) {
            throw new GenericFileOperationFailedException(client.getReplyCode(), client.getReplyString(),
                    e.getMessage(), e);
        } catch (InvalidPayloadException e) {
            throw new GenericFileOperationFailedException("Cannot store file: " + name, e);
        }
    }

    private boolean doStoreFileFromIS(String name, String targetName, InputStream is) throws IOException {
        try {
            if (endpoint.getFileExist() == GenericFileExist.Append && existsFile(targetName)) {
                // Append + Resume
                log.trace("Client resumeFile: {}", targetName);
                return resume(targetName, is);
            } else {
                log.trace("Client storeFile: {}", targetName);
                return client.storeFile(targetName, is);
            }
        } finally {
            IOHelper.close(is, "store: " + name, log);
        }
    }

    private boolean resume(String targetName, InputStream is) throws IOException {
        Long size = getSize(targetName);

        // Set the offset
        client.setRestartOffset(size);
        // Create stream and skip first SIZE bytes
        is.skip(size);

        try {
            OutputStream outs = client.storeFileStream(targetName);
            if (outs != null) {
                try {
                    copyStream(is, outs, client.getBufferSize(), CopyStreamEvent.UNKNOWN_STREAM_SIZE,
                            client.getCopyStreamListener());
                } finally {
                    outs.close();
                }
            }
        } finally {
            is.close();
        }

        return client.completePendingCommand();
    }

    protected Long getSize(String targetName) {
        List<FTPFile> listFiles = listFiles();
        for (FTPFile ftpFile : listFiles) {
            if (targetName.equals(ftpFile.getName())) {
                return ftpFile.getSize();
            }
        }
        return null;
    }

    private void copyStream(InputStream source, OutputStream dest, int bufferSize, long streamSize,
            CopyStreamListener listener) throws CopyStreamException {
        int bytes;
        long total;
        byte[] buffer;

        buffer = new byte[bufferSize];
        total = 0;

        try {
            while ((bytes = source.read(buffer)) != -1) {
                if (bytes == 0) {
                    bytes = source.read();
                    if (bytes < 0) {
                        break;
                    }
                    dest.write(bytes);
                    dest.flush();
                    ++total;
                    if (listener != null) {
                        listener.bytesTransferred(total, 1, streamSize);
                    }
                    continue;
                }

                dest.write(buffer, 0, bytes);
                dest.flush();
                total += bytes;
                if (listener != null) {
                    listener.bytesTransferred(total, bytes, streamSize);
                }
            }
        } catch (IOException e) {
            throw new CopyStreamException("IOException caught while copying.", total, e);
        }
    }

    private boolean doStoreFileFromFile(String name, String targetName, File file) throws IOException {
        if (file.isDirectory()) {
            return doStoreDirectory(file);
        } else {
            return doStoreFileFromIS(name, targetName, getIS(file));
        }
    }

    private boolean doStoreDirectory(File file) throws IOException {
        boolean result = true;
        buildDirectory(file.getName(), false);
        String currentDir = null;
        try {
            currentDir = getCurrentDirectory();
            changeCurrentDirectory(file.getName());

            // Upload all directories first
            for (File childFile : file.listFiles(directoryFileFilter)) {
                result &= doStoreFileFromFile(childFile.getName(), childFile.getName(), childFile);
            }
            // Upload all files
            for (File childFile : file.listFiles(normalFileFilter)) {
                result &= doStoreFileFromFile(childFile.getName(), childFile.getName(), childFile);
            }

            return result;
        } finally {
            // change back to current directory if we changed directory
            if (currentDir != null) {
                changeCurrentDirectory(currentDir);
            }
        }
    }

    private InputStream getIS(File file) throws IOException {
        return Files.newInputStreamSupplier(file).getInput();
    }

    private class NormalFileFilter implements FileFilter {

        @Override
        public boolean accept(File file) {
            return file.isFile();
        }

    }

    private class DirectoryFileFilter implements FileFilter {

        @Override
        public boolean accept(File file) {
            return file.isDirectory();
        }

    }

}