Overview
By default, JBoss VFS support 2 kinks of file system:
- Real file system
- Zip achieves(zip, war, ear, jar, etc)
to support ftp file system, we need extend JBoss VFS add a ftp file system implementation, then mount it to a specific mount point of VFS, this article will demonstrate this.
More details about JBoss VFS refer to VFS User Guide and Source Code.
FtpFileSystem Implementation
A FTPClient from commons-net is used to communicate with FTP Server, the FtpFileSystem implementation as below:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.CodeSigner;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executors;
import org.apache.commons.net.ftp.FTPClient;
import org.jboss.vfs.TempFileProvider;
import org.jboss.vfs.VFS;
import org.jboss.vfs.VirtualFile;
import org.jboss.vfs.spi.FileSystem;
public class FtpFileSystem implements FileSystem {
private FTPClient client;
private boolean isMount = false;
private VirtualFile tmpPoint;
public FtpFileSystem(FTPClient ftpClient) {
this.client = ftpClient;
}
@Override
public File getFile(VirtualFile mountPoint, VirtualFile target) throws IOException {
if(!isMount) {
VirtualFile tmp = mountPoint.getChild("tmp");
TempFileProvider provider = TempFileProvider.create("tmp", Executors.newScheduledThreadPool(2));
VFS.mountTemp(tmp, provider);
this.tmpPoint = tmp;
isMount = true;
}
if(!tmpPoint.getChild(target.getName()).exists()) {
download(tmpPoint.getChild(target.getName()));
}
return tmpPoint.getChild(target.getName()).getPhysicalFile();
}
private void download(VirtualFile file) throws IOException {
file.getPhysicalFile().createNewFile();
OutputStream out = new FileOutputStream(file.getPhysicalFile());
boolean completed = this.client.retrieveFile(file.getName(), out);
if(!completed) {
throw new IOException("Faile to download " + file);
}
}
@Override
public InputStream openInputStream(VirtualFile mountPoint, VirtualFile target) throws IOException {
return new FileInputStream(getFile(mountPoint, target));
}
@Override
public boolean isReadOnly() {
return false;
}
@Override
public boolean delete(VirtualFile mountPoint, VirtualFile target) {
if(this.tmpPoint != null && this.tmpPoint.getChild(target.getName()).exists()) {
this.tmpPoint.getChild(target.getName()).delete();
}
try {
return this.client.deleteFile(target.getName());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public long getSize(VirtualFile mountPoint, VirtualFile target) {
try {
return getFile(mountPoint, target).length();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public long getLastModified(VirtualFile mountPoint, VirtualFile target) {
try {
return getFile(mountPoint, target).lastModified();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean exists(VirtualFile mountPoint, VirtualFile target) {
String name = target.getName();
if(this.tmpPoint != null && this.tmpPoint.getChild(name).exists()) {
return true;
}
try {
String[] names = this.client.listNames();
boolean exists = false;
if (names != null && names.length > 0){
for(String n : names) {
if(n.equals(name)) {
exists = true;
break;
}
}
}
return exists;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean isFile(VirtualFile mountPoint, VirtualFile target) {
try {
return getFile(mountPoint, target).isFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean isDirectory(VirtualFile mountPoint, VirtualFile target) {
try {
if(this.client.cwd(target.getPathName()) == 250) {
return true;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return false;
}
@Override
public List<String> getDirectoryEntries(VirtualFile mountPoint, VirtualFile target) {
try {
return Arrays.asList(this.client.listNames(target.getPathName()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public CodeSigner[] getCodeSigners(VirtualFile mountPoint, VirtualFile target) {
return null;
}
@Override
public void close() throws IOException {
this.client.disconnect();
}
@Override
public File getMountSource() {
return null;
}
@Override
public URI getRootURI() throws URISyntaxException {
try {
return new URI("ftp", this.client.printWorkingDirectory() + "!/", null);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
Mount FtpFileSystem
Assuming remote ftp file system path is '/home/kylin/vsftpd', then mount FtpFileSystem as below:
FtpFileSystem ftpFileSystem = new FtpFileSystem(ftpClient);
VirtualFile mountPoint = VFS.getChild("/home/kylin/vsftpd");
VFS.mount(mountPoint, ftpFileSystem);
Note that, once mount success, we can use the path '/home/kylin/vsftpd/<any path to file>' to navigate and get the files under ftp server.
Example: get file from ftp server
"marketdata-price.txt" are the file exist in ftp server, its absolute path is "/home/kylin/vsftpd/marketdata-price.txt", use the VFS API to get this file as below:
VirtualFile marketdata = VFS.getChild("/home/kylin/vsftpd/marketdata-price.txt");
marketdata.isDirectory();
marketdata.isFile();
marketdata.getSize();
marketdata.getLastModified();
marketdata.openStream();
Example: delete file from ftp server
"marketdata-price.csv" are the file exist in ftp server, its absolute path is "/home/kylin/vsftpd/marketdata-price.csv", use the VFS API to delete this file as below:
VirtualFile marketdata = VFS.getChild("/home/kylin/vsftpd/marketdata-price.csv");
marketdata.delete();
Comments