Note this blog is obsolete, see https://www.manorrock.com/blog/ for the current blog On the #jsf IRC channel Ryan asked how you can get it so the JSF runtime loads resource library contracts from the filesystem. This blog entry will show you how.

BE AWARE this code is a proof of ]]> The FilesystemResourceHandler public class FilesystemResourceHandler extends ResourceHandlerWrapper { private final File resourceDirectory; private final ResourceHandler resourceHandler; public FilesystemResourceHandler(ResourceHandler resourceHandler) { this.resourceHandler = resourceHandler; this.resourceDirectory = new File("/tmp/contracts"); } @Override public ResourceHandler getWrapped() { return resourceHandler; } @Override public Resource createResource(String resourceName, String libraryName) { List activeContracts = FacesContext.getCurrentInstance().getResourceLibraryContracts(); if (!resourceName.startsWith("filesystemResourceHandler")) { if (activeContracts != null) { for(File file : this.resourceDirectory.listFiles()) { for (String contract : activeContracts) { if (contract.equals(file.getName())) { if (libraryName != null) { return new FilesystemResource(resourceDirectory, contract, libraryName, resourceName); } else { return new FilesystemResource(resourceDirectory, contract, null, resourceName); } } } } } } else { resourceName = resourceName.substring(resourceName.indexOf("/") + 1); String contract = resourceName.substring(0, resourceName.indexOf("/")); resourceName = resourceName.substring(resourceName.indexOf("/") + 1); return new FilesystemResource(resourceDirectory, contract, null, resourceName); } return resourceHandler.createResource(resourceName, libraryName); } @Override public boolean isResourceURL(String url) { if (url.contains("filesystemResourceHandler")) { return true; } return resourceHandler.isResourceURL(url); } } The FilesystemResource public class FilesystemResource extends Resource { private final File baseDir; private final String contract; public FilesystemResource(File baseDir, String contract, String libraryName, String resourceName) { this.baseDir = baseDir; this.contract = contract; setLibraryName(libraryName); setResourceName(resourceName); } @Override public InputStream getInputStream() throws IOException { /* * Be aware you need to make sure you clean libraryName and resourceName here, * this code is merely a proof of concept! */ File resourceFile = new File(baseDir, contract + "/" + (getLibraryName() != null ? getLibraryName() + "/" : "") + getResourceName()); return new FileInputStream(resourceFile); } @Override public Map getResponseHeaders() { return Collections.EMPTY_MAP; } @Override public String getRequestPath() { /* * Note this URL should take prefix mapping or extension mapping into account, * right now assuming you have mapped /faces/* */ return FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath() + "/faces/javax.faces.resource/filesystemResourceHandler/" + contract + "/" + (getLibraryName() != null ? getLibraryName() + "/" : "") + getResourceName(); } @Override public URL getURL() { return null; } @Override public boolean userAgentNeedsUpdate(FacesContext context) { return true; } } The faces-config.xml <?xml version='1.0' encoding='UTF-8'?> <faces-config version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"> <application> <resource-handler>filesystemrlc.FilesystemResourceHandler</resource-handler> </application> </faces-config> Note the code for this sample is available as part of the Glassfish samples (see the subversion repository at https://svn.java.net/svn/glassfish-samples~svn/trunk/ws/javaee7/jsf/filesystemrlc/) And that is it. Enjoy!