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

fun.mike.frontier.alpha.SftpFileTransferClient Maven / Gradle / Ivy

There is a newer version: 0.0.14
Show newest version
package fun.mike.frontier.alpha;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import fun.mike.frontier.impl.alpha.SftpConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static java.util.Objects.isNull;

public class SftpFileTransferClient implements FileTransferClient {
    private static final Logger log = LoggerFactory.getLogger(FtpFileTransferClient.class);

    private final String host;
    private final Integer port;
    private final String username;
    private final String password;
    private final String privateKeyPath;
    private final String publicKeyPath;
    private final byte[] passphrase;

    public SftpFileTransferClient(String host,
            Integer port,
            String username,
            String password,
            String privateKeyPath,
            String publicKeyPath,
            byte[] passphrase) {
        this.host = host;
        this.port = port;
        this.username = username;
        this.password = password;
        this.privateKeyPath = privateKeyPath;
        this.publicKeyPath = publicKeyPath;
        this.passphrase = passphrase;
    }

    public static SftpFileTransferClient withKeys(String host,
            Integer port,
            String username,
            String privateKeyPath,
            String publicKeyPath,
            byte[] passphrase) {
        return new SftpFileTransferClient(host, port, username, null, privateKeyPath, publicKeyPath, null);
    }

    public static SftpFileTransferClient withPassphrase(String host,
            Integer port,
            String username,
            String privateKeyPath,
            String publicKeyPath,
            byte[] passphrase) {
        return new SftpFileTransferClient(host, port, username, null, privateKeyPath, publicKeyPath, passphrase);
    }

    public static SftpFileTransferClient withPassword(String host, Integer port, String username, String password) {
        return new SftpFileTransferClient(host, port, username, password, null, null, null);
    }

    @Override
    public String upload(String source, String dest) throws FileTransferException {
        String locationLabel = getLocationLabel(dest);
        log.debug(String.format("Uploading local file %s to %s.", source, locationLabel));

        try (InputStream is = new FileInputStream(source)) {
            return upload(is, dest);
        } catch (IOException e) {
            String message = String.format("Failed to read file at \"%s\".", source);
            log.warn(message);
            throw new FileTransferException(message, e);
        }
    }

    @Override
    public Optional optionalStream(String path) throws FileTransferException {
        throw new UnsupportedOperationException("Not yet implemented.");
    }

    @Override
    public InputStream stream(String path) throws FileTransferException, MissingFileException {
        throw new UnsupportedOperationException("Not yet implemented.");
    }

    @Override
    public Boolean dirExists(String path) throws FileTransferException {
        String locationLabel = getLocationLabel(path);
        log.debug(String.format("Checking if directory %s exists.",
                                locationLabel));

        SftpConnector con = connect();
        ChannelSftp chan = con.getChannel();

        try {
            SftpATTRS attrs = chan.lstat(path);

            if (attrs.isDir()) {
                return true;
            }

            String message = String.format("%s exists, but is not a directory.",
                                           locationLabel);
            throw new FileTransferException(message);
        } catch (SftpException e) {
            if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
                return false;
            } else {
                String message = String.format("Error asserting if directory %s exists.", locationLabel);
                throw new FileTransferException(message);
            }
        } finally {
            disconnect(con);
        }
    }

    @Override
    public Boolean fileExists(String path) throws FileTransferException {
        String locationLabel = getLocationLabel(path);
        log.debug(String.format("Checking if directory %s exists.",
                                locationLabel));

        SftpConnector con = connect();
        ChannelSftp chan = con.getChannel();

        try {
            SftpATTRS attrs = chan.lstat(path);

            if (attrs.isDir()) {
                String message = String.format("%s exists, but is a directory.",
                                               locationLabel);
                throw new FileTransferException(message);
            }

            return true;
        } catch (SftpException e) {
            if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
                return false;
            } else {
                String message = String.format("Error asserting if file %s exists.", locationLabel);
                throw new FileTransferException(message);
            }
        } finally {
            disconnect(con);
        }
    }

    @Override
    public Optional optionalSlurp(String path) throws FileTransferException, MissingFileException {
        throw new UnsupportedOperationException("Not yet implemented.");
    }

    @Override
    public String slurp(String path) throws FileTransferException, MissingFileException {
        SftpConnector con = connect();
        ChannelSftp chan = con.getChannel();

        try {
            return IO.slurp(chan.get(path));
        } catch (SftpException e) {
            String message = String.format("Failed to retrieve file at path \"%s\".", path);
            log.warn(message);
            throw new FileTransferException(message, e);
        } finally {
            disconnect(con);
        }
    }

    @Override
    public List list(String path) throws FileTransferException {
        throw new UnsupportedOperationException("Not yet implemented.");
    }

    @Override
    public Boolean optionalDownload(String path, String localPath) throws FileTransferException {
        throw new UnsupportedOperationException("Not yet implemented.");
    }

    @Override
    public Optional optionalDownload(String path, OutputStream stream) throws FileTransferException {
        throw new UnsupportedOperationException("Not yet implemented.");
    }

    public void download(String path, String localPath) throws FileTransferException {
        SftpConnector con = connect();
        ChannelSftp chan = con.getChannel();

        try {
            chan.get(path, localPath);
        } catch (SftpException e) {
            String message = String.format("Failed to retrieve file at path \"%s\".", path);
            log.warn(message);
            throw new FileTransferException(message, e);
        } finally {
            disconnect(con);
        }
    }

    @Override
    public OutputStream download(String path, OutputStream stream) throws FileTransferException, MissingFileException {
        throw new UnsupportedOperationException("Not yet implemented.");
    }

    @Override
    public Map downloadAll(Map targets) throws FileTransferException {
        throw new UnsupportedOperationException("Not yet implemented.");
    }

    @Override
    public String upload(InputStream is, String path) throws FileTransferException {
        SftpConnector conn = connect();

        try {
            ChannelSftp chan = conn.getChannel();

            chan.put(is, path);
            log.info("File transferred successfully to host.");
            return path;
        } catch (SftpException e) {
            String message = String.format("Failed to access path \"%s\".", path);
            log.warn(message);
            throw new FileTransferException(message, e);
        } finally {
            disconnect(conn);
        }
    }

    @Override
    public void delete(String path) throws FileTransferException {
        SftpConnector conn = connect();
        ChannelSftp chan = conn.getChannel();

        try {
            if (!fileExists(path)) {
                throw fileNotFound(path);
            }

            chan.rm(path);
        } catch (SftpException e) {
            String message = String.format("Failed to retrieve file at path \"%s\".", path);
            log.warn(message);
            throw new FileTransferException(message, e);
        } finally {
            disconnect(conn);
        }
    }

    private SftpConnector connect() {
        try {
            JSch.setLogger(new SimpleJschLogger());
            JSch jsch = new JSch();

            if (privateKeyPath != null) {
                log.debug("Using public key authentication.");
                log.debug("Private key path: " + privateKeyPath);
                log.debug("Public key path: " + publicKeyPath);
                if (isNull(passphrase)) {
                    log.debug("No passphrase given.");
                    jsch.addIdentity(privateKeyPath, publicKeyPath);
                } else {
                    log.debug("Using given passphrase.");
                    jsch.addIdentity(privateKeyPath, publicKeyPath, passphrase);
                }
            }

            Session session = jsch.getSession(this.username, this.host, this.port);
            if (this.password != null) {
                log.debug("Using password.");
                session.setPassword(this.password);
            }

            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();
            ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
            channelSftp.connect();
            return new SftpConnector(session, channelSftp);
        } catch (JSchException e) {
            String message = "Jsch failed to set up connection.";
            log.warn(message);
            throw new FileTransferException(message, e);
        }
    }

    private void disconnect(SftpConnector conn) {
        conn.getSession().disconnect();
        conn.getChannel().disconnect();
    }

    private String getLocationLabel(String path) {
        return String.format("%s:%s", getHostLabel(), path);
    }

    private String getHostLabel() {
        if (port == 21) {
            return host;
        }
        return String.format("%s:%d", host, port);
    }

    private MissingFileException fileNotFound(String path) {
        String locationLabel = getLocationLabel(path);
        String message = String.format("File %s not found.", path);
        return new MissingFileException(message);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy