All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xbib.io.ftp.fs.FTPFileStrategy Maven / Gradle / Ivy

package org.xbib.io.ftp.fs;

import org.xbib.io.ftp.client.FTPFile;
import org.xbib.io.ftp.client.FTPFileFilter;

import java.io.IOException;
import java.nio.file.NoSuchFileException;
import java.nio.file.NotDirectoryException;
import java.util.ArrayList;
import java.util.List;

/**
 * A strategy for handling FTP files in an FTP server specific way.
 * This will help support FTP servers that return the current directory (.) when
 * listing directories, and FTP servers that don't.
 */
abstract class FTPFileStrategy {

    static FTPFileStrategy getInstance(FTPClientPool.Client client) throws IOException {
        FTPFile[] ftpFiles = client.listFiles("/", new FTPFileFilter() {
            @Override
            public boolean accept(FTPFile ftpFile) {
                String fileName = FTPFileSystem.getFileName(ftpFile);
                return FTPFileSystem.CURRENT_DIR.equals(fileName);
            }
        });
        return ftpFiles.length == 0 ? NonUnix.INSTANCE : Unix.INSTANCE;
    }

    abstract List getChildren(FTPClientPool.Client client, FTPPath path) throws IOException;

    abstract FTPFile getFTPFile(FTPClientPool.Client client, FTPPath path) throws IOException;

    abstract FTPFile getLink(FTPClientPool.Client client, FTPFile ftpFile, FTPPath path) throws IOException;

    private static final class Unix extends FTPFileStrategy {

        private static final FTPFileStrategy INSTANCE = new Unix();

        @Override
        List getChildren(FTPClientPool.Client client, FTPPath path) throws IOException {

            FTPFile[] ftpFiles = client.listFiles(path.path());

            if (ftpFiles.length == 0) {
                throw new NoSuchFileException(path.path());
            }
            boolean isDirectory = false;
            List children = new ArrayList<>(ftpFiles.length);
            for (FTPFile ftpFile : ftpFiles) {
                String fileName = FTPFileSystem.getFileName(ftpFile);
                if (FTPFileSystem.CURRENT_DIR.equals(fileName)) {
                    isDirectory = true;
                } else if (!FTPFileSystem.PARENT_DIR.equals(fileName)) {
                    children.add(ftpFile);
                }
            }

            if (!isDirectory) {
                throw new NotDirectoryException(path.path());
            }

            return children;
        }

        @Override
        FTPFile getFTPFile(FTPClientPool.Client client, FTPPath path) throws IOException {
            final String name = path.fileName();

            FTPFile[] ftpFiles = client.listFiles(path.path(), new FTPFileFilter() {
                @Override
                public boolean accept(FTPFile ftpFile) {
                    String fileName = FTPFileSystem.getFileName(ftpFile);
                    return FTPFileSystem.CURRENT_DIR.equals(fileName) || (name != null && name.equals(fileName));
                }
            });
            client.throwIfEmpty(path.path(), ftpFiles);
            if (ftpFiles.length == 1) {
                return ftpFiles[0];
            }
            for (FTPFile ftpFile : ftpFiles) {
                if (FTPFileSystem.CURRENT_DIR.equals(FTPFileSystem.getFileName(ftpFile))) {
                    return ftpFile;
                }
            }
            throw new IllegalStateException();
        }

        @Override
        FTPFile getLink(FTPClientPool.Client client, FTPFile ftpFile, FTPPath path) throws IOException {
            if (ftpFile.getLink() != null) {
                return ftpFile;
            }
            if (ftpFile.isDirectory() && FTPFileSystem.CURRENT_DIR.equals(FTPFileSystem.getFileName(ftpFile))) {
                // The file is returned using getFTPFile, which returns the . (current directory) entry for directories.
                // List the parent (if any) instead.

                final String parentPath = path.toAbsolutePath().parentPath();
                final String name = path.fileName();

                if (parentPath == null) {
                    // path is /, there is no link
                    return null;
                }

                FTPFile[] ftpFiles = client.listFiles(parentPath, new FTPFileFilter() {
                    @Override
                    public boolean accept(FTPFile ftpFile) {
                        return (ftpFile.isDirectory() || ftpFile.isSymbolicLink()) && name.equals(FTPFileSystem.getFileName(ftpFile));
                    }
                });
                client.throwIfEmpty(path.path(), ftpFiles);
                return ftpFiles[0].getLink() == null ? null : ftpFiles[0];
            }
            return null;
        }
    }

    private static final class NonUnix extends FTPFileStrategy {

        private static final FTPFileStrategy INSTANCE = new NonUnix();

        @Override
        List getChildren(FTPClientPool.Client client, FTPPath path) throws IOException {

            FTPFile[] ftpFiles = client.listFiles(path.path());

            boolean isDirectory = false;
            List children = new ArrayList<>(ftpFiles.length);
            for (FTPFile ftpFile : ftpFiles) {
                String fileName = FTPFileSystem.getFileName(ftpFile);
                if (FTPFileSystem.CURRENT_DIR.equals(fileName)) {
                    isDirectory = true;
                } else if (!FTPFileSystem.PARENT_DIR.equals(fileName)) {
                    children.add(ftpFile);
                }
            }

            if (!isDirectory && children.size() <= 1) {
                // either zero or one, check the parent to see if the path exists and is a directory
                FTPPath currentPath = path;
                FTPFile currentFtpFile = getFTPFile(client, currentPath);
                while (currentFtpFile.isSymbolicLink()) {
                    currentPath = path.resolve(currentFtpFile.getLink());
                    currentFtpFile = getFTPFile(client, currentPath);
                }
                if (!currentFtpFile.isDirectory()) {
                    throw new NotDirectoryException(path.path());
                }
            }

            return children;
        }

        @Override
        FTPFile getFTPFile(FTPClientPool.Client client, FTPPath path) throws IOException {
            final String parentPath = path.toAbsolutePath().parentPath();
            final String name = path.fileName();
            if (parentPath == null) {
                // path is /, but that cannot be listed
                FTPFile rootFtpFile = new FTPFile();
                rootFtpFile.setName("/");
                rootFtpFile.setType(FTPFile.DIRECTORY_TYPE);
                return rootFtpFile;
            }
            FTPFile[] ftpFiles = client.listFiles(parentPath,
                    ftpFile -> name != null && name.equals(FTPFileSystem.getFileName(ftpFile)));
            if (ftpFiles.length == 0) {
                throw new NoSuchFileException(path.path());
            }
            if (ftpFiles.length == 1) {
                return ftpFiles[0];
            }
            throw new IllegalStateException();
        }

        @Override
        FTPFile getLink(FTPClientPool.Client client, FTPFile ftpFile, FTPPath path) throws IOException {
            // getFTPFile always returns the entry in the parent, so there's no need to list the parent here.
            return ftpFile.getLink() == null ? null : ftpFile;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy