
org.ow2.petals.bc.ftp.connection.WrappedFTPClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of petals-bc-ftp Show documentation
Show all versions of petals-bc-ftp Show documentation
A binding component used to transfer files using ftp
/**
* Copyright (c) 2007-2012 EBM WebSourcing, 2012-2016 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 http://www.gnu.org/licenses/
* for the GNU Lesser General Public License version 2.1.
*/
package org.ow2.petals.bc.ftp.connection;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
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.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 org.ow2.petals.component.framework.util.FileNamePatternUtil;
import org.ow2.petals.component.framework.util.XMLUtil;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import com.ebmwebsourcing.easycommons.lang.StringHelper;
/**
* This class handles a connection to the FTP server with the specified configuration parameter.
* @author Mathieu CARROLLE - EBM WebSourcing
*/
public class WrappedFTPClient extends FTPClient {
private final FTPConnectionInfo connectionInfo;
private final transient Logger logger;
public WrappedFTPClient(final FTPConnectionInfo connectionInfo, final Logger logger) {
super();
this.connectionInfo = connectionInfo;
this.logger = logger;
}
/**
* This method sets :
*
* - the working directory
* - the data connection mode (Active or Passive)
* - the type of transfer (ASCII or Binary)
*
*
* @throws IOException
*/
public void configureConnection() throws IOException {
// Working directory
boolean cd = true;
if (!StringHelper.isNullOrEmpty(connectionInfo.getDirectory())) {
cd = this.changeWorkingDirectory(connectionInfo.getDirectory());
}
if (cd == false) {
throw new IOException("Failed to change directory. Target directory : ["
+ connectionInfo.getDirectory() + "]");
}
logger.fine("FTP server working directory is : " + this.printWorkingDirectory());
// connection mode
if (connectionInfo.isPassiveMode()) {
this.enterLocalPassiveMode();
logger.fine("enter Passive mode");
}
// transfer mode
if (connectionInfo.isAsciiTransferType()) {
this.setFileType(FTP.ASCII_FILE_TYPE);
logger.fine("ascii transfer mode enable");
} else if (connectionInfo.isBinaryTransferType()) {
this.setFileType(FTP.BINARY_FILE_TYPE);
logger.fine("binary transfer mode enable");
}
}
/**
* Deleted the specified remote file.
*
* @param remoteFile
* Remote file to delete
* @throws IOException
* @throws InterruptedException
*/
public void del(final String remoteFile) throws IOException {
int numberOfTries = 0;
int maxTries = connectionInfo.getAttempt();
boolean deleted = false;
while (!deleted) {
numberOfTries++;
if (numberOfTries > maxTries) {
throw new IOException("Error occurred while deleting '" + remoteFile
+ "' file from the FTP server");
}
try {
if (this.logger.isLoggable(Level.FINE)) {
logger.fine("start deleting '" + remoteFile + "' file from the FTP server");
}
deleted = this.deleteFile(remoteFile);
} catch (IOException e) {
if (numberOfTries == maxTries) {
throw e;
} else {
this.logger.warning("An attempt to delete the file '" + remoteFile
+ "' failed : " + e.getMessage());
}
try {
Thread.sleep(connectionInfo.getDelay());
} catch (InterruptedException ex1) {
throw new IOException(ex1);
}
}
}
}
/**
* Get a file content from a FTP server.
*
* @param server
* the server
* @param port
* the port
* @param login
* the login
* @param password
* the password
* @param filePattern
* the remote file
*
* @return String
* @throws InterruptedException
* @throws SAXException
* @throws FTPBCException
* impossible to get: The file does not exist
*/
public Document get(final String filePattern) throws IOException {
Document doc = null;
int numberOfTries = 0;
final int maxTries = connectionInfo.getAttempt();
while (doc == null) {
numberOfTries++;
if (numberOfTries > maxTries) {
throw new IOException("Error occurred while getting '" + filePattern
+ "' file from the FTP server");
}
try {
logger.fine("start getting '" + filePattern + "' file from the FTP server");
final FTPFile[] files = this.listFiles(filePattern);
if (files != null && files.length > 0) {
doc = getAsDocument(files[0].getName());
} else {
throw new IOException("Can not find the specified resource");
}
} catch (IOException e) {
if (numberOfTries == maxTries) {
throw e;
} else {
this.logger.warning("An attempt to get the file '" + filePattern
+ "' failed : " + e.getMessage());
}
try {
Thread.sleep(connectionInfo.getDelay());
} catch (InterruptedException ex1) {
throw new IOException(ex1);
}
}
}
return doc;
}
public FTPConnectionInfo getConnectionInfo() {
return connectionInfo;
}
/**
* Get a file content from a FTP server.
*
* @param server
* the server
* @param port
* the port
* @param login
* the login
* @param password
* the password
* @param filePatternWildCard
* the remote file
*
* @return String
* @throws InterruptedException
* @throws FTPBCException
* impossible to get: The file does not exist
*/
public DataHandler getFileAsAttachment(final String filePatternWildCard) throws IOException {
DataHandler data = null;
int numberOfTries = 0;
final int maxTries = connectionInfo.getAttempt();
while (data == null) {
numberOfTries++;
if (numberOfTries > maxTries) {
throw new IOException("Error occurred while getting '" + filePatternWildCard
+ "' file from the FTP server");
}
try {
logger.fine("start getting '" + filePatternWildCard
+ "' file from the FTP server");
FTPFile[] files = this.listFiles(filePatternWildCard);
if (files != null && files.length > 0) {
data = getAsDataHandler(files[0]);
} else {
throw new IOException("Can not find the specified resource");
}
} catch (IOException e) {
if (numberOfTries == maxTries) {
throw e;
} else {
this.logger.warning("An attempt to get the file '" + filePatternWildCard
+ "' failed : " + e.getMessage());
}
try {
Thread.sleep(connectionInfo.getDelay());
} catch (InterruptedException e1) {
throw new IOException(e1);
}
}
}
return data;
}
/**
* Connect and log the FTP client with the current configuration
*
* @throws IOException
*/
public void connectAndLog() throws IOException {
logger.fine("create FTP connection to " + connectionInfo.getServer());
// set encoding before connect to the fTP server
this.setControlEncoding(connectionInfo.getEncoding());
this.connect(connectionInfo.getServer(), connectionInfo.getPort());
int reply = this.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
this.disconnect();
throw new IOException("connection to FTP server failed.");
}
// Login
boolean logged = this.login(connectionInfo.getUser(), connectionInfo.getPassword());
if (!logged) {
throw new IOException("authentication failed.");
}
logger.fine(connectionInfo.toString());
}
/**
* List files from FTP server
*
* @return
* @throws IOException
* @throws InterruptedException
*/
public List listFolderContent() throws IOException {
List fileList = new ArrayList();
boolean listAllFiles = false;
int numberOfTries = 0;
int maxTries = connectionInfo.getAttempt();
while (!listAllFiles) {
try {
logger.fine("start listing a directory from the FTP server");
for (FTPFile file : this.listFiles()) {
if (file.isFile()) {
fileList.add(file.getName());
}
}
listAllFiles = true;
} catch (IOException e) {
numberOfTries++;
if (numberOfTries == maxTries) {
throw e;
} else {
this.logger
.warning("An attempt to list a directory failed : " + e.getMessage());
}
try {
Thread.sleep(connectionInfo.getDelay());
} catch (InterruptedException ex1) {
throw new IOException(ex1);
}
}
}
return fileList;
}
public void mDel(List remoteFiles) throws IOException {
int numberOfTries = 0;
int maxTries = connectionInfo.getAttempt();
boolean deletedAllFile = false;
while (!deletedAllFile) {
try {
if (this.logger.isLoggable(Level.FINE)) {
logger.fine("start deleting '" + remoteFiles.toString()
+ "' file from the FTP server");
}
for (String pathname : remoteFiles) {
this.deleteFile(pathname);
}
deletedAllFile = true;
} catch (IOException e) {
if (numberOfTries == maxTries) {
throw e;
} else {
this.logger.warning("An attempt to delete the file '" + remoteFiles
+ "' failed : " + e.getMessage());
}
try {
Thread.sleep(connectionInfo.getDelay());
} catch (InterruptedException ex1) {
throw new IOException(ex1);
}
}
}
}
/**
* This method will only get files, it does not include subpath
*
* @param filePatternWildCardList
* @return
* @throws IOException
* @throws InterruptedException
*/
public Map mGet(final List filePatternWildCardList)
throws IOException {
boolean getAllFiles = false;
int numberOfTries = 0;
int maxTries = connectionInfo.getAttempt();
Map datahandlers = new HashMap<>();
// Construct the fileFilters to match files read from the FTP directory
final List fileNameFilters = new LinkedList<>();
for (final String string : filePatternWildCardList) {
fileNameFilters.add(FileNamePatternUtil.buildFileNameFilterFromWildCard(
string));
}
final FilenameFilter filter = FileNamePatternUtil.buildFileNameFilterFromFilters(fileNameFilters);
while (!getAllFiles) {
try {
if (this.logger.isLoggable(Level.FINE)) {
logger.fine("start getting files from the FTP server");
}
for (FTPFile file : this.listFiles()) {
if (file.isFile() && filter.accept(null, file.getName())) {
datahandlers.put(file.getName(), getAsDataHandler(file));
}
}
getAllFiles = true;
} catch (IOException e) {
numberOfTries++;
if (numberOfTries >= maxTries) {
throw e;
} else {
this.logger.warning("An attempt to get a file failed : " + e.getMessage());
}
try {
Thread.sleep(connectionInfo.getDelay());
} catch (InterruptedException ex1) {
throw new IOException(ex1);
}
}
}
return datahandlers;
}
/**
* Put files on the FTP server.
*
* @param attachments
* @return
* @throws IOException
* @throws InterruptedException
*/
public void mPut(Map attachments) throws IOException {
int numberOfTries = 0;
int maxTries = connectionInfo.getAttempt();
boolean transmit;
boolean isFileExist;
for (Entry entry : attachments.entrySet()) {
transmit = false;
isFileExist = false;
while (!transmit) {
if (numberOfTries == maxTries) {
throw new IOException("Error occurred while storing '" + entry.getKey()
+ "' file on the FTP server");
}
try {
logger.fine("start sending '" + entry.getKey() + "' file on the FTP server");
isFileExist = this.fileExistOnRemoteDirectory(entry.getKey());
if (!isFileExist || this.connectionInfo.isOverwrite()) {
InputStream stream = entry.getValue().getInputStream();
transmit = this.storeFile(entry.getKey(), stream);
stream.close();
} else {
// hack to stop retry policy
numberOfTries = maxTries;
throw new IOException("File [" + entry.getKey() + "] already exists");
}
if (transmit) {
logger.fine("'" + entry.getKey() + "' sent on the FTP server");
} else {
numberOfTries++;
}
} catch (IOException e) {
numberOfTries++;
if (numberOfTries >= maxTries) {
throw e;
} else {
this.logger.warning("An attempt to put the file '" + entry.getKey()
+ "' failed : " + e.getMessage());
}
try {
Thread.sleep(connectionInfo.getDelay());
} catch (InterruptedException ex1) {
throw new IOException(ex1);
}
}
}
}
}
/**
* Put the file on the FTP server.
*
* @param fileName
* @param content
* @return
* @throws IOException
* @throws InterruptedException
*/
public void putString(final String fileName, String content) throws IOException {
boolean transmit = false;
boolean fileExist = false;
int numberOfTries = 0;
int maxTries = connectionInfo.getAttempt();
while (!transmit) {
numberOfTries++;
if (numberOfTries > maxTries) {
throw new IOException("Error occurred while storing '" + fileName
+ "' file on the FTP server");
}
try {
logger.fine("start sending '" + fileName + "' file on the FTP server");
fileExist = this.fileExistOnRemoteDirectory(fileName);
if (!fileExist || this.connectionInfo.isOverwrite()) {
OutputStream ops = this.storeFileStream(fileName);
ops.write(content.getBytes());
ops.flush();
ops.close();
transmit = this.completePendingCommand();
} else {
// hack to stop retry policy
numberOfTries = maxTries;
throw new IOException("File [" + fileName + "] already exists");
}
} catch (IOException e) {
if (numberOfTries >= maxTries) {
throw e;
} else {
this.logger.warning("An attempt to put the file '" + fileName + "' failed : "
+ e.getMessage());
}
try {
Thread.sleep(connectionInfo.getDelay());
} catch (InterruptedException ex1) {
throw new IOException(ex1);
}
}
}
logger.fine("'" + fileName + "' sent on the FTP server");
}
/***
* Search if the file exist on the remote directory
*
* @param srcFileName
* Name of the file
* @param client
* @return true if the file exist on the remote directory (case-sensitive)
* @throws IOException
*/
private boolean fileExistOnRemoteDirectory(String srcFileName) throws IOException {
boolean fileExist = false;
String[] remoteFileNames = this.listNames();
for (String remoteFileName : remoteFileNames) {
if (remoteFileName.equals(srcFileName)) {
fileExist = true;
break;
}
}
return fileExist;
}
/**
* The ftp-client MUST be connected. This method DOES NOT close the
* ftp-client
*
* @param remoteFile
* @param client
* a ftpclient, MUST be CONNECTED
* @return the retrieved file, as a datahandler
* @throws IOException
* the file is not found or FTP access problem
*/
private DataHandler getAsDataHandler(FTPFile remoteFile) throws IOException {
logger.fine("start receiving file " + remoteFile.getName() + " from FTP server");
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(
(int) remoteFile.getSize());
try {
this.retrieveFile(remoteFile.getName(), outputStream);
outputStream.flush();
} catch (IOException e) {
throw e;
} finally {
outputStream.close();
}
logger.fine(remoteFile.getName() + " file received from FTP server");
final ByteArrayDataSource datasource = new ByteArrayDataSource(outputStream.toByteArray(),
FileTypeMap.getDefaultFileTypeMap().getContentType(remoteFile.getName()));
datasource.setName(remoteFile.getName());
final DataHandler result = new DataHandler(datasource);
logger.fine(remoteFile.getName() + " set as DataHandler");
return result;
}
/**
* Extract the content of the specified XML file and returned it as XML
* document
*
* @param remoteFile
* @return the retrieved file, as a Document
* @throws IOException
* the file is not found or FTP access problem
*/
private Document getAsDocument(String remoteFileName) throws IOException {
final Document doc;
if (this.logger.isLoggable(Level.FINE)) {
logger.fine("start receiving file " + remoteFileName + " from FTP server");
}
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
this.retrieveFile(remoteFileName, bos);
bos.flush();
final ByteArrayInputStream is = new ByteArrayInputStream(bos.toByteArray());
try {
doc = XMLUtil.loadDocument(is);
} catch (SAXException e) {
throw new IOException("processed file '" + remoteFileName
+ "' is not a valid xml file : " + e.getMessage());
} finally {
bos.close();
is.close();
}
if (this.logger.isLoggable(Level.FINE)) {
logger.fine(remoteFileName + " file received from FTP server and set as document");
}
return doc;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy