
org.ow2.petals.bc.sftp.connection.WrappedSftpClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of petals-bc-sftp Show documentation
Show all versions of petals-bc-sftp Show documentation
A binding component used to transfer files using secure ftp
/**
* 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;
}
}