package net.sf.cotta.ftp; import net.sf.cotta.system.FileSystem; import net.sf.cotta.PathContent; import net.sf.cotta.TIoException; import net.sf.cotta.TPath; import net.sf.cotta.ftp.client.commonsNet.CommonsNetFtpClient; import net.sf.cotta.io.OutputMode; import org.apache.commons.net.ftp.FTPClient; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.nio.channels.FileChannel; public class FtpFileSystem implements FileSystem { private final FtpClient ftpClient; private static final TPath ROOT_DIR = TPath.parse("/"); private static final TPath CURRENT_DIR = TPath.parse("."); public FtpFileSystem(FtpClient ftpClient) { this.ftpClient = ftpClient; } public FtpFileSystem(FTPClient ftpClient) { this(new CommonsNetFtpClient(ftpClient)); } public final boolean fileExists(TPath path) { return pathExists(path); } public final void createFile(TPath path) throws TIoException { try { OutputStream outputStream = ftpClient.store(path); try { outputStream.write(new byte[0]); } finally { outputStream.close(); } } catch (IOException e) { throw new TIoException(path, "Create file failed", e); } } public final void deleteFile(TPath path) throws TIoException { try { ftpClient.delete(path); } catch (IOException e) { throw new TIoException(path, "Delete file failed", e); } } public boolean dirExists(TPath path) { return isConstantPath(path) || pathExists(path); } public final void createDir(TPath path) throws TIoException { try { ftpClient.makeDirectory(path); } catch (IOException e) { throw new TIoException(path, "Create dir failed", e); } } public final InputStream createInputStream(final TPath path) throws TIoException { try { return ftpClient.retrieve(path); } catch (TIoException e) { throw e; } catch (IOException e) { throw new TIoException(path, "Failed to create input stream", e); } } public final OutputStream createOutputStream(TPath path, OutputMode mode) throws TIoException { try { if (mode.isOverwrite()) { return ftpClient.store(path); } if (mode.isAppend()) { return ftpClient.append(path); } throw new FtpFileSystemException("Failed to create output stream, as mode unkown"); } catch (IOException e) { throw new TIoException(path, "Failed to create output stream", e); } } public final FileChannel createOutputChannel(TPath path, OutputStream outputStream) throws TIoException { throw new UnsupportedOperationException("FtpFileSystem"); } public final void deleteDirectory(TPath path) throws TIoException { try { ftpClient.delete(path); } catch (IOException e) { throw new TIoException(path, "Delete directory faild", e); } } public final void moveFile(TPath source, TPath destination) throws TIoException { try { ftpClient.rename(source, destination); } catch (IOException e) { throw new TIoException(source, "Moving file failed, target <" + destination.toPathString() + ">", e); } } public final void moveDirectory(TPath source, TPath destination) throws TIoException { try { ftpClient.rename(source, destination); } catch (IOException e) { throw new TIoException(source, "Moving directory failed, target <" + destination.toPathString() + ">", e); } } public final String pathString(TPath path) { return path.toPathString(); } public final long fileLength(TPath path) { FtpFile[] ftpFiles = listFtpDirectory(path.parent()); for (FtpFile ftpFile : ftpFiles) { if (ftpFile.getPath().equals(path)) { return ftpFile.getSize(); } } throw new FtpFileSystemException("get file length failed, as we can not find it on its parent directory"); } public final File toJavaFile(TPath path) { throw new UnsupportedOperationException("FtpFileSystem"); } public final String toCanonicalPath(TPath path) { throw new UnsupportedOperationException("FtpFileSystem"); } public final FileChannel createInputChannel(TPath path) throws TIoException { throw new UnsupportedOperationException("FtpFileSystem"); } public long fileLastModified(TPath path) { throw new UnsupportedOperationException("FtpFileSystem"); } public int compare(TPath path1, TPath path2) { return path1.compareTo(path2); } public boolean equals(TPath path1, TPath path2) { return path1.equals(path2); } public int hashCode(TPath path) { return path.hashCode(); } public URI toUri(TPath path) { throw new UnsupportedOperationException(); } private boolean isConstantPath(TPath path) { return path.equals(ROOT_DIR) || path.equals(CURRENT_DIR); } private boolean pathExists(TPath path) { FtpFile[] existingFiles = listFtpDirectory(path.parent()); if (existingFiles == null) { return false; } for (FtpFile existingFile : existingFiles) { if (existingFile.getPath().equals(path)) { return true; } } return false; } public PathContent list(TPath path) throws TIoException { FtpFile[] ftpFiles = listFtpDirectory(path); PathContent content = new PathContent(ftpFiles.length); for (FtpFile ftpFile : ftpFiles) { if (FtpFileType.DIRECTORY.equals(ftpFile.getFileType())) { content.addDirectoryPath(ftpFile.getPath()); } else if (FtpFileType.FILE.equals(ftpFile.getFileType())) { content.addFilePath(ftpFile.getPath()); } } return content; } private FtpFile[] listFtpDirectory(TPath path) { try { return ftpClient.list(path); } catch (IOException e) { throw new FtpFileSystemException(e); } } private class FtpFileSystemException extends RuntimeException { public FtpFileSystemException(IOException cause) { super(cause); } public FtpFileSystemException(String message) { super(message); } } }