net.yacy.grid.io.assets.FTPStorageFactory.java Source code

Java tutorial

Introduction

Here is the source code for net.yacy.grid.io.assets.FTPStorageFactory.java

Source

/**
 *  FilesystemStorageFactory
 *  Copyright 28.1.2017 by Michael Peter Christen, @0rb1t3r
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *  
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program in the file lgpl21.txt
 *  If not, see <http://www.gnu.org/licenses/>.
 */

package net.yacy.grid.io.assets;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;

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.FTPReply;

import net.yacy.grid.mcp.Data;

public class FTPStorageFactory implements StorageFactory<byte[]> {

    private static int DEFAULT_PORT = 21;

    private String server, username, password;
    private int port;
    private Storage<byte[]> ftpClient;
    private boolean deleteafterread;

    public FTPStorageFactory(String server, int port, String username, String password, boolean deleteafterread)
            throws IOException {
        this.server = server;
        this.username = username == null ? "" : username;
        this.password = password == null ? "" : password;
        this.port = port;
        this.deleteafterread = deleteafterread;

        this.ftpClient = new Storage<byte[]>() {

            @Override
            public void checkConnection() throws IOException {
                return;
            }

            private FTPClient initConnection() throws IOException {
                FTPClient ftp = new FTPClient();
                ftp.setDataTimeout(3000);
                ftp.setConnectTimeout(20000);
                if (FTPStorageFactory.this.port < 0 || FTPStorageFactory.this.port == DEFAULT_PORT) {
                    ftp.connect(FTPStorageFactory.this.server);
                } else {
                    ftp.connect(FTPStorageFactory.this.server, FTPStorageFactory.this.port);
                }
                ftp.enterLocalPassiveMode(); // the server opens a data port to which the client conducts data transfers
                int reply = ftp.getReplyCode();
                if (!FTPReply.isPositiveCompletion(reply)) {
                    if (ftp != null)
                        try {
                            ftp.disconnect();
                        } catch (Throwable ee) {
                        }
                    throw new IOException("bad connection to ftp server: " + reply);
                }
                if (!ftp.login(FTPStorageFactory.this.username, FTPStorageFactory.this.password)) {
                    if (ftp != null)
                        try {
                            ftp.disconnect();
                        } catch (Throwable ee) {
                        }
                    throw new IOException("login failure");
                }
                ftp.setFileType(FTP.BINARY_FILE_TYPE);
                ftp.setBufferSize(8192);
                return ftp;
            }

            @Override
            public StorageFactory<byte[]> store(String path, byte[] asset) throws IOException {
                long t0 = System.currentTimeMillis();
                FTPClient ftp = initConnection();
                try {
                    long t1 = System.currentTimeMillis();
                    String file = cdPath(ftp, path);
                    long t2 = System.currentTimeMillis();
                    ftp.enterLocalPassiveMode();
                    boolean success = ftp.storeFile(file, new ByteArrayInputStream(asset));
                    long t3 = System.currentTimeMillis();
                    if (!success)
                        throw new IOException("storage to path " + path + " was not successful (storeFile=false)");
                    Data.logger.debug("FTPStorageFactory.store ftp store successfull: check connection = "
                            + (t1 - t0) + ", cdPath = " + (t2 - t1) + ", store = " + (t3 - t2));
                } catch (IOException e) {
                    throw e;
                } finally {
                    if (ftp != null)
                        try {
                            ftp.disconnect();
                        } catch (Throwable ee) {
                        }
                }
                return FTPStorageFactory.this;
            }

            @Override
            public Asset<byte[]> load(String path) throws IOException {
                FTPClient ftp = initConnection();
                ByteArrayOutputStream baos = null;
                byte[] b = null;
                try {
                    String file = cdPath(ftp, path);
                    baos = new ByteArrayOutputStream();
                    ftp.retrieveFile(file, baos);
                    b = baos.toByteArray();
                    if (FTPStorageFactory.this.deleteafterread)
                        try {
                            boolean deleted = ftp.deleteFile(file);
                            FTPFile[] remaining = ftp.listFiles();
                            if (remaining.length == 0) {
                                ftp.cwd("/");
                                if (path.startsWith("/"))
                                    path = path.substring(1);
                                int p = path.indexOf('/');
                                if (p > 0)
                                    path = path.substring(0, p);
                                ftp.removeDirectory(path);
                            }
                        } catch (Throwable e) {
                            Data.logger.warn("FTPStorageFactory.load failed to remove asset " + path, e);
                        }
                } catch (IOException e) {
                    throw e;
                } finally {
                    if (ftp != null)
                        try {
                            ftp.disconnect();
                        } catch (Throwable ee) {
                        }
                }
                return new Asset<byte[]>(FTPStorageFactory.this, b);
            }

            @Override
            public void close() {
            }

            private String cdPath(FTPClient ftp, String path) throws IOException {
                int success_code = ftp.cwd("/");
                if (success_code >= 300)
                    throw new IOException("cannot cd into " + path + ": " + success_code);
                if (path.length() == 0 || path.equals("/"))
                    return "";
                if (path.charAt(0) == '/')
                    path = path.substring(1); // we consider that all paths are absolute to / (home)
                int p;
                while ((p = path.indexOf('/')) > 0) {
                    String dir = path.substring(0, p);
                    int code = ftp.cwd(dir);
                    if (code >= 300) {
                        // path may not exist, try to create the path
                        boolean success = ftp.makeDirectory(dir);
                        if (!success)
                            throw new IOException("unable to create directory " + dir + " for path " + path);
                        code = ftp.cwd(dir);
                        if (code >= 300)
                            throw new IOException("unable to cwd into directory " + dir + " for path " + path);
                    }
                    path = path.substring(p + 1);
                }
                return path;
            }
        };
    }

    @Override
    public String getSystem() {
        return "ftp";
    }

    @Override
    public String getConnectionURL() {
        return "ftp://" + (this.username != null && this.username.length() > 0
                ? username + (this.password != null && this.password.length() > 0 ? ":" + this.password : "") + "@"
                : "") + this.getHost() + ((this.hasDefaultPort() ? "" : ":" + this.getPort()));
    }

    @Override
    public String getHost() {
        return this.server;
    }

    @Override
    public boolean hasDefaultPort() {
        return this.port == -1 || this.port == DEFAULT_PORT;
    }

    @Override
    public int getPort() {
        return hasDefaultPort() ? DEFAULT_PORT : this.port;
    }

    @Override
    public Storage<byte[]> getStorage() throws IOException {
        return this.ftpClient;
    }

    @Override
    public void close() {
        this.ftpClient.close();
    }

    public static void main(String[] args) {
        try {
            Data.init(new File("data"), new HashMap<String, String>(), true);
            FTPStorageFactory ftpc = new FTPStorageFactory("127.0.0.1", 2121, "anonymous", "yacy", true);
            Storage<byte[]> storage = ftpc.getStorage();
            String path = "test/file";
            String data = "123";
            storage.store(path, data.getBytes());
            Asset<byte[]> b = storage.load(path);
            System.out.println(new String(b.getPayload()));
            Data.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}