uk.trainwatch.io.ftp.DefaultFTPClient.java Source code

Java tutorial

Introduction

Here is the source code for uk.trainwatch.io.ftp.DefaultFTPClient.java

Source

/*
 * Copyright 2015 peter.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package uk.trainwatch.io.ftp;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.ConnectException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPFileFilter;
import org.apache.commons.net.ftp.FTPHTTPClient;
import org.apache.commons.net.ftp.FTPReply;
import uk.trainwatch.io.IOConsumer;
import uk.trainwatch.io.IOPredicate;
import uk.trainwatch.util.WriterConsumer;

/**
 *
 * @author peter
 */
public class DefaultFTPClient implements uk.trainwatch.io.ftp.FTPClient {

    private final IOConsumer<DefaultFTPClient> connect;
    private final IOPredicate<DefaultFTPClient> login;
    private final FTPClient ftp;
    private final boolean useEpsvWithIPv4;
    private final boolean localActive;
    private final boolean binaryTransfer;
    private final boolean debuggingEnabled;
    private final Map<String, Object> attributes;
    private boolean loggedIn;
    private WriterConsumer writer;

    DefaultFTPClient(FTPClientBuilder builder) {
        this.attributes = builder.attributes;

        this.useEpsvWithIPv4 = builder.useEpsvWithIPv4;
        this.localActive = builder.localActive;
        this.binaryTransfer = builder.binaryTransfer;

        this.debuggingEnabled = builder.debuggingEnabled && builder.consumer != null;

        if (builder.proxy == null) {
            ftp = new FTPClient();
        } else if (builder.proxyUser == null) {
            ftp = new FTPHTTPClient(builder.proxy, builder.proxyPort);
        } else {
            ftp = new FTPHTTPClient(builder.proxy, builder.proxyPort, builder.proxyUser, builder.proxyPass);
        }

        if (builder.keepAliveTimeout >= 0) {
            ftp.setControlKeepAliveTimeout(builder.keepAliveTimeout);
        }

        if (builder.controlKeepAliveReplyTimeout >= 0) {
            ftp.setControlKeepAliveReplyTimeout(builder.controlKeepAliveReplyTimeout);
        }

        ftp.setListHiddenFiles(builder.listHiddenFiles);

        if (builder.consumer != null) {
            // Don't log blank lines
            writer = new WriterConsumer(builder.consumer, true);

            if (builder.printCommands) {
                // suppress login details
                ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(writer), true));
            }
        }

        connect = builder.connect;
        login = builder.login;
    }

    public FTPClient getDelegate() {
        return ftp;
    }

    @Override
    public void close() throws IOException {
        try {
            if (ftp.isConnected()) {
                try {
                    if (loggedIn) {
                        ftp.logout();
                    }
                } finally {
                    loggedIn = false;

                    ftp.disconnect();
                }
            }
        } finally {
            if (writer != null) {
                writer.close();
                writer = null;
            }
        }
    }

    @Override
    public void log(String msg) {
        if (writer != null) {
            writer.println(msg);
        }
    }

    @Override
    public void log(Supplier<String> msg) {
        if (writer != null) {
            writer.println(msg.get());
        }
    }

    private void debug(Supplier<String> msg) {
        if (debuggingEnabled) {
            log(msg);
        }
    }

    @Override
    public void connect() throws IOException {
        if (ftp.isConnected()) {
            return;
        }

        debug(() -> "Connecting...");

        connect.accept(this);

        // After connection attempt, you should check the reply code to verifysuccess.
        if (FTPReply.isPositiveCompletion(ftp.getReplyCode())) {
            debug(() -> "Connected");
        } else {
            debug(() -> "Connection refused");
            throw new ConnectException("Connection refused");
        }
    }

    @Override
    public boolean isConnected() {
        return ftp.isConnected();
    }

    @Override
    public void login() throws IOException {
        if (loggedIn) {
            return;
        }

        if (!login.test(this)) {
            throw new ConnectException("Login failed");
        }

        String systemType = ftp.getSystemType();
        debug(() -> "Remote system is " + systemType);

        if (binaryTransfer) {
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
        } else {
            // in theory this should not be necessary as servers should default to ASCII but they don't all do so - see NET-500
            ftp.setFileType(FTP.ASCII_FILE_TYPE);
        }

        // Use passive mode as default because most of us are
        // behind firewalls these days.
        if (localActive) {
            ftp.enterLocalActiveMode();
        } else {
            ftp.enterLocalPassiveMode();
        }

        ftp.setUseEPSVwithIPv4(useEpsvWithIPv4);

        loggedIn = true;
    }

    @Override
    public boolean isLoggedIn() {
        return loggedIn;
    }

    @Override
    public boolean changeWorkingDirectory(String pathname) throws IOException {
        return ftp.changeWorkingDirectory(pathname);
    }

    @Override
    public boolean changeToParentDirectory() throws IOException {
        return ftp.changeToParentDirectory();
    }

    @Override
    public boolean appendFile(String remote, InputStream local) throws IOException {
        return ftp.appendFile(remote, local);
    }

    @Override
    public OutputStream appendFileStream(String remote) throws IOException {
        return ftp.appendFileStream(remote);
    }

    @Override
    public Writer appendWriter(String remote) throws IOException {
        return new OutputStreamWriter(appendFileStream(remote));
    }

    @Override
    public boolean store(String remote, InputStream local) throws IOException {
        return ftp.storeFile(remote, local);
    }

    @Override
    public OutputStream storeOutputStream(String remote) throws IOException {
        return ftp.storeFileStream(remote);
    }

    @Override
    public Writer storeWriter(String remote) throws IOException {
        return new OutputStreamWriter(storeOutputStream(remote));
    }

    @Override
    public boolean completePendingCommand() throws IOException {
        return ftp.completePendingCommand();
    }

    @Override
    public boolean retrieveFile(String remote, OutputStream local) throws IOException {
        return ftp.retrieveFile(remote, local);
    }

    @Override
    public InputStream retrieveFileStream(String remote) throws IOException {
        return ftp.retrieveFileStream(remote);
    }

    @Override
    public Reader retrieveReader(String remote) throws IOException {
        return new InputStreamReader(retrieveFileStream(remote));
    }

    @Override
    public FTPFile mlistFile(String pathname) throws IOException {
        return ftp.mlistFile(pathname);
    }

    @Override
    public Collection<FTPFile> mlistDir() throws IOException {
        return Arrays.asList(ftp.mlistDir());
    }

    @Override
    public Collection<FTPFile> mlistDir(String pathname) throws IOException {
        return Arrays.asList(ftp.mlistDir(pathname));
    }

    @Override
    public Collection<FTPFile> mlistDir(String pathname, FTPFileFilter filter) throws IOException {
        return Arrays.asList(ftp.mlistDir(pathname, filter));
    }

    @Override
    public boolean deleteFile(String pathname) throws IOException {
        return ftp.deleteFile(pathname);
    }

    @Override
    public boolean makeDirectory(String pathname) throws IOException {
        return ftp.makeDirectory(pathname);
    }

    @Override
    public String printWorkingDirectory() throws IOException {
        return ftp.printWorkingDirectory();
    }

    @Override
    public Collection<FTPFile> listFiles(String pathname) throws IOException {
        return Arrays.asList(ftp.listFiles(pathname));
    }

    @Override
    public Collection<FTPFile> listFiles() throws IOException {
        return Arrays.asList(ftp.listFiles());
    }

    @Override
    public Collection<FTPFile> listFiles(String pathname, FTPFileFilter filter) throws IOException {
        return Arrays.asList(ftp.listFiles(pathname, filter));
    }

    @Override
    public Collection<FTPFile> listDirectories() throws IOException {
        return Arrays.asList(ftp.listDirectories());
    }

    @Override
    public Collection<FTPFile> listDirectories(String parent) throws IOException {
        return Arrays.asList(ftp.listDirectories(parent));
    }

    @Override
    public Collection<String> listNames(String pathname) throws IOException {
        return Arrays.asList(ftp.listNames(pathname));
    }

    @Override
    public Collection<String> listNames() throws IOException {
        return Arrays.asList(ftp.listNames());
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T getAttribute(String n) throws IOException {
        return (T) attributes.get(n);
    }

    @Override
    public void setAttribute(String n, Object v) throws IOException {
        attributes.put(n, v);
    }

    @Override
    public boolean isAttributePresent(String n) throws IOException {
        return attributes.containsKey(n);
    }

}