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

com.orion.ftp.client.pool.FtpClientPool Maven / Gradle / Ivy

There is a newer version: 1.0.9
Show newest version
package com.orion.ftp.client.pool;

import com.orion.constant.Const;
import com.orion.ftp.client.FtpInstance;
import com.orion.ftp.client.Ftps;
import com.orion.ftp.client.config.FtpConfig;
import com.orion.utils.Exceptions;
import com.orion.utils.Valid;
import com.orion.utils.io.Streams;
import org.apache.commons.net.ftp.FTPClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * FTP连接池
 *
 * @author Jiahang Li
 * @version 1.0.0
 * @since 2020/3/18 11:19
 */
public class FtpClientPool implements AutoCloseable {

    /**
     * LOG
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(FtpClientPool.class);

    /**
     * 如果池中连接不足是否创建而不是报错
     */
    private boolean emptyCreateTemp;

    /**
     * 入栈超时时间 ms
     */
    private int timeout;

    /**
     * 队列
     */
    private BlockingQueue pool;

    /**
     * 连接工厂
     */
    private FtpClientFactory factory;

    /**
     * 长连接心跳监听
     */
    private FtpClientKeepAlive keepAlive;

    public FtpClientPool(FtpClientFactory factory) {
        this(factory, Const.N_10);
    }

    public FtpClientPool(FtpClientFactory factory, int size) {
        Valid.notNull(factory, "ftp client factory is null");
        this.timeout = Const.MS_S_5;
        this.emptyCreateTemp = false;
        this.factory = factory;
        this.pool = new ArrayBlockingQueue<>(size);
        this.init(size);
    }

    /**
     * 初始化
     *
     * @param maxPoolSize 池内数量
     */
    private void init(int maxPoolSize) {
        try {
            for (int i = 0; i < maxPoolSize; i++) {
                this.addClient();
            }
        } catch (Exception e) {
            throw Exceptions.ftp("init ftp client to pool error", e);
        }
    }

    /**
     * 入栈超时 ms
     *
     * @param timeout timeout ms
     * @return this
     */
    public FtpClientPool timeout(int timeout) {
        this.timeout = timeout;
        return this;
    }

    /**
     * 如果池中连接不足是否创建而不是报错
     *
     * @param emptyCreateTemp 是否创建
     * @return this
     */
    public FtpClientPool emptyCreateTemp(boolean emptyCreateTemp) {
        this.emptyCreateTemp = emptyCreateTemp;
        return this;
    }

    /**
     * 监听keepAlive的连接是否超时
     *
     * @return this
     */
    public FtpClientPool keepAliveListener() {
        // keepAlive 监听
        keepAlive = new FtpClientKeepAlive(this);
        keepAlive.listener(factory.getConfig().getConnTimeout() / 2);
        return this;
    }

    /**
     * 获取一个连接
     *
     * @return 连接
     */
    public synchronized FTPClient getClient() {
        LOGGER.debug("get ftp client with pool");
        try {
            FTPClient client = pool.poll(timeout, TimeUnit.MILLISECONDS);
            if (client == null) {
                if (emptyCreateTemp) {
                    LOGGER.debug("there are no free ftp connections in the pool, used create temp client");
                    return factory.createClient();
                } else {
                    LOGGER.error("cannot get ftp client with pool, not have more free ftp connection");
                    throw Exceptions.ftp("cannot get ftp client with pool, not have more free ftp connection");
                }
            }
            // 不存活
            if (!Ftps.isActive(client)) {
                this.invalidClient(client);
                this.addClient();
                return this.getClient();
            }
            return client;
        } catch (InterruptedException e) {
            LOGGER.error("get ftp client with pool error", e);
            throw Exceptions.ftp("get ftp client with pool error", e);
        }
    }

    /**
     * 获取一个实例
     *
     * @return this
     */
    public synchronized FtpInstance getInstance() {
        return new FtpInstance(this);
    }

    /**
     * 归还一个连接, 如果归还超时则销毁改对象
     *
     * @param client 客户端
     */
    public synchronized void returnClient(FTPClient client) {
        try {
            Valid.notNull(client, "return client is null");
            LOGGER.debug("return ftp client with pool");
            if (!pool.offer(client, timeout, TimeUnit.MILLISECONDS)) {
                Ftps.destroy(client);
            }
        } catch (InterruptedException e) {
            LOGGER.error("return ftp client with to pool error", e);
        }
    }

    /**
     * 新建一个连接到池中
     */
    protected synchronized void addClient() {
        try {
            pool.offer(factory.createClient(), timeout, TimeUnit.MILLISECONDS);
            LOGGER.debug("add ftp client with pool");
        } catch (InterruptedException e) {
            LOGGER.error("cannot add a new connection to the pool", e);
        }
    }

    /**
     * 使客户端无效
     *
     * @param client 客户端
     */
    protected synchronized void invalidClient(FTPClient client) {
        LOGGER.debug("invalid ftp client with pool");
        pool.remove(client);
        Ftps.destroy(client);
    }

    /**
     * 关闭连接池 并且释放连接
     *
     * @throws InterruptedException 释放连接超时
     */
    @Override
    public void close() throws InterruptedException {
        LOGGER.debug("ftp client pool closing...");
        Streams.close(keepAlive);
        while (pool.iterator().hasNext()) {
            FTPClient client = pool.take();
            Ftps.destroy(client);
        }
    }

    /**
     * 获取连接池
     *
     * @return 连接池
     */
    protected BlockingQueue getPool() {
        return pool;
    }

    public boolean isEmptyCreateTemp() {
        return emptyCreateTemp;
    }

    public FtpClientFactory getFactory() {
        return factory;
    }

    /**
     * 获取FTP 配置文件
     *
     * @return FtpConfig
     */
    public FtpConfig getConfig() {
        return factory.getConfig();
    }

    /**
     * 获取空闲的连接数量
     *
     * @return 数量
     */
    public int getFreeSize() {
        return pool.size();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy