package ua.pp.bizon.cripto.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import ua.pp.bizon.cripto.file.IFile;
import ua.pp.bizon.cripto.file.IPath;
import ua.pp.bizon.cripto.file.Path;
public class FileUtilFtpImpl extends Path implements IFile, IPath {
public FileUtilFtpImpl(String path, String username, String password, String host) {
super(Place.FTP, path, username, password, host);
}
private static Log log = LogFactory.getLog(FileUtilFtpImpl.class);
public byte[] read() throws IOException {
FTPClient client = getClient();
client.setFileType(FTPClient.BINARY_FILE_TYPE);
String[] pathes = this.getPath().replaceAll("\\\\", "/").split("/");
String filename = pathes[pathes.length - 1];
cwdFtpTo(client, true);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
client.retrieveFile(filename, outputStream);
outputStream.close();
byte buffer[] = outputStream.toByteArray();
client.disconnect();
log.debug("read ftp done");
return buffer;
}
protected FTPClient getClient() throws IOException {
FTPClient client = new FTPClient();
log.debug("connect to host " + getHost());
client.connect(getHost());
log.debug("login using username " + getUsername());
if (!client.login(getUsername(), getPassword())){
throw new IOException("user is not login, code " + client.getReplyCode() + ", message: " + client.getReplyString());
}
return client;
}
public void write(String filename, byte[] data) throws IOException {
log.debug("FTP WRITE: to = " + this + ", filename = " + filename + ", data.length = " + data.length);
FTPClient client = getClient();
client.setFileType(FTPClient.BINARY_FILE_TYPE);
cwdFtpTo(client, true);
if (filename.isEmpty()) {
filename = getPath().substring(getPath().lastIndexOf('/') + 1);
log.debug("FTP WRITE: new filename = '" + filename + "'");
}
log.debug("rescheck if file exist");
int size = 0;
FTPFile[] files = client.listFiles();
for (FTPFile i : files) {
if (i.getName().equals(filename)) {
log.debug("File " + i.getName() + " exist, appending");
if (i.getSize() > Integer.MAX_VALUE) {
log.error("Sorry, we not support files bigger than " + Integer.MAX_VALUE + " bytes");
throw new RuntimeException("Sorry, we not support files bigger than " + Integer.MAX_VALUE + " bytes");
}
size = (int) i.getSize();
}
}
log.debug("FTP WRITE STARTED");
long start = System.currentTimeMillis();
log.trace("clientappendfile=" + client.appendFile(filename, new ByteArrayInputStream(data, size, data.length - size)));
log.trace("client responce code:" + client.getReplyCode() + ", string:" + client.getReplyString());
long end = System.currentTimeMillis();
log.debug("FTP WRITE FINISHED, time = " + (end - start) + ", speed: " + ((data.length * 1000) / (128 * (end - start))) + "kbps");
if (client.getReplyCode() != 226) {
log.error("client error code:" + client.getReplyCode() + ", string:" + client.getReplyString());
throw new IOException(client.getReplyString());
}
client.disconnect();
log.trace("save to ftp done");
}
/**
* go to directory where file should be append. <br>
* if to.getPath() end with / - it is directory. if not - last part of name
* is filename.
*
* @param to
* @param client
* @param create
* @param name
* @return
* @throws IOException
*/
protected boolean cwdFtpTo(FTPClient client, boolean create) throws IOException {
String normalizedTo = getPath().replaceAll("\\\\", "/");
String[] pathes = normalizedTo.split("/");
// we get filename from origin file
boolean isDirectory = normalizedTo.charAt(normalizedTo.length() - 1) == '/';
if (pathes.length > 0) {
for (int i = 0; isDirectory ? (i < pathes.length) : (i < pathes.length - 1); i++) {
if (!pathes[i].isEmpty()) {
log.trace("Ftp client: we at: " + client.printWorkingDirectory() + ", go to \'" + pathes[i] + "'");
int reply = client.cwd(pathes[i]);
if (reply > 400) {
if (create) {
log.info("error cwd to " + pathes[i] + ", code: " + reply + " , message: " + client.getReplyString());
log.debug("try creating directory " + pathes[i]);
log.trace("create directory is " + client.makeDirectory(pathes[i]) + ", message: " + client.getReplyString());
log.trace("cwd is " + client.cwd(pathes[i]) + ", " + client.getReplyString());
} else {
log.warn("error cwd to " + pathes[i] + ", code: " + reply + " , message: " + client.getReplyString());
return false;
}
}
log.trace("cwd is " + reply + ", " + client.getReplyString());
log.trace("Ftp client: we at: " + client.printWorkingDirectory());
}
}
}
return true;
}
public boolean exists() throws IOException {
log.debug("exist : " + this);
FTPClient client = getClient();
String[] pathes = getPath().replaceAll("\\\\", "/").split("/");
boolean find = false;
if (pathes.length > 0) {
for (int i = 0; i < pathes.length - 1; i++){
log.trace("Ftp client: we at: " + client.printWorkingDirectory() + ", go to \'" + pathes[i] + "'");
int reply = client.cwd(pathes[i]);
if (reply >= 400) {
log.warn("exist cwd " + pathes[i] + " responce code : " + client.getReplyCode() + ", reply: " + client.getReplyString());
return false;
}
log.trace("exist responce code : " + client.getReplyCode() + ", reply: " + client.getReplyString());
}
FTPFile files[] = client.listFiles();
for (FTPFile f : files) {
if (f != null) {
find |= pathes[pathes.length - 1].equals(f.getName());
} else {
log.warn("exist: listfiles() return null");
}
}
}
return find;
}
public boolean writable() {
// TODO Auto-generated method stub
return true;
}
public boolean isDirectory() throws IOException {
String normalizedTo = getPath().replaceAll("\\\\", "/");
boolean isDirectory = normalizedTo.charAt(normalizedTo.length() - 1) == '/';
if (isDirectory == true)
return true;
FTPClient client = getClient();
isDirectory = cwdFtpTo(client, false);
if (isDirectory == false) {
client.disconnect();
return isDirectory;
} else {
isDirectory = client.changeWorkingDirectory(normalizedTo.split("/")[normalizedTo.split("/").length - 1]);
client.disconnect();
return isDirectory;
}
}
public List<IPath> ls() throws IOException {
FTPClient client = getClient();
cwdFtpTo(client, true);
List<IPath> rezult = new LinkedList<IPath>();
FTPFile[] names = client.listFiles();
for (FTPFile i : names) {
rezult.add(new FileUtilFtpImpl(getPath() + i.getName() + (i.isDirectory() ? File.separatorChar : ""), getUsername(), getPassword(), getHost()));
}
client.disconnect();
return rezult;
}
public IPath mkdir(String lastPathName) throws IOException {
log.debug("FTP mkdir: to=" + this + ", lastPathName=" + lastPathName);
FTPClient client = getClient();
cwdFtpTo(client, true);
if (!client.makeDirectory(lastPathName) && client.getReplyCode() != 550) {
String message = "error during mkdir ,code : " + client.getReplyCode() + ", reply: " + client.getReplyString();
log.warn(message);
} else {
log.debug("mkdir responce code : " + client.getReplyCode() + ", reply: " + client.getReplyString());
}
return new FileUtilFtpImpl(getPath() + lastPathName + File.separatorChar, getUsername(), getPassword(), getHost());
}
@Override
public boolean delete() throws IOException {
log.debug("ftp delete file " + getPath());
boolean res = false;
FTPClient client = getClient();
if (isDirectory()) {
for (IPath i : ls()) {
res |= !i.delete();
}
res |= client.deleteFile(getPath());
log.debug("ftp delete file " + getPath() + " reply code: " + client.getReplyCode() + ", reply string: " + client.getReplyString());
client.disconnect();
return !res;
} else {
try {
return client.deleteFile(getPath());
} finally {
log.debug("ftp delete file " + getPath() + " reply code: " + client.getReplyCode() + ", reply string: " + client.getReplyString());
client.disconnect();
}
}
}
}