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

org.ow2.petals.bc.sftp.connection.WrappedSftpClient Maven / Gradle / Ivy

There is a newer version: 1.10.0
Show newest version
/**
 * Copyright (c) 2009-2012 EBM WebSourcing, 2012-2015 Linagora
 * 
 * This program/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 program/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/library; If not, see 
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.bc.sftp.connection;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.activation.DataHandler;
import javax.activation.FileTypeMap;
import javax.mail.util.ByteArrayDataSource;

import org.ow2.petals.component.framework.util.FileNamePatternUtil;
import org.ow2.petals.component.framework.util.FileNamePatternUtil.RegexFileNameFilter;
import org.ow2.petals.component.framework.util.XMLUtil;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.ebmwebsourcing.easycommons.lang.StringHelper;
import com.sshtools.j2ssh.SftpClient;
import com.sshtools.j2ssh.authentication.AuthenticationProtocolState;
import com.sshtools.j2ssh.authentication.SshAuthenticationClient;
import com.sshtools.j2ssh.sftp.FileAttributes;
import com.sshtools.j2ssh.sftp.SftpFile;
import com.sshtools.j2ssh.transport.IgnoreHostKeyVerification;

/**
 * This class handle a connection to the SFTP server with the specified configuration parameters.
 * @author Mathieu CARROLLE - EBM WebSourcing
 */
public class WrappedSftpClient extends BasicSftpClient {

    private final Logger logger;

    public WrappedSftpClient(final SFTPConnectionInfo connectionConfiguration, final Logger logger) {
        super(connectionConfiguration);
        this.logger = logger;
    }

    /**
     * Change the path on the remote server.
     * 
     * @throws IOException
     */
    public void configure() throws IOException {
        if (!StringHelper.isNullOrEmpty(info.getDirectory())) {
            this.client.cd(info.getDirectory());
        }
    }

    /**
     * Open a ssh connection on the remote server and open a sftpclient.
     * 
     * @throws SshAuthenticationException
     * @throws IOException
     */
    public void connectAndLog() throws IOException {
        this.setSocketTimeout((int) this.info.getMaxIdleTime());
        try {
            this.connect(info.getServer(), info.getPort(), new IgnoreHostKeyVerification());
        } catch (IOException ex) {
            final StringBuilder errorSB = new StringBuilder();
            errorSB.append("Can't open a connection to [");
            errorSB.append(info);
            errorSB.append("]. Cause : " + ex.getMessage());
            throw new IOException(errorSB.toString(), ex);
        }
        // Retrieve the authentication informations
        final SshAuthenticationClient sshAuthenticationClient;
        sshAuthenticationClient = info.getSshAuthentication().getAuthenticationClient();
        // Try the authentication
        int authenticationResult = this.authenticate(sshAuthenticationClient);
        if (authenticationResult != AuthenticationProtocolState.COMPLETE) {
            this.disconnect();
            throw new IOException("Can't open a connection to [" + info
                    + "]. Cause : Authentication failed");
        }
        this.client = this.openSftpClient();
    }

    /***
     * 
     * @param filePattern
     * @throws SshAuthenticationException
     * @throws SftpClientPoolException
     * @throws IOException
     */
    @SuppressWarnings("unchecked")
    public void del(String filePattern) throws IOException {
        final RegexFileNameFilter filter = FileNamePatternUtil.getInstance()
                .buildFileNameFilterFromWildChar(filePattern);
        final List fileContainedWithinWorkingDir = client.ls();
        // Retrieve the files that match the given name
        for (SftpFile file : fileContainedWithinWorkingDir) {
            if ((file.isFile() && file.canRead()) && filter.accept(null, file.getFilename())) {
                file.delete();
                break;
            }
        }
    }

    /**
     * Retrieve the file given by its filename on the SFTP server.
     * 
     * @param filePattern
     *            name of the file to get from the SFTP server
     * @return the retrieved file, streamed
     * @throws SftpClientPoolException
     *             if a problem on the client pool occur while performing this
     *             operation
     * @throws SshAuthenticationException
     *             if the given authentication information are not valid
     * @throws IOException
     *             if any IO problem occur while sending file or connecting to
     *             server
     */
    @SuppressWarnings("unchecked")
    public Document get(final String filePattern) throws IOException {
        final RegexFileNameFilter filter = FileNamePatternUtil.getInstance()
                .buildFileNameFilterFromWildChar(filePattern);
        // Holds the result of the GET operation
        Document result = null;
        final List fileContainedWithinWorkingDir = client.ls();
        for (SftpFile file : fileContainedWithinWorkingDir) {
            if ((file.isFile() && file.canRead()) && filter.accept(null, file.getFilename())) {
                result = this.getAsDocument(file, client);
                break;
            }
        }
        // If the file doen't exist
        if (result == null) {
            throw new IOException("Can not find the specified resource");
        }
        return result;
    }

    /**
     * Retrieve the file given by its filename on the SFTP server.
     * 
     * @param filePattern
     *            name of the file to get from the SFTP server
     * @return the retrieved file
     * @throws SftpClientPoolException
     *             if a problem on the client pool occur while performing this
     *             operation
     * @throws SshAuthenticationException
     *             if the given authentication information are not valid
     * @throws IOException
     *             if any IO problem occur while sending file or connecting to
     *             server
     */
    @SuppressWarnings("unchecked")
    public DataHandler getAsAttachment(final String filePattern) throws IOException {
        final RegexFileNameFilter filter = FileNamePatternUtil.getInstance()
                .buildFileNameFilterFromWildChar(filePattern);
        // Holds the result of the GET operation
        DataHandler retrievedFile = null;
        // Retrieve all the files from the current directory
        List fileContainedWithinWorkingDir = client.ls();
        // Retrieve the files that match the given name
        for (SftpFile file : fileContainedWithinWorkingDir) {
            if ((file.isFile() && file.canRead()) && filter.accept(null, file.getFilename())) {
                retrievedFile = this.getAsDataHandler(file, client);
                break;
            }
        }
        // If the file doen't exist
        if (retrievedFile == null) {
            throw new IOException("File not found");
        }
        return retrievedFile;
    }

    public SFTPConnectionInfo getInfo() {
        return info;
    }

    /**
     * List the content of the directory specified in the SFTPConfigurationInfo
     * used to build an instance of this object. Only the file are returned,
     * directories are ignored, because this is not relevant since this
     * component does not allow the user to swich from a directory to another.
     * 
     * @return the list of the files found in the "working directory" specified
     *         the SFTPConnectionInfo object which configures this connection
     * @throws IOException
     *             if any IO problem occur while sending file or connecting to
     *             server
     */
    public List list() throws IOException {
        // The list used to store the result of the ls operation
        final List fileList = new ArrayList();
        List sftpFiles = client.ls();
        for (SftpFile file : sftpFiles) {
            if (file.isFile()) {
                if (logger.isLoggable(Level.FINE)) {
                    logger.fine("file : " + file.getFilename());
                }
                fileList.add(file.getFilename());
            }
        }
        return fileList;
    }

    /**
     * Retrieve the specified files from the SSH server.
     * 
     * @param fileFilterList
     *            the list of files to get from the SFTP server
     * @return fhe files specified in the list
     * @throws SftpClientPoolException
     *             if a problem on the client pool occur while performing this
     *             operation
     * @throws SshAuthenticationException
     *             if the given authentication information are not valid
     * @throws IOException
     *             if any IO problem occur while sending file or connecting to
     *             server
     */
    @SuppressWarnings("unchecked")
    public Map mGet(final List fileFilterList) throws IOException {
        // Holds the result of the MGET operation
        final Map dataHandlers = new HashMap();

        // Performs the MGET operation
        // Construct the fileFilters to match files read from the FTP
        // directory
        List filterList = new LinkedList();
        for (String string : fileFilterList) {
            filterList.add(FileNamePatternUtil.getInstance()
                    .buildFileNameFilterFromWildChar(string));
        }

        RegexFileNameFilter filter = FileNamePatternUtil.getInstance()
                .buildFileNameFilterFromFilters(filterList);

        final List filesContainedWithinWorkingDir = client.ls();
        for (SftpFile file : filesContainedWithinWorkingDir) {
            if ((file.isFile() && file.canRead()) && filter.accept(null, file.getFilename())) {
                dataHandlers.put(file.getFilename(), this.getAsDataHandler(file, client));
            }
        }
        return dataHandlers;
    }

