com.symbian.driver.plugins.ftptelnet.FtpTransfer.java Source code

Java tutorial

Introduction

Here is the source code for com.symbian.driver.plugins.ftptelnet.FtpTransfer.java

Source

/*
* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

package com.symbian.driver.plugins.ftptelnet;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.SocketException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.cli.ParseException;
import org.apache.commons.net.ProtocolCommandEvent;
import org.apache.commons.net.ProtocolCommandListener;
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 com.symbian.driver.core.environment.TDConfig;
import com.symbian.driver.core.extension.IDeviceComms;

public class FtpTransfer implements IDeviceComms.ISymbianTransfer {

    private String iIP = "127.0.0.1";

    private int iPort = 21;

    private FTPClient iFTP = null;

    private String iUserName = "username";

    private String iPassword = "pass";

    private String iPassive = "true";

    private static String iSystemDrive = null;

    private static String iDefaultSystemDrive = "C";

    private static String iSystemDriveLiteral = "System Drive: ";

    private boolean iFirstDeleteIteration = true;

    private static final int iBufferSize = 10 * 1460;

    /** Singleton to STAT. */
    private static final Logger LOGGER = Logger.getLogger(FtpTransfer.class.getName());

    private static Hashtable<String, FtpTransfer> iFtpInstances = new Hashtable<String, FtpTransfer>();

    /**
     * getInstance : gets the first instance from the list of instances. If
     * there are no instances, it will try to create an instance with transport
     * from TDConfig.
     * 
     * @return FtpTransfer instance (connected to the server if possible however
     *         not guaranteed)
     */
    public static synchronized FtpTransfer getInstance() {
        FtpTransfer lInstance = null;
        if (iFtpInstances.isEmpty()) {
            // create a new one with transport from config
            try {
                String lTransport = TDConfig.getInstance().getPreference(TDConfig.TRANSPORT);

                lInstance = new FtpTransfer(lTransport);
                iFtpInstances.put(lTransport, lInstance);
            } catch (ParseException lParseException) {
                LOGGER.log(Level.SEVERE, "Could not create an FTP session.", lParseException);
            }
        } else {
            // get the first instance.
            lInstance = iFtpInstances.elements().nextElement();
        }
        return lInstance;
    }

    /**
     * getInstance : get FtpTransfer instance for the provided transport if
     * created or create a new one.
     * 
     * @param String
     *            aTransport
     * @return a FtpTransfer instance (connected to the server if possible
     *         however not guaranteed)
     */
    public static synchronized FtpTransfer getInstance(String aTransport) {
        FtpTransfer lInstance = null;
        if (iFtpInstances.containsKey(aTransport)) {
            // get the appropriate instance
            lInstance = (FtpTransfer) iFtpInstances.get(aTransport);
        } else {
            // create a new one with the transport provided
            try {
                lInstance = new FtpTransfer(aTransport);
                iFtpInstances.put(aTransport, lInstance);
            } catch (ParseException lParseException) {
                LOGGER.log(Level.SEVERE, "Could not create an FTP session.", lParseException);
            }
        }
        return lInstance;
    }

    /**
     * removeAllInstances: disconnect all instances and deletes them.
     * 
     * @return boolean success/fail (if any fails to disconnect)
     */
    public static boolean removeAllInstances() {
        boolean lResult = true;
        Set<String> lkeySet = iFtpInstances.keySet();
        for (Iterator iter = lkeySet.iterator(); iter.hasNext();) {

            FtpTransfer lInstance = (FtpTransfer) iFtpInstances.get(iter.next());
            try {
                lInstance.disconnectFTP();
                iFtpInstances.remove(iter);
            } catch (IOException lIOException) {
                lResult = false;
                LOGGER.log(Level.SEVERE, "Session with transport: " + iter + " failed to disconnect.",
                        lIOException);
            }
        }
        return lResult;
    }

    private FtpTransfer(String aTransport) throws ParseException {
        // check transport is valid
        String lTransport = aTransport;
        if (!isTransportValid(lTransport)) {
            throw new ParseException("Transport " + lTransport + " incorrect.");
        }

        // connect FTP
        connectFTP();

    }

    /**
     * isTransportValid Checks if the transport is correct
     * 
     * @param String
     *            aTransport. Should be in the form tcp:ip@:port
     * @return true/false
     */
    private boolean isTransportValid(String aTransport) {
        // ip transport should be in the form tcp:d+.d+.d+.d+:port
        Pattern lPattern = Pattern.compile("tcp:(\\d+\\.\\d+\\.\\d+\\.\\d+)(:\\d+)?");
        Matcher lMatcher = lPattern.matcher(aTransport);
        if (lMatcher.matches()) {
            iIP = lMatcher.group(1);
            try {
                iPort = Integer.parseInt(TDConfig.getInstance().getPreference(
                        FtpTelnetLaunchConstants.PLUGIN_ID + ":" + FtpTelnetLaunchConstants.FTPPORT));
                iPassive = TDConfig.getInstance().getPreference(
                        FtpTelnetLaunchConstants.PLUGIN_ID + ":" + FtpTelnetLaunchConstants.FTPPASSIVE);
            } catch (Exception lException) {
                LOGGER.log(Level.WARNING, "Configuration error.", lException);
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * connectFTP : connects to ftp server
     * 
     * @return boolean success/fail
     */
    public boolean connectFTP() {
        if (isFTPConnected()) {
            return true;
        }
        // Connect to FTP
        try {

            // 1. create an apache client
            iFTP = new FTPClient();
            iFTP.addProtocolCommandListener(new ProtocolCommandListener() {

                public void protocolCommandSent(ProtocolCommandEvent aProtocolCommandEvent) {
                    LOGGER.fine("FTP Command Send: (" + aProtocolCommandEvent.getCommand() + ") "
                            + aProtocolCommandEvent.getMessage());
                }

                public void protocolReplyReceived(ProtocolCommandEvent aProtocolCommandEvent) {
                    LOGGER.fine("FTP Command Recieved: (" + aProtocolCommandEvent.getMessage() + ") Returned Code "
                            + aProtocolCommandEvent.getReplyCode());
                }
            });
            FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
            iFTP.configure(conf);
            // 2. connect
            iFTP.connect(iIP, iPort);

            // 3. check connection done.
            int reply = iFTP.getReplyCode();

            if (!FTPReply.isPositiveCompletion(reply)) {
                disconnectFTP();
                LOGGER.log(Level.SEVERE, "FTP error: " + reply);
                return false;
            }

            // 4. Login
            if (!iFTP.login(iUserName, iPassword)) {
                LOGGER.log(Level.SEVERE, "FTP failed to login, Username: " + iUserName + " Password: " + iPassword);
                disconnectFTP();
                return false;
            } else {
                if (iPassive.equalsIgnoreCase("true")) {
                    iFTP.enterLocalPassiveMode();
                }
                iFTP.setFileType(FTP.BINARY_FILE_TYPE);
                iFTP.setBufferSize(iBufferSize);
            }

        } catch (SocketException lSocketException) {
            LOGGER.log(Level.SEVERE, "Socket exception ", lSocketException);
            return false;
        } catch (IOException lIOException) {
            LOGGER.log(Level.SEVERE, "Socket exception ", lIOException);
            return false;
        }

        LOGGER.info("FTP connection established with transport : " + iIP + ":" + iPort);

        return true;

    }

    /**
     * disconnects from ftp server
     * 
     * @throws IOException
     */
    public void disconnectFTP() throws IOException {
        if (iFTP != null && iFTP.isConnected()) {
            iFTP.logout();
            iFTP.disconnect();
            LOGGER.info("FTP with transport " + iIP + ":" + iPort + " Disconnected.");
        }
    }

    /**
     * isFTPConnected : checks if connection is established.
     * 
     * @return boolean true/false
     */
    public boolean isFTPConnected() {
        if (iFTP != null && iFTP.isConnected()) {
            return true;
        }
        return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.symbian.driver.core.extension.IDeviceComms.ISymbianTransfer#cd(java.io.File)
     */
    public boolean cd(File aSymbianPath) {
        LOGGER.info("FTP cd : " + aSymbianPath);
        boolean lResult = false;
        String lDir = normalizePath(aSymbianPath);
        if (connectFTP()) {
            try {
                lResult = iFTP.changeWorkingDirectory(lDir);
            } catch (IOException lIOException) {
                LOGGER.log(Level.SEVERE, "FTP command failed : cd " + aSymbianPath, lIOException);
            }
        }

        return lResult;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.symbian.driver.core.extension.IDeviceComms.ISymbianTransfer#delete(java.io.File,
     *      boolean)
     */
    public boolean delete(File aSymbianFile, boolean aRecurse) {
        LOGGER.info("Deleting file/folder " + aSymbianFile.toString());
        // aSymbianFile can be
        // 1. folder name (this is the only case where aRecurse is relevant)
        // 2. file name
        // 3. a pattern

        boolean lResult = false;
        String lDir = aSymbianFile.getPath().replaceAll("\\\\", "/");
        if (iFirstDeleteIteration) {
            if (lDir.contains("*")) {
                lDir = normalizePath(aSymbianFile.getParentFile());
            } else {
                lDir = normalizePath(aSymbianFile);
            }
        }
        if (connectFTP()) {
            try {
                if (lDir.contains("*")) {
                    // ex. delete \test\*.txt
                    // calls delete("\test", "*.txt")
                    lResult = delete(lDir, new File(lDir).getName());
                } else {
                    // try to delete it first
                    lResult = iFTP.deleteFile(lDir);
                    if (!lResult) {
                        String lRes = iFTP.getReplyString();
                        if (lRes.indexOf("No such file or directory") == -1) {
                            // it could be a existing folder
                            // first delete all files
                            lResult = delete(lDir, "*");

                            if (lResult && aRecurse) {
                                // delete recusively

                                FTPFile[] lFiles = iFTP.listFiles();
                                File lFile = null;
                                for (int i = 0; i < lFiles.length; i++) {
                                    lFile = new File(pwd(), lFiles[i].getName());
                                    iFirstDeleteIteration = false;
                                    lResult = delete(lFile, true);
                                    if (!lResult) {
                                        break;
                                    }
                                }
                                // folder deleted , delete the folder itself
                                if (lResult) {
                                    lResult = iFTP.removeDirectory(lDir);
                                } else {
                                    LOGGER.log(Level.SEVERE, "Could not delete folder " + lFile);
                                }
                            }
                        }
                    }
                }
            } catch (IOException lIOException) {
                lResult = false;
                LOGGER.log(Level.SEVERE,
                        "FTP command failed : delete " + (aRecurse ? "folder " : "file ") + aSymbianFile,
                        lIOException);
            }
        }

        return lResult;
    }

    private boolean delete(String aDirectory, String name) {
        boolean lReturn = true;
        String lName = name.replaceAll("\\*", "\\.\\*");

        Pattern lPattern = Pattern.compile(lName, Pattern.CASE_INSENSITIVE);
        try {
            lReturn = iFTP.changeWorkingDirectory(aDirectory);
            if (lReturn) {
                FTPFile[] lFiles = iFTP.listFiles();
                for (int i = 0; i < lFiles.length; i++) {
                    if (lFiles[i].isFile()) {
                        if (lPattern.matcher(lFiles[i].getName()).matches()) {
                            // delete the file
                            LOGGER.info("Deleting file " + lFiles[i].getName());
                            lReturn = iFTP.deleteFile(lFiles[i].getName());
                            LOGGER.info("Delete file " + lFiles[i].getName());
                        }
                    }
                }
            } else {
                lReturn = true;
            }
        } catch (IOException lIOException) {
            lReturn = false;
            LOGGER.log(Level.SEVERE, "FTP command failed : delete " + name, lIOException);
        }
        return lReturn;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.symbian.driver.core.extension.IDeviceComms.ISymbianTransfer#dir(java.io.File)
     */
    public List<File> dir(File aSymbianPath) {
        LOGGER.info("Listing folder " + aSymbianPath.toString());
        String lDir = aSymbianPath.getPath().replaceAll("\\\\", "/");
        String lName = ".*";
        if (lDir.contains("*")) {
            lDir = normalizePath(aSymbianPath.getParentFile());
            lName = aSymbianPath.getName().replaceAll("\\*", "\\.\\*");
        } else {
            if (!lDir.equals("/")) {
                lDir = normalizePath(aSymbianPath);
            }
        }

        Pattern lPattern = Pattern.compile(lName, Pattern.CASE_INSENSITIVE);
        List<File> lReturn = new LinkedList<File>();
        if (connectFTP()) {
            try {
                if (iFTP.changeWorkingDirectory(lDir)) {
                    FTPFile[] lFiles = iFTP.listFiles();
                    for (int i = 0; i < lFiles.length; i++) {
                        if (lPattern.matcher(lFiles[i].getName()).matches()) {
                            // convert file back to NT
                            lReturn.add(new File(backToNT(new File(lDir, lFiles[i].getName()).getPath())));
                        }
                    }
                }
            } catch (IOException lIOException) {
                LOGGER.log(Level.SEVERE, "FTP command failed : dir " + aSymbianPath, lIOException);
            }
        }
        return lReturn;
    }

    private String backToNT(String aDirectory) {
        return aDirectory.replaceAll("\\\\", "/").replaceAll("^/(.)", "$1:");
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.symbian.driver.core.extension.IDeviceComms.ISymbianTransfer#mkdir(java.io.File)
     */
    public boolean mkdir(File aSymbianDir) {
        LOGGER.info("Creating folder " + aSymbianDir.toString());
        String lDir = normalizePath(aSymbianDir);
        boolean lResult = false;
        if (connectFTP()) {
            try {
                String[] lPaths = lDir.split("/");
                String lPath = "/";
                for (int i = 0; i < lPaths.length; i++) {
                    if (!lPaths[i].equals("")) {
                        lPath = lPath + lPaths[i] + "/";
                        lResult = iFTP.changeWorkingDirectory(lPath);
                        if (!lResult) {
                            // can create
                            lResult = iFTP.makeDirectory(lPaths[i]);
                            // and accessible
                            lResult = iFTP.changeWorkingDirectory(lPath);
                        }
                    }
                }
            } catch (IOException lIOException) {
                LOGGER.log(Level.SEVERE, "FTP command failed : mkdir " + aSymbianDir, lIOException);
            }
        }
        return lResult;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.symbian.driver.core.extension.IDeviceComms.ISymbianTransfer#move(java.io.File,
     *      java.io.File)
     */
    public boolean move(File aSymbianSource, File aSymbianDestination) {
        LOGGER.info("Moving file from " + aSymbianSource + " to " + aSymbianDestination);
        String lDirSource = normalizePath(aSymbianSource);
        String lDirDestination = normalizePath(aSymbianDestination);
        boolean lResult = false;
        if (connectFTP()) {
            try {
                lResult = iFTP.rename(lDirSource, lDirDestination);
            } catch (IOException lIOException) {
                LOGGER.log(Level.SEVERE,
                        "FTP command failed : rename " + aSymbianSource + " to " + aSymbianDestination,
                        lIOException);
            }
        }
        return lResult;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.symbian.driver.core.extension.IDeviceComms.ISymbianTransfer#pwd()
     */
    public File pwd() {
        LOGGER.info("FTP pwd");
        String lResult = null;
        File lPWD = null;
        if (connectFTP()) {
            try {
                lResult = iFTP.printWorkingDirectory();
                if (lResult != null) {
                    lPWD = new File(backToNT(lResult));
                }
            } catch (IOException lIOException) {
                LOGGER.log(Level.SEVERE, "FTP command failed : pwd ", lIOException);
            }
        }
        return lPWD;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.symbian.driver.core.extension.IDeviceComms.ISymbianTransfer#retrieve(java.io.File,
     *      java.io.File)
     */
    public boolean retrieve(File aSymbianFile, File aHostFile) {
        LOGGER.info("Retrieve file " + aSymbianFile + " to " + aHostFile);
        String lDirSource = normalizePath(aSymbianFile.getParentFile());
        String lName = aSymbianFile.getName();
        boolean lResult = false;

        if (connectFTP()) {
            try {
                lResult = iFTP.changeWorkingDirectory(lDirSource);
                if (lResult) {
                    if (aHostFile.isDirectory()) {
                        aHostFile = new File(aHostFile, lName);
                    }
                    lResult = iFTP.retrieveFile(lName, new FileOutputStream(aHostFile));
                }
            } catch (FileNotFoundException lFileNotFoundException) {
                LOGGER.log(Level.SEVERE, "FTP command failed : retrieve ", lFileNotFoundException);
                lResult = false;
            } catch (IOException lIOException) {
                LOGGER.log(Level.SEVERE, "FTP command failed : retrieve ", lIOException);
                lResult = false;
            }
        }

        return lResult;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.symbian.driver.core.extension.IDeviceComms.ISymbianTransfer#send(java.io.File,
     *      java.io.File)
     */
    public boolean send(File aHostFile, File aSymbianFile) {
        LOGGER.info("Sending file " + aHostFile + " to " + aSymbianFile);
        try {
            Thread.sleep(400);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        String lName = aSymbianFile.getName();
        boolean lResult = false;

        if (connectFTP()) {
            try {
                // create folder if it does exist
                String lParent = normalizePath(aSymbianFile.getParentFile());
                lResult = iFTP.changeWorkingDirectory(lParent);
                if (!lResult) {
                    // try to create it
                    lResult = iFTP.makeDirectory(lParent);
                    if (lResult) {
                        lResult = iFTP.changeWorkingDirectory(lParent);
                    }
                }
                if (lResult) {
                    lResult = iFTP.storeFile(lName, new FileInputStream(aHostFile));
                }
            } catch (FileNotFoundException lFileNotFoundException) {
                lResult = false;
                LOGGER.log(Level.SEVERE, "FTP command failed : send ", lFileNotFoundException);
            } catch (IOException lIOException) {
                lResult = false;
                LOGGER.log(Level.SEVERE, "FTP command failed : send ", lIOException);
            }
        }
        return lResult;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.symbian.driver.core.extension.IDeviceComms.ISymbianTransfer#listDrives()
     */
    public List<String> listDrives() {
        LOGGER.info("listing Drives");
        List<String> lDrives = new LinkedList<String>();
        List<File> lFiles = new LinkedList<File>();
        if (connectFTP()) {
            lFiles = dir(new File("/"));
            for (Iterator iter = lFiles.iterator(); iter.hasNext();) {
                File element = (File) iter.next();
                lDrives.add(element.toString());
            }
        }
        if (lDrives.isEmpty()) {
            LOGGER.log(Level.SEVERE, "Could not get list of drives from server.");
        }
        return lDrives;
    }

    public String getSystemDrive() {
        LOGGER.fine("FTP getSystemDrive");
        if (iSystemDrive == null) {
            // get system drive
            if (connectFTP()) {
                try {
                    String lStatus = iFTP.getStatus();
                    int lPos = lStatus.indexOf(iSystemDriveLiteral);
                    if (lPos != -1) {
                        iSystemDrive = lStatus.substring(lPos + iSystemDriveLiteral.length(),
                                lPos + iSystemDriveLiteral.length() + 1);
                    } else {
                        LOGGER.log(Level.SEVERE,
                                "Could not get System Drive from server. Will use the first from the list of drives.");
                        List<String> lDrives = listDrives();
                        if (!lDrives.isEmpty()) {
                            iSystemDrive = lDrives.get(0);
                        } else {
                            LOGGER.log(Level.SEVERE, "Could not get System Drive from server. Will use default: \\"
                                    + iDefaultSystemDrive + "\\");
                            iSystemDrive = iDefaultSystemDrive;
                        }
                    }
                } catch (IOException lIOException) {
                    LOGGER.log(Level.SEVERE, "FTP command failed : STAT ", lIOException);
                }

            }
        }
        return iSystemDrive;
    }

    public String normalizePath(File aSymbianFile) {
        // a SymbianPath could be
        // \path\... use system drive /C/path/...
        // drive:\path\... covert it to /C/path/...
        // path covert it to pwd()/path...
        // just file name pwd()/name
        String lReturn = null;
        if (aSymbianFile == null) {
            lReturn = pwd().getPath().replaceAll("\\\\", "/");
        } else {
            File lFile = aSymbianFile;
            lReturn = lFile.getPath().replaceAll("\\\\", "/");
            Matcher lMatcher = Pattern.compile("^(.):(.*)").matcher(lReturn);
            if (lReturn.startsWith("/")) {
                // prepend system drive to the path.
                lReturn = "/" + getSystemDrive() + lReturn;
            } else if (lReturn.startsWith("$:")) {
                lReturn = lReturn.replace("$:", "/" + getSystemDrive());
            } else if (lMatcher.find()) {
                lReturn = "/" + lMatcher.group(1) + lMatcher.group(2);
            } else {
                lReturn = pwd() + "/" + lReturn;
            }
        }
        return lReturn;
    }
}