VFS
Commons Virtual File System(VFS)は、さまざまな種類のファイルシステムに統一された方法でアクセスするための抽象化レイヤを提供しています。このコンポーネントを使えば、1つまたは複数のファイルシステムに同時に接続できます。これはLinuxオペレーティングシステムのmount機能に似ています。
VFSがサポートするファイルシステムは次のとおりです。
- ローカルファイル ― ローカルのファイルおよびフォルダ(file://)
- zip、jar、tar、tgz、tbz2、gzip、bzip2 ― 多様な圧縮形式を透過的に処理可能(zip://、jar://、など)
- CIFS ― sambaサーバーまたはWindowsの共有ファイル(smb://)
- FTP ― FTPサーバー(ftp://)
- HTTPおよびHTTPS(http://)
- SFTP ― SSHまたはSCPサーバー(sftp://)
- テンポラリファイル(tmp://)
- WebDAV ― Web-based Distributed Authoring and Versioning(webdav://)
- クロスローダの提供するリソース ― ローディングクラスまたはクラスローダを使った他のリソース(res://)
サポートされているプロトコルURIの完全な構文についてはこちらを、高レベルでのこのAPIの用法についてはこちらをご覧ください。
このコンポーネントは、種類の異なるファイルに対してシームレスにアクセスする必要があるアプリケーションで非常に役立ちます。たとえば、デスクトップ検索ツールがその代表的な例です。ユーザーは、デスクトップ検索ツールを使って、さまざまな形式のファイルから特定のファイルまたはファイルコンテンツを検索します。Windows Explorerのような機能をJavaアプリケーションに組み込む場合にもこのコンポーネントが利用できます。
ここで紹介するサンプルアプリケーションでは、Commons VFSを利用して、フォルダだけでなくzipおよびjarファイルにも対応した検索を行います。このサンプルにユーザーインターフェイスはありませんが、テストケースを使ってその動作を確認できます。このサンプルとテストケースは「in.co.narayanan.commons.vfs」パッケージに含まれています。サンプルアプリケーションを実行するには、ソースアーカイブをダウンロードしてCommon VFSライブラリ作成用のAntビルドスクリプトを実行します。このAntスクリプトは、依存関係のある他のライブラリファイルもダウンロードできる優れモノです。in.co.narayanan.commons.vfs.TestSearchBuddyというJUnitテストケースクラスを実行するとサンプルアプリケーションが起動します。
TCommons VFSを用いる基本的な考え方は、サポートされているファイルの種類ごとにプロバイダを作成して、DefautFileSystemManagerのインスタンス(以降はマネージャとして参照されます)に追加するというものです。以降の処理では、managerのresolveFileメソッドを使って、該当するFileObjectのインスタンスへの参照を取得する必要があります。このmanagerとFileObjectには他にも役に立つメソッドがたくさんあるので、javadocを読んでおいて損はありません。以降では、検索ツールにおけるCommons VFS APIの使い方を説明します。
リスト6は、DefaultFileSystemManagerクラスの初期化に用いるin.co.narayanan.commons.vfs.SearchBuddyクラスのコードの一部です。
/** * Initialize the DefaultFileSystemManager to support * file, zip and jar providers. A virtual file system * is created and passed to the SearchableVirtualFileSystem * decorator class. * * @throws SearchException Error in initializing the file * FileSystemManager */ private void init() throws SearchException { defFileSysMgr = new DefaultFileSystemManager(); try { defFileSysMgr.addProvider( "file", new DefaultLocalFileProvider()); defFileSysMgr.addProvider( "zip", new ZipFileProvider()); defFileSysMgr.addProvider( "jar", new JarFileProvider()); defFileSysMgr.init(); // Create the virtual file system VirtualFileSystem vfs = (VirtualFileSystem)defFileSysMgr .createVirtualFileSystem("vfs://").getFileSystem(); searchableVfs = new SearchableVirtualFileSystem(vfs); } catch (FileSystemException e) { throw new SearchException( "Unable to initialize the FileSystemManager.", e); } }
太字の部分は、ローカルファイルシステム、zipファイル、jarファイルを検索するためのプロバイダを追加するコードです。このコードはVirtualFileSystemクラスのインスタンスを作成します。作成したインスタンスは他のファイルシステムのマウントに使用されます(この詳細とSearchableVirtualFileSystemクラスについては後述)。
リスト7は、テストケースクラスTestSearchBuddyの一部です。このコードは、サンプルアプリケーションを使ってどのようにファイル検索を行うかを示しています。
/** * Adds the folder, zip, and a jar file to search * * @throws Exception Error in the test. */ public void testSearchInZips() throws Exception { SearchBuddy searchTool = new SearchBuddy(); searchTool.addSearchableZip("testroot.zip"); searchTool.addSearchableJar("testjar.jar"); searchTool.addSearchableFolder("."); System.out.println("Searching for news.txt"); searchTool.search("news", "txt"); System.out.println("Searching for Range.class"); searchTool.search("range", "class"); System.out.println("Searching for test.xml"); searchTool.search("test", "xml"); System.out.println("Searching for *.properties"); searchTool.search(null, "properties"); searchTool.close(); }
太字の行は、検索対象のzipファイルとjarファイルを追加する部分です。このsearchメソッドの呼び出し時には、検索するファイル名と拡張子を与えます。
リスト8は、SearchBuddyクラスのコードの一部です。このコードは、各種ファイルを仮想ファイルシステムにマウントする方法を示しています。
/** * Mount a zip file to the searchable virtual * file system. * * @param pathToFolder Absolute or relative path to the zip file. * @throws SearchException Error while adding the zip file * to the virtual file system. */ public void addSearchableZip(String pathToZip) throws SearchException { File zipFile = new File(pathToZip); if(!zipFile.exists()) { throw new SearchException("Invalid zip file path"); } try { FileObject zipFileObject = defFileSysMgr.toFileObject(zipFile); searchableVfs.addJunction("/" + zipFile, defFileSysMgr.resolveFile("zip:" + zipFileObject + "!/")); } catch (FileSystemException e) { throw new SearchException( "Unable to add zip file to the virtual file system", e); } }
このzipファイルのマウントは、VirtualFileSystemクラスのaddJunctionメソッドを呼び出すことで行われます。この接合箇所(またはマウントポイント)はデコレータクラスSearchableVirtualFileSystemにキャッシュされ、後の検索処理で呼び出されます。
リスト9は、マウントされたファイルシステムを検索するコードです。
Class SearchBuddy /** * Delegate the search call to the Searchable virtual file * system decorator. * * @param fileNamePart Name of the file. * @param extension Extension to search * @throws SearchException Error from the VirtualFileSystem when searching for file. */ public void search(String fileNamePart, String extension) throws SearchException { searchableVfs.search(fileNamePart, extension); } Class SearchableVirtualFileSystem /** * Iterate the junctions to search for the given file name. * * @param fileNamePart File name to search * @param extension Extension to search * @throws SearchException */ public void search(String fileNamePart, String extension) throws SearchException { try { Iterator<String> searchPoints = junctions.iterator(); FileObject matchingFiles[]; while(searchPoints.hasNext()) { String searchPoint = searchPoints.next(); FileObject searchRoot = vfs.resolveFile(searchPoint); filter.setExtension(extension); filter.setFileNamePart(fileNamePart); matchingFiles = searchRoot.findFiles(filter); for(FileObject file : matchingFiles) { System.out.println("Result:" + file); } } } catch (FileSystemException e) { throw new SearchException("Search failed", e); } }
このsearchメソッドは、マウントされたファイルシステムに対して繰り返し処理を行い、ルートを特定して、FileObjectクラスのfindFilesメソッドを検索フィルタ付きで呼び出します。検索結果はコンソールに出力されます。このデコレータクラスSearchableVirtualFileSystemの主な役割は、マウントされたファイルシステムを記憶しておくことです。他のメソッドを呼び出す権限は、ラップされたVirtualFileSystemのインスタンスに委譲されます。
このサンプルアプリケーションのソースファイルには、説明用のコメントが十分に書かれているので、詳しくはそちらをご覧ください。
Common VFSのフレームワークをデスクトップおよびサーバーアプリケーションに用いれば、コンシューマプログラムとファイルタイプ固有のコードとを完全に分離できます。その結果、アプリケーションのモジュール性が高まり、開発が容易になります。