    /**
     * Sends a set of files to a SFTP server.
     * 
     * @param attachments
     *            the file to be send
     * @return true if success
     * @throws SftpClientPoolException
     *             if a problem on the client pool occur while performing this
     *             operation
     * @throws SshAuthenticationException
     *             if the given authentication information are not valid
     * @throws IOException
     *             if any IO problem occur while sending file or connecting to
     *             server
     */
    public boolean mput(Map attachments) throws IOException {
        boolean result = false;
        // Process the attached files
        for (Entry attachmentEntry : attachments.entrySet()) {
            final String fileName = attachmentEntry.getKey();
            logger.fine("Start sending : " + fileName + " file on the SFTP server.");
            boolean fileExist = true;
            try {
                client.stat(fileName);
            } catch (IOException e) {
                // Exception is caught when the file doesn't exist
                fileExist = false;
            }
            if (this.info.isOverwrite() || !fileExist) {
                // Make an InputStream from the attachment
                final InputStream stream = attachments.get(fileName).getInputStream();
                client.put(stream, fileName);
                // Checks if the file has been correctly uploaded to the server
                FileAttributes transmittedFileAttributes = client.stat(fileName);
                result = transmittedFileAttributes.isFile();

                // Raises an exception if the file has not been properly sent
                if (!result) {
                    throw new IOException("Problem while sending " + fileName
                            + " on the SFTP server.");
                }
                logger.fine(fileName + " sent on the SFTP server");
            } else {
                throw new IOException("File [" + fileName + "] already exists.");
            }
        }
        return result;
    }

    /**
     * Create a new file - using the given filename - on the SFTP server, with
     * the given content.
     * 
     * @param fileName
     *            name of the file to write onto the SFTP server
     * @param content
     *            file content, as String
     * @return true if everything seems to be OK
     * @throws SftpClientPoolException
     *             if a problem on the client pool occur while performing this
     *             operation
     * @throws SshAuthenticationException
     *             if the given authentication information are not valid
     * @throws IOException
     *             if any IO problem occur while sending file or connecting to
     *             server
     */
    public boolean putString(final String fileName, final String content) throws IOException {
        boolean result = false;
        boolean fileExist = true;
        try {
            client.stat(fileName);
        } catch (IOException e) {
            // Exception is caught when the file doesn't exist
            fileExist = false;
        }
        if (this.info.isOverwrite() || !fileExist) {
            logger.fine("Start sending :" + fileName + " file on the SFTP server");
            // Makes an InputStream from the given content
            InputStream stream = new ByteArrayInputStream(content.getBytes());
            client.put(stream, fileName);
            // Checks if the file has been correctly uploaded to the server
            FileAttributes transmittedFileAttributes;
            transmittedFileAttributes = client.stat(fileName);

            result = transmittedFileAttributes.isFile();
            // Raises an exception if the file has not been properly sent
            if (!result) {
                throw new IOException("Problem while sending " + fileName + " on the SFTP server.");
            }

            logger.fine(fileName + " sent on the FTP server");
        } else {
            throw new IOException("File [" + fileName + "] already exists.");
        }
        return result;
    }

    /**
     * The sftp-client MUST be connected. This method DOES NOT close the
     * sftp-client
     * 
     * @param remoteFile
     * @param client
     *            a sftpclient, MUST be CONNECTED
     * @return the retrieved file, as a datahandler
     * @throws IOException
     *             the file is not found or FTP access problem
     */
    private DataHandler getAsDataHandler(SftpFile remoteFile, SftpClient client) throws IOException {
        DataHandler result;
        this.logger.info("start receiving file " + remoteFile.getFilename() + " from SFTP server");
        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(remoteFile
                .getAttributes().getSize().intValue());
        client.get(remoteFile.getFilename(), outputStream);
        outputStream.flush();
        logger.finest(remoteFile.getFilename() + " file received from SFTP server");
        final ByteArrayDataSource datasource = new ByteArrayDataSource(outputStream.toByteArray(),
                FileTypeMap.getDefaultFileTypeMap().getContentType(remoteFile.getFilename()));
        outputStream.close();
        datasource.setName(remoteFile.getFilename());
        result = new DataHandler(datasource);
        logger.finest(remoteFile.getFilename() + " set as DataHandler");
        return result;
    }

    /**
     * The sftp-client MUST be connected. This method DOES NOT close the
     * sftp-client
     * 
     * @param remoteFile
     * @param client
     *            a sftpclient, MUST be CONNECTED
     * @return the retrieved file, as a Source
     * @throws IOException
     *             the file is not found or SFTP access problem
     */
    private Document getAsDocument(SftpFile remoteFile, SftpClient client) throws IOException {
        final Document doc;
        if (this.logger.isLoggable(Level.FINEST)) {
            logger.finest("start receiving file " + remoteFile.getFilename() + " from FTP server");
        }
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        client.get(remoteFile.getFilename(), out);
        out.flush();
        final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        out.close();
        try {
            doc = XMLUtil.loadDocument(in);
        } catch (SAXException e) {
            throw new IOException("processed file [" + remoteFile.getFilename()
                    + "] is not a valid xml file : " + e.getMessage());
        } finally {
            in.close();
        }
        if (this.logger.isLoggable(Level.FINEST)) {
            logger.finest(remoteFile.getFilename()
                    + " file received from FTP server and set as document");
        }
        return doc;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy