Friday, January 11, 2013

Access resources in Java archives with Virtual File System (cross-application sever solution)

During my work on a custom JSF library I was looking for a way how to read the metadata from composite components in order to create a nice self-documented library. Based on this great article from Ed Burns I implemented a nice documentation framework which extracts all metadata from the VDL. Main idea:
FacesContext fc = FacesContext.getCurrentInstance();
ViewDeclarationLanguage vdl = fc.getApplication().getViewHandler().getViewDeclarationLanguage(fc, "/views/home.xhtml");
Resource ccResource = fc.getApplication().getResourceHandler().createResource(resourceName, libraryName);
BeanInfo metadata = vdl.getComponentMetadata(context, ccResource);
PropertyDescriptor attributes[] = metadata.getPropertyDescriptors();
// read metadata for cc:attributes, cc:clientBehavior, cc:valueHolder, cc:actionSource, cc:facet
The createResource method above expects the resource name and library name to access the metadata of a composite component. The library name is known. Assume the composite components are placed in a JAR file under the folder /META-INF/resources/com/foo That means, the library name is com/foo. The problem is to get names of all resources below the com/foo. Resources are XHTML files as composite components. For instance, for this structure
the resource names would be mycomponent1.xhtml and mycomponent1.xhtml. Without file extensions, they are the same as tag names of composite components. Is there a simple and reliable way to read these names from a WAR archive? Yes, sure, there is a simple method to read resources located in one Java archive from another Java archive. JBoss has Virtual File System (VFS). A good documentation can be found here. Please don't confuse it with Apache Commons VFS. These are different things with perhaps the same goal. In JBoss 6 / 7 application servers, if we read JAR files from the classpath, URLs start with vfs (meaning virtual file system) and not with file as usually. So that JBoss VFS is very handy here because it is exactly for vfs handling. The implemented approach is also working with all other application servers. I tested successful:
  • JBoss 6 / 7
  • Jetty 8
  • GlassFish 3
  • Tomcat 7
  • WebLogic 12
The next method shows the approach. To get an URL for the interested JAR file, we need to know any Java class in this JAR file. This can be a marker interface or any other interface, abstract class as well. Obtained Class object can be passed into the method along with the library name.
public void extractMetadata(Class clazz, String libraryName) throws IOException, URISyntaxException {
  VirtualFile virtualFile;
  Closeable handle = null;
  URL url = clazz.getProtectionDomain().getCodeSource().getLocation();
  String protocol = url.getProtocol();

  if ("vfs".equals(protocol)) {
    URLConnection conn = url.openConnection();
    virtualFile = (VirtualFile) conn.getContent();
  } else if ("file".equals(protocol)) {
    virtualFile = VFS.getChild(url.toURI());

    File archiveFile = virtualFile.getPhysicalFile();
    TempFileProvider provider = TempFileProvider.create("tmp", Executors.newScheduledThreadPool(2));
    handle = VFS.mountZip(archiveFile, virtualFile, provider);
  } else {
    throw new UnsupportedOperationException("Protocol " + protocol + " is not supported");

  List<VirtualFile> files = virtualFile.getChild("/META-INF/resources/" + libraryName).getChildren();
  List<String> resourceNames = new ArrayList<String>(files.size());
  for (VirtualFile ccFile : files) {

  if (handle != null) {

  FacesContext fc = FacesContext.getCurrentInstance();
  ViewDeclarationLanguage vdl = fc.getApplication().getViewHandler().getViewDeclarationLanguage(fc,

  for (String resourceName : resourceNames) {
    Resource ccResource = fc.getApplication().getResourceHandler().createResource(resourceName, libraryName);
    BeanInfo metadata = vdl.getComponentMetadata(fc, ccResource);
    // extract metadata
As I said, supporting of two URL protocols, vfs and file, was enough for me to get it working on all modern app. servers. The main goal of this method is collecting VirtualFile instances below a certain folder. VirtualFile allows to get other infos such as size, name, path, whether the object is a file or directory, etc. It allows to get children und provides many other traversal operations. For the file protocol, we have to mount the archive file in the Virtual File System (like in UNIX). Once mounted, the archive structure is accessible like a normal file system. The call virtualFile.getChild("/META-INF/resources/" + libraryName).getChildren() returns all children (VirtualFile instances) below our /META-INF/resources/com/foo/. We iterate through and collect resource (file) names.


  1. Hi Oleg, I bought the EBook PRimeFaces CookBook today but it not coming with capters 11 and 12
    Chapter 11, Writing Custom Components
    Chapter 12, PrimeFaces Extensions in Action
    What happens to that chapters??? Sorry if i wrote here i dont know how contact you. Thanks!

  2. Hi Sebastian. First, thanks for buying the book.

    The Packt Publishing told us that the current book's size has exceeded the planned size and they offer two last chapters as bonus for free downloading. I think you can download the last two chapters as PDFs from the book's page, somewhere here

    I think the book should contain this information too. If not, let me know, I will ask Packt.

  3. Yes i read the table of contents of the book and they put two links to download the chapters, but the links are not available yet. I send an email to them. Thanks for the anwser!

  4. Thanks for this post. I would like to add that I had to use the following dependency:



Note: Only a member of this blog may post a comment.