org.springframework.integration.ftp.session.AbstractFtpSessionFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.integration.ftp.session.AbstractFtpSessionFactory.java

Source

/*
 * Copyright 2002-2019 the original author or authors.
 *
 * 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
 *
 *      https://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 org.springframework.integration.ftp.session;

import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTP;
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.ftp.FTPReply;

import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.messaging.MessagingException;
import org.springframework.util.Assert;

/**
 * Base class for FTP SessionFactory implementations.
 *
 * @author Iwein Fuld
 * @author Mark Fisher
 * @author Oleg Zhurakousky
 * @since 2.0
 */
public abstract class AbstractFtpSessionFactory<T extends FTPClient> implements SessionFactory<FTPFile> {

    protected final Log logger = LogFactory.getLog(this.getClass()); // NOSONAR

    private FTPClientConfig config;

    private String username;

    private String host;

    private String password;

    private int port = FTP.DEFAULT_PORT;

    private int bufferSize = 2048; //see https://issues.apache.org/jira/browse/NET-207

    private int clientMode = FTPClient.ACTIVE_LOCAL_DATA_CONNECTION_MODE;

    private int fileType = FTP.BINARY_FILE_TYPE;

    private String controlEncoding = FTP.DEFAULT_CONTROL_ENCODING;

    private Integer connectTimeout;

    private Integer defaultTimeout;

    private Integer dataTimeout;

    /**
     * File types defined by {@link org.apache.commons.net.ftp.FTP} constants:
     * <ul>
     * <li>{@link org.apache.commons.net.ftp.FTP#ASCII_FILE_TYPE}</li>
     * <li>{@link org.apache.commons.net.ftp.FTP#EBCDIC_FILE_TYPE}</li>
     * <li>{@link org.apache.commons.net.ftp.FTP#BINARY_FILE_TYPE} (DEFAULT)</li>
     * <li>{@link org.apache.commons.net.ftp.FTP#LOCAL_FILE_TYPE}</li>
     * </ul>
     * @param fileType The file type.
     */
    public void setFileType(int fileType) {
        this.fileType = fileType;
    }

    public void setControlEncoding(String controlEncoding) {
        Assert.hasText(controlEncoding, "'controlEncoding' must not be empty");
        this.controlEncoding = controlEncoding;
    }

    public void setConfig(FTPClientConfig config) {
        Assert.notNull(config, "'config' must not be null");
        this.config = config;
    }

    public void setBufferSize(int bufferSize) {
        this.bufferSize = bufferSize;
    }

    public void setHost(String host) {
        Assert.hasText(host, "'host' must not be empty");
        this.host = host;
    }

    public void setPort(int port) {
        Assert.isTrue(port > 0, "Port number should be > 0");
        this.port = port;
    }

    public void setUsername(String user) {
        Assert.hasText(user, "'user' should be a nonempty string");
        this.username = user;
    }

    public void setPassword(String pass) {
        Assert.notNull(pass, "password should not be null");
        this.password = pass;
    }

    /**
     * ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0 <br>
     * A constant indicating the FTP session is expecting all transfers
     * to occur between the client (local) and server and that the server
     * should connect to the client's data port to initiate a data transfer.
     * This is the default data connection mode when and FTPClient instance
     * is created.
     * PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2 <br>
     * A constant indicating the FTP session is expecting all transfers
     * to occur between the client (local) and server and that the server
     * is in passive mode, requiring the client to connect to the
     * server's data port to initiate a transfer.
     *
     * @param clientMode The client mode.
     */
    public void setClientMode(int clientMode) {
        Assert.isTrue(
                clientMode == FTPClient.ACTIVE_LOCAL_DATA_CONNECTION_MODE
                        || clientMode == FTPClient.PASSIVE_LOCAL_DATA_CONNECTION_MODE,
                "Only local modes are supported. Was: " + clientMode);
        this.clientMode = clientMode;
    }

    /**
     * Set the connect timeout for the socket.
     * @param connectTimeout the timeout
     */
    public void setConnectTimeout(int connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    /**
     * Set the (socket option) timeout on the command socket.
     * @param defaultTimeout the timeout.
     */
    public void setDefaultTimeout(int defaultTimeout) {
        this.defaultTimeout = defaultTimeout;
    }

    /**
     * Set the (socket option) timeout on the data connection.
     * @param dataTimeout the timeout.
     */
    public void setDataTimeout(int dataTimeout) {
        this.dataTimeout = dataTimeout;
    }

    @Override
    public FtpSession getSession() {
        try {
            return new FtpSession(this.createClient());
        } catch (Exception e) {
            throw new IllegalStateException("failed to create FTPClient", e);
        }
    }

    private T createClient() throws IOException {
        final T client = this.createClientInstance();
        Assert.notNull(client, "client must not be null");
        client.configure(this.config);
        Assert.hasText(this.username, "username is required");
        if (this.connectTimeout != null) {
            client.setConnectTimeout(this.connectTimeout);
        }
        if (this.defaultTimeout != null) {
            client.setDefaultTimeout(this.defaultTimeout);
        }
        if (this.dataTimeout != null) {
            client.setDataTimeout(this.dataTimeout);
        }
        client.setControlEncoding(this.controlEncoding);

        this.postProcessClientBeforeConnect(client);

        // Connect
        client.connect(this.host, this.port);

        if (!FTPReply.isPositiveCompletion(client.getReplyCode())) {
            throw new MessagingException("Connecting to server [" + this.host + ":" + this.port
                    + "] failed. Please check the connection.");
        }
        this.logger.debug("Connected to server [" + this.host + ":" + this.port + "]");

        // Login
        if (!client.login(this.username, this.password)) {
            throw new IllegalStateException(
                    "Login failed. The response from the server is: " + client.getReplyString());
        }

        this.postProcessClientAfterConnect(client);

        this.updateClientMode(client);
        client.setFileType(this.fileType);
        client.setBufferSize(this.bufferSize);
        return client;
    }

    /**
     * Sets the mode of the connection. Only local modes are supported.
     */
    private void updateClientMode(FTPClient client) {
        switch (this.clientMode) {
        case FTPClient.ACTIVE_LOCAL_DATA_CONNECTION_MODE:
            client.enterLocalActiveMode();
            break;
        case FTPClient.PASSIVE_LOCAL_DATA_CONNECTION_MODE:
            client.enterLocalPassiveMode();
            break;
        default:
            break;
        }
    }

    protected abstract T createClientInstance();

    /**
     * Will handle additional initialization after client.connect() method was invoked,
     * but before any action on the client has been taken
     *
     * @param t The client.
     * @throws IOException Any IOException
     */
    protected void postProcessClientAfterConnect(T t) throws IOException {
        // NOOP
    }

    /**
     * Will handle additional initialization before client.connect() method was invoked.
     *
     * @param client The client.
     * @throws IOException Any IOException.
     */
    protected void postProcessClientBeforeConnect(T client) throws IOException {
        // NOOP
    }

}