com.github.fge.ftpfs.io.commonsnetimpl.CommonsNetFtpAgent.java Source code

Java tutorial

Introduction

Here is the source code for com.github.fge.ftpfs.io.commonsnetimpl.CommonsNetFtpAgent.java

Source

/*
 * Copyright (c) 2014, Francis Galiegue (fgaliegue@gmail.com)
 *
 * This software is dual-licensed under:
 *
 * - the Lesser General Public License (LGPL) version 3.0 or, at your option, any
 *   later version;
 * - the Apache Software License (ASL) version 2.0.
 *
 * The text of both licenses is available under the src/resources/ directory of
 * this project (under the names LGPL-3.0.txt and ASL-2.0.txt respectively).
 *
 * Direct link to the sources:
 *
 * - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
 * - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
 */

package com.github.fge.ftpfs.io.commonsnetimpl;

import com.github.fge.ftpfs.io.AbstractFtpAgent;
import com.github.fge.ftpfs.io.FtpAgentQueue;
import com.github.fge.ftpfs.FtpConfiguration;
import com.github.fge.ftpfs.io.FtpFileView;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPConnectionClosedException;
import org.apache.commons.net.ftp.FTPFile;

import javax.annotation.concurrent.NotThreadSafe;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.AccessDeniedException;
import java.nio.file.AccessMode;
import java.nio.file.FileSystemException;
import java.nio.file.NoSuchFileException;
import java.nio.file.NotDirectoryException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

@NotThreadSafe
public final class CommonsNetFtpAgent extends AbstractFtpAgent {
    private final FTPClient ftpClient;

    public CommonsNetFtpAgent(final FtpAgentQueue queue, final FtpConfiguration cfg) {
        super(queue, cfg);
        ftpClient = new FTPClient();
        ftpClient.setAutodetectUTF8(true);
    }

    @Override
    public FtpFileView getFileView(final String name) throws IOException {
        try {
            ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
            final FTPFile[] files = ftpClient.listFiles(name);
            if (files.length == 0)
                throw new NoSuchFileException(name);
            if (files.length == 1)
                return new CommonsNetFtpFileView(files[0]);
            for (final FTPFile file : files)
                if (".".equals(file.getName()))
                    return new CommonsNetFtpFileView(file);
            throw new IllegalStateException();
        } catch (FTPConnectionClosedException e) {
            status = Status.DEAD;
            throw new IOException("service unavailable", e);
        }
    }

    @Override
    public EnumSet<AccessMode> getAccess(final String name) throws IOException {
        try {
            ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
            final FTPFile[] files = ftpClient.listFiles(name);
            if (files.length == 0)
                throw new NoSuchFileException(name);
            if (files.length == 1)
                return calculateAccess(files[0]);
            for (final FTPFile file : files)
                if (".".equals(file.getName()))
                    return calculateAccess(file);
            throw new IllegalStateException();
        } catch (FTPConnectionClosedException e) {
            status = Status.DEAD;
            throw new IOException("service unavailable", e);
        }
    }

    @Override
    public List<String> getDirectoryNames(final String dir) throws IOException {
        try {
            ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
            final FTPFile[] files = ftpClient.listFiles(dir);
            if (files.length == 0)
                throw new NoSuchFileException(dir);
            if (files.length == 1)
                handleFailedDirectoryList(dir, files[0]);
            final List<String> ret = new ArrayList<>(files.length);
            String name;
            for (final FTPFile file : files) {
                name = file.getName();
                if (!(".".equals(name) || "..".equals(name)))
                    ret.add(name);
            }
            return ret;
        } catch (FTPConnectionClosedException e) {
            status = Status.DEAD;
            throw new IOException("service unavailable", e);
        }
    }

    @Override
    protected InputStream openInputStream(final String file) throws IOException {
        try {
            ftpClient.setFileType(FTP.ASCII_FILE_TYPE);
            final FTPFile[] files = ftpClient.listFiles(file);
            if (files.length == 0)
                throw new AccessDeniedException(file);
            if (files.length > 1)
                throw new IOException(file + " is a directory");
            if (files[0].isDirectory())
                throw new AccessDeniedException(file);
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            final InputStream ret = ftpClient.retrieveFileStream(file);
            if (ret == null)
                throw new IOException("cannot open stream to file (server " + "reply " + ftpClient.getReplyCode());
            return ret;
        } catch (FTPConnectionClosedException e) {
            status = Status.DEAD;
            throw new IOException("service unavailable", e);
        }
    }

    @Override
    public void connect() throws IOException {
        if (status == Status.CONNECTED)
            return;
        try {
            ftpClient.connect(cfg.getHostname(), cfg.getPort());
            if (!ftpClient.login(cfg.getUsername(), cfg.getPassword()))
                throw new IOException("cannot login to server (server reply: " + ftpClient.getReplyCode());
        } catch (FTPConnectionClosedException e) {
            status = Status.DEAD;
            throw new IOException("service unavailable", e);
        } catch (IOException e) {
            status = Status.DEAD;
            throw e;
        }
        status = Status.CONNECTED;
    }

    @Override
    public void disconnect() throws IOException {
        ftpClient.disconnect();
    }

    @Override
    public void completeTransfer() throws IOException {
        if (!ftpClient.completePendingCommand())
            throw new IOException("non finalized read from FTP server");
    }

    private static EnumSet<AccessMode> calculateAccess(final FTPFile file) {
        final EnumSet<AccessMode> ret = EnumSet.noneOf(AccessMode.class);
        if (file.hasPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION))
            ret.add(AccessMode.READ);
        if (file.hasPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION))
            ret.add(AccessMode.WRITE);
        if (file.hasPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION))
            ret.add(AccessMode.EXECUTE);
        return ret;
    }

    private static void handleFailedDirectoryList(final String dir, final FTPFile file) throws FileSystemException {
        throw file.isDirectory() ? new AccessDeniedException(dir) : new NotDirectoryException(dir);
    }
}