lucee.commons.io.res.type.ftp.FTPResource.java Source code

Java tutorial

Introduction

Here is the source code for lucee.commons.io.res.type.ftp.FTPResource.java

Source

/**
 *
 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
 *
 * 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 library.  If not, see <http://www.gnu.org/licenses/>.
 * 
 **/
package lucee.commons.io.res.type.ftp;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import lucee.commons.date.JREDateTimeUtil;
import lucee.commons.io.IOUtil;
import lucee.commons.io.ModeUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.ResourceProvider;
import lucee.commons.io.res.util.ResourceSupport;
import lucee.commons.io.res.util.ResourceUtil;
import lucee.commons.lang.StringUtil;
import lucee.runtime.PageContext;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.op.Caster;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPFile;

public final class FTPResource extends ResourceSupport {

    private final FTPResourceProvider provider;
    private final String path;
    private final String name;
    private final FTPConnectionData data;

    /**
     * Constructor of the class
     * @param factory
     * @param data 
     * @param path
     */
    FTPResource(FTPResourceProvider provider, FTPConnectionData data, String path) {
        this.provider = provider;
        this.data = data;

        String[] pathName = ResourceUtil.translatePathName(path);
        this.path = pathName[0];
        this.name = pathName[1];
    }

    /**
    * Constructor of the class
    * @param factory
    * @param data 
    * @param path
    */
    private FTPResource(FTPResourceProvider provider, FTPConnectionData data, String path, String name) {
        this.provider = provider;
        this.data = data;
        this.path = path;
        this.name = name;
    }

    @Override
    public boolean isReadable() {
        Boolean rtn = hasPermission(FTPFile.READ_PERMISSION);
        if (rtn == null)
            return false;
        return rtn.booleanValue();
    }

    public boolean isWriteable() {
        Boolean rtn = hasPermission(FTPFile.WRITE_PERMISSION);
        if (rtn == null)
            return false;
        return rtn.booleanValue();
    }

    private Boolean hasPermission(int permission) {
        FTPResourceClient client = null;
        try {
            provider.read(this);
            client = provider.getClient(data);
            FTPFile file = client.getFTPFile(this);
            if (file == null)
                return null;
            return Caster.toBoolean(file.hasPermission(FTPFile.USER_ACCESS, permission)
                    || file.hasPermission(FTPFile.GROUP_ACCESS, permission)
                    || file.hasPermission(FTPFile.WORLD_ACCESS, permission));
        } catch (IOException e) {
            return Boolean.FALSE;
        } finally {
            provider.returnClient(client);
        }
    }

    @Override
    public void remove(boolean alsoRemoveChildren) throws IOException {
        if (isRoot())
            throw new FTPResoucreException("can't delete root of ftp server");

        if (alsoRemoveChildren)
            ResourceUtil.removeChildren(this);
        FTPResourceClient client = null;
        try {
            provider.lock(this);
            client = provider.getClient(data);
            boolean result = client.deleteFile(getInnerPath());
            if (!result)
                throw new IOException("can't delete file [" + getPath() + "]");
        } finally {
            provider.returnClient(client);
            provider.unlock(this);
        }
    }

    @Override
    public boolean delete() {
        if (isRoot())
            return false;
        FTPResourceClient client = null;
        try {
            provider.lock(this);
            client = provider.getClient(data);
            return client.deleteFile(getInnerPath());
        } catch (IOException e) {
            return false;
        } finally {
            provider.returnClient(client);
            provider.unlock(this);
        }
    }

    @Override
    public boolean exists() {
        try {
            provider.read(this);
        } catch (IOException e) {
            return true;
        }
        FTPResourceClient client = null;
        InputStream is = null;
        try {
            //          getClient muss zuerst sein so wird verbindung geprueft
            client = provider.getClient(data);
            if (isRoot())
                return true;

            FTPFile file = client.getFTPFile(this);
            if (file != null) {
                return !file.isUnknown();
            }

            //String pathname = getInnerPath();
            String p = getInnerPath();
            if (!StringUtil.endsWith(p, '/'))
                p += "/";
            if (client.listNames(p) != null)
                return true;
            return false;
        } catch (IOException e) {
            return false;
        } finally {
            IOUtil.closeEL(is);
            provider.returnClient(client);
        }
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getParent() {
        if (isRoot())
            return null;
        return provider.getScheme().concat("://").concat(data.key()).concat(path.substring(0, path.length() - 1));
    }

    public String getInnerParent() {
        return path;
    }

    @Override
    public Resource getParentResource() {
        if (isRoot())
            return null;
        return new FTPResource(provider, data, path);
    }

    @Override
    public Resource getRealResource(String realpath) {
        realpath = ResourceUtil.merge(getInnerPath(), realpath);
        if (realpath.startsWith("../"))
            return null;
        return new FTPResource(provider, data, realpath);
    }

    @Override
    public String getPath() {
        return provider.getScheme().concat("://").concat(data.key()).concat(path).concat(name);
    }

    /**
     * @return returns path starting from ftp root
     */
    String getInnerPath() {
        return path.concat(name);
    }

    @Override
    public boolean isAbsolute() {
        // TODO impl isAbolute
        return true;
    }

    @Override
    public boolean isDirectory() {
        try {
            provider.read(this);
        } catch (IOException e1) {
            return false;
        }
        FTPResourceClient client = null;
        try {
            // getClient muss zuerst sein so wird verbindung geprueft
            client = provider.getClient(data);
            if (isRoot())
                return true;

            FTPFile file = client.getFTPFile(this);
            if (file != null) {
                return file.isDirectory();
            }
            //if(file==null) return false;
            //return file.isDirectory();

            String p = getInnerPath();
            if (!StringUtil.endsWith(p, '/'))
                p += "/";
            return client.listNames(p) != null;

        } catch (IOException e) {
            return false;
        } finally {
            provider.returnClient(client);
        }
    }

    @Override
    public boolean isFile() {
        if (isRoot())
            return false;
        try {
            provider.read(this);
        } catch (IOException e1) {
            return false;
        }
        FTPResourceClient client = null;
        InputStream is = null;
        try {
            client = provider.getClient(data);
            FTPFile file = client.getFTPFile(this);
            if (file != null) {
                return file.isFile();
            }
            return false;
            //String pathname = getInnerPath();
            //return (is=client.retrieveFileStream(pathname))!=null;
        }

        catch (IOException e) {
            return false;
        } finally {
            IOUtil.closeEL(is);
            provider.returnClient(client);
        }
    }

    @Override
    public long lastModified() {
        //if(isRoot()) return 0;

        FTPResourceClient client = null;
        try {
            provider.read(this);
            client = provider.getClient(data);
            FTPFile file = client.getFTPFile(this);
            if (file == null)
                return 0;
            return file.getTimestamp().getTimeInMillis();
        } catch (IOException e) {
            return 0;
        } finally {
            provider.returnClient(client);
        }
    }

    @Override
    public long length() {
        if (isRoot())
            return 0;
        FTPResourceClient client = null;
        try {
            provider.read(this);
            client = provider.getClient(data);
            FTPFile file = client.getFTPFile(this);
            if (file == null)
                return 0;
            return file.getSize();
        } catch (IOException e) {
            return 0;
        } finally {
            provider.returnClient(client);
        }
    }

    @Override
    public Resource[] listResources() {
        if (isFile())
            return null;//new Resource[0];

        FTPResourceClient client = null;
        try {
            client = provider.getClient(data);
            FTPFile[] files = null;
            String p = getInnerPath();
            if (!StringUtil.endsWith(p, '/'))
                p += "/";
            files = client.listFiles(p);
            if (files == null)
                return new Resource[0];

            List list = new ArrayList();
            String parent = path.concat(name).concat("/");
            String name;
            FTPResource res;
            for (int i = 0; i < files.length; i++) {
                name = files[i].getName();
                if (!".".equals(name) && !"..".equals(name)) {
                    res = new FTPResource(provider, data, parent, name);
                    client.registerFTPFile(res, files[i]);
                    list.add(res);
                }
            }
            return (Resource[]) list.toArray(new FTPResource[list.size()]);
        } catch (IOException ioe) {
            return null;
        } finally {
            provider.returnClient(client);
        }
    }

    @Override
    public boolean setLastModified(long time) {
        //if(isRoot()) return false;

        FTPResourceClient client = null;
        try {
            provider.lock(this);
            client = provider.getClient(data);

            PageContext pc = ThreadLocalPageContext.get();
            Calendar c = JREDateTimeUtil.getThreadCalendar();
            if (pc != null)
                c.setTimeZone(pc.getTimeZone());
            c.setTimeInMillis(time);
            FTPFile file = client.getFTPFile(this);
            if (file == null)
                return false;
            file.setTimestamp(c);
            client.unregisterFTPFile(this);
            return true;
        } catch (IOException e) {
        } finally {
            provider.returnClient(client);
            provider.unlock(this);
        }

        return false;
    }

    public boolean setReadOnly() {
        try {
            setMode(ModeUtil.setWritable(getMode(), false));
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    @Override
    public void createFile(boolean createParentWhenNotExists) throws IOException {
        ResourceUtil.checkCreateFileOK(this, createParentWhenNotExists);
        //client.unregisterFTPFile(this);
        IOUtil.copy(new ByteArrayInputStream(new byte[0]), getOutputStream(), true, true);
    }

    @Override
    public void moveTo(Resource dest) throws IOException {
        FTPResourceClient client = null;
        ResourceUtil.checkMoveToOK(this, dest);
        try {
            provider.lock(this);
            client = provider.getClient(data);

            client.unregisterFTPFile(this);

            if (dest instanceof FTPResource)
                moveTo(client, (FTPResource) dest);
            else
                super.moveTo(dest);

        } finally {
            provider.returnClient(client);
            provider.unlock(this);
        }
    }

    private void moveTo(FTPResourceClient client, FTPResource dest) throws IOException {
        if (!dest.data.equals(data)) {
            super.moveTo(dest);
            return;
        }
        if (dest.exists())
            dest.delete();

        client.unregisterFTPFile(dest);
        boolean ok = client.rename(getInnerPath(), dest.getInnerPath());
        if (!ok)
            throw new IOException("can't create file " + this);

    }

    @Override
    public void createDirectory(boolean createParentWhenNotExists) throws IOException {
        ResourceUtil.checkCreateDirectoryOK(this, createParentWhenNotExists);

        FTPResourceClient client = null;
        try {
            provider.lock(this);
            client = provider.getClient(data);
            client.unregisterFTPFile(this);
            boolean ok = client.makeDirectory(getInnerPath());
            if (!ok)
                throw new IOException("can't create file " + this);

        } finally {
            provider.returnClient(client);
            provider.unlock(this);
        }
    }

    @Override
    public InputStream getInputStream() throws IOException {
        ResourceUtil.checkGetInputStreamOK(this);
        provider.lock(this);
        FTPResourceClient client = provider.getClient(data);
        client.setFileType(FTP.BINARY_FILE_TYPE);
        try {
            return IOUtil.toBufferedInputStream(
                    new FTPResourceInputStream(client, this, client.retrieveFileStream(getInnerPath())));
        } catch (IOException e) {
            provider.returnClient(client);
            provider.unlock(this);
            throw e;
        }
    }

    @Override
    public OutputStream getOutputStream(boolean append) throws IOException {
        ResourceUtil.checkGetOutputStreamOK(this);
        FTPResourceClient client = null;
        try {
            provider.lock(this);
            client = provider.getClient(data);
            client.unregisterFTPFile(this);
            client.setFileType(FTP.BINARY_FILE_TYPE);
            OutputStream os = append ? client.appendFileStream(getInnerPath())
                    : client.storeFileStream(getInnerPath());
            if (os == null)
                throw new IOException("can not open stream to file [" + this + "]");

            return IOUtil.toBufferedOutputStream(new FTPResourceOutputStream(client, this, os));
        } catch (IOException e) {
            provider.returnClient(client);
            provider.unlock(this);
            throw e;
        }
    }

    @Override
    public String[] list() {
        if (isFile())
            return new String[0];

        FTPResourceClient client = null;
        try {
            client = provider.getClient(data);
            String[] files = null;

            String p = getInnerPath();
            if (!StringUtil.endsWith(p, '/'))
                p += "/";
            files = client.listNames(p);
            if (files == null)
                return new String[0];
            for (int i = 0; i < files.length; i++) {
                files[i] = cutName(files[i]);
            }
            return files;
        } catch (IOException ioe) {
            return null;
        } finally {
            provider.returnClient(client);
        }
    }

    private String cutName(String path) {
        int index = path.lastIndexOf('/');
        if (index == -1)
            return path;
        return path.substring(index + 1);
    }

    @Override
    public ResourceProvider getResourceProvider() {
        return provider;
    }

    public FTPResourceProvider getFTPResourceProvider() {
        return provider;
    }

    boolean isRoot() {
        return StringUtil.isEmpty(name);
    }

    public int getMode() {
        //if(isRoot()) return 0;

        FTPResourceClient client = null;
        try {
            provider.read(this);
            client = provider.getClient(data);

            FTPFile file = client.getFTPFile(this);
            int mode = 0;
            if (file == null)
                return 0;

            // World
            if (file.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.EXECUTE_PERMISSION))
                mode += 01;
            if (file.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.WRITE_PERMISSION))
                mode += 02;
            if (file.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.READ_PERMISSION))
                mode += 04;

            // Group
            if (file.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.EXECUTE_PERMISSION))
                mode += 010;
            if (file.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.WRITE_PERMISSION))
                mode += 020;
            if (file.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.READ_PERMISSION))
                mode += 040;

            // Owner
            if (file.hasPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION))
                mode += 0100;
            if (file.hasPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION))
                mode += 0200;
            if (file.hasPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION))
                mode += 0400;

            return mode;

        } catch (IOException e) {
        } finally {
            provider.returnClient(client);
        }

        return 0;
    }

    public void setMode(int mode) throws IOException {
        //if(isRoot()) throw new IOException("can't change mode of root");

        FTPResourceClient client = null;
        try {
            provider.lock(this);
            client = provider.getClient(data);

            FTPFile file = client.getFTPFile(this);
            if (file != null) {
                // World
                file.setPermission(FTPFile.WORLD_ACCESS, FTPFile.EXECUTE_PERMISSION, (mode & 01) > 0);
                file.setPermission(FTPFile.WORLD_ACCESS, FTPFile.WRITE_PERMISSION, (mode & 02) > 0);
                file.setPermission(FTPFile.WORLD_ACCESS, FTPFile.READ_PERMISSION, (mode & 04) > 0);

                // Group
                file.setPermission(FTPFile.GROUP_ACCESS, FTPFile.EXECUTE_PERMISSION, (mode & 010) > 0);
                file.setPermission(FTPFile.GROUP_ACCESS, FTPFile.WRITE_PERMISSION, (mode & 020) > 0);
                file.setPermission(FTPFile.GROUP_ACCESS, FTPFile.READ_PERMISSION, (mode & 040) > 0);

                // Owner
                file.setPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION, (mode & 0100) > 0);
                file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, (mode & 0200) > 0);
                file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, (mode & 0400) > 0);

                client.unregisterFTPFile(this);
            }
        } catch (IOException e) {
        } finally {
            provider.returnClient(client);
            provider.unlock(this);
        }

    }

    public boolean setReadable(boolean value) {
        try {
            setMode(ModeUtil.setReadable(getMode(), value));
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    public boolean setWritable(boolean value) {
        try {
            setMode(ModeUtil.setWritable(getMode(), value));
            return true;
        } catch (IOException e) {
            return false;
        }
    }
}