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