
fi.evolver.utils.ftp.FtpConnection Maven / Gradle / Ivy
package fi.evolver.utils.ftp;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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 fi.evolver.utils.CommunicationException;
import fi.evolver.utils.UriUtils;
public class FtpConnection extends RemoteConnection {
private final FTPClient client = new FTPClient();
private InputStream input = null;
public static FtpConnection connect(URI uri, int connectTimeoutMs, int readTimeoutMs) throws CommunicationException {
if (uri == null)
throw new NullPointerException("Connection URI can not be null");
if (!"ftp".equals(uri.getScheme()))
throw new CommunicationException("The %s protocol is not supported", uri.getScheme());
FtpConnection connection = new FtpConnection();
connection.initConnection(uri, connectTimeoutMs, readTimeoutMs);
return connection;
}
private FtpConnection() { }
@Override
public List list(Pattern filter) throws CommunicationException {
finishTransaction();
try {
FTPFile[] files = client.listFiles();
List results = new ArrayList<>();
for (FTPFile file: files) {
if (filter != null) {
Matcher m = filter.matcher(file.getName());
if (!m.matches())
continue;
}
results.add(new RemoteFile(
file.getName(),
file.getSize(),
toLocalDateTime(file.getTimestamp()),
file.isDirectory()));
}
return results;
}
catch (IOException e) {
throw new CommunicationException(e, "Listing files failed");
}
}
private static LocalDateTime toLocalDateTime(Calendar calendar) {
if (calendar == null)
return null;
ZoneId zoneId = ZoneId.systemDefault();
TimeZone timeZone = calendar.getTimeZone();
if (timeZone != null)
zoneId = timeZone.toZoneId();
return LocalDateTime.ofInstant(calendar.toInstant(), zoneId);
}
@Override
public InputStream download(String remote) throws CommunicationException {
finishTransaction();
try {
InputStream temp = client.retrieveFileStream(remote);
if (temp == null)
throw new IOException("Retrieving file stream failed: " + client.getReplyString());
input = new FtpInputStream(temp);
return input;
}
catch (IOException e) {
throw new CommunicationException(e, "Initiating download of %s failed: %s", remote, client.getReplyString());
}
}
@Override
public void rename(String from, String to) throws CommunicationException {
finishTransaction();
try {
if (!client.rename(from, to))
throw new CommunicationException("Renaming %s to %s failed: %s", from, to, client.getReplyString());
}
catch (IOException e) {
throw new CommunicationException(e, "Renaming %s to %s failed", from, to);
}
}
@Override
public void upload(String remote, InputStream local) throws CommunicationException {
finishTransaction();
try {
if (!client.storeFile(remote, local))
throw new CommunicationException("Uploading %s failed: %s", remote, client.getReplyString());
}
catch (IOException e) {
throw new CommunicationException(e, "Uploading file to %s failed", remote);
}
}
@Override
public String pwd() throws CommunicationException {
finishTransaction();
try {
String dir = client.printWorkingDirectory();
if (dir == null)
throw new CommunicationException("Checking current directory failed");
return dir;
}
catch (IOException e) {
throw new CommunicationException(e, "Checking current directory failed");
}
}
@Override
public void cd(String directory) throws CommunicationException {
finishTransaction();
try {
if (!client.changeWorkingDirectory(directory))
throw new CommunicationException("Changing directory to %s failed: %s", directory, client.getReplyString());
}
catch (IOException e) {
throw new CommunicationException(e, "Changing directory to %s failed", directory);
}
}
@Override
public void rm(String remote) throws CommunicationException {
try {
if (!client.deleteFile(remote))
throw new CommunicationException("Deleting file %s failed: %s", remote, client.getReplyString());
}
catch (IOException e) {
throw new CommunicationException(e, "Deleting file %s failed", remote);
}
}
@Override
public void rmdir(String remote) throws CommunicationException {
try {
if (!client.removeDirectory(remote))
throw new CommunicationException("Deleting file %s failed: %s", remote, client.getReplyString());
}
catch (IOException e) {
throw new CommunicationException(e, "Deleting file %s failed", remote);
}
}
@Override
public void mkdir(String remote) throws CommunicationException {
try {
if (!client.makeDirectory(remote))
throw new CommunicationException("Creating directory %s failed: %s", remote, client.getReplyString());
}
catch (IOException e) {
throw new CommunicationException(e, "Creating directory %s failed", remote);
}
}
@Override
public void close() throws CommunicationException {
finishTransaction();
try {
client.disconnect();
}
catch (IOException e) {
throw new CommunicationException(e, "Disconnection failed");
}
}
public void finishTransaction() throws CommunicationException {
if (input != null) {
try {
input.close();
}
catch (IOException e) {
throw new CommunicationException(e, "Downloading file failed");
}
}
}
private void initConnection(URI uri, int connectTimeoutMs, int readTimeoutMs) throws CommunicationException {
String host = "unspecified server";
try {
host = uri.getHost();
int port = uri.getPort() == -1 ? 21 : uri.getPort();
String user = UriUtils.getUserName(uri);
String password = UriUtils.getPassword(uri);
if (user == null)
user = "anonymous";
if (password == null)
password = "";
client.setDefaultTimeout(connectTimeoutMs);
client.connect(host, port);
client.setSoTimeout(readTimeoutMs);
client.setDataTimeout(Duration.ofMillis(readTimeoutMs));
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
throw new CommunicationException("FTP connection failed: %s", client.getReplyString());
}
if (!client.login(user, password))
throw new CommunicationException("FTP login failed: %s", client.getReplyString());
client.enterLocalPassiveMode();
if (!client.setFileType(FTP.BINARY_FILE_TYPE)) {
client.disconnect();
throw new CommunicationException("Setting FTP file type failed: %s", client.getReplyString());
}
}
catch (CommunicationException e) {
throw e;
}
catch (Exception e) {
throw new CommunicationException(e, "FTP connection to %s failed", host);
}
}
private class FtpInputStream extends InputStream {
private final InputStream in;
boolean closed = false;
public FtpInputStream(InputStream in) {
this.in = in;
}
@Override
public int available() throws IOException {
return in.available();
}
@Override
public void close() throws IOException {
if (closed)
return;
try {
in.close();
if (!client.completePendingCommand())
throw new CommunicationException("Downloading file failed");
}
finally {
input = null;
closed = true;
}
}
@Override
public synchronized void mark(int readLimit) {
in.mark(readLimit);
}
@Override
public boolean markSupported() {
return in.markSupported();
}
@Override
public int read() throws IOException {
return in.read();
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
return in.read(b, off, len);
}
@Override
public int read(byte[] b) throws IOException {
return in.read(b);
}
@Override
public synchronized void reset() throws IOException {
in.reset();
}
@Override
public long skip(long n) throws IOException {
return in.skip(n);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy