Tapestry Component Library Auto-Discovery


After working on application component auto-discovery (see earlier blog postings) I wanted to get Tapestry to auto-discover Tapestry component libraries.

It wasn't difficult and I got my application specification down to:

<description><![CDATA[ A Tapestry Test Application ]]></description> <property name="org.apache.tapestry.disable-caching" value="true"/> <property name="org.apache.tapestry.visit-class" value="com.mjhenderson.users.tapestry.Visit"/> <service name="users.membership" class="com.mjhenderson.users.tapestry.engine.MembershipEngineService"/> </application>

The two component library references are gone, auto-discovery adds them to the application specification.

Auto-discovery works by resolving all files with the name tapestry-library.properties on the class path and reading each on in to a java.util.Properties. The file needs 2 property settings in it:

tapestry.library.id=springinspector tapestry.library.specification-path=/com/mjhenderson/tapestry/springinspector/springinspector.library

I modified the org.apache.tapestry.ApplicationServlet class to perform library auto-discovery after reading the application specification file:

private void addAutoDiscoveredLibrarySpecifications(IApplicationSpecification appSpec) { LibraryLocator locator = new LibraryLocator(); Iterator libraries = locator.getAutoDiscoveredLibraries().iterator(); while (libraries.hasNext()) { LibraryLocator.LibraryInfo info = (LibraryLocator.LibraryInfo)libraries.next(); if (appSpec.getLibrarySpecificationPath(info.id) == null) { appSpec.setLibrarySpecificationPath(info.id, info.path); } } }

LibraryLocator does the work:

public List getAutoDiscoveredLibraries() { List list = new ArrayList(); try { Enumeration resources = Thread.currentThread().getContextClassLoader().getResources("tapestry-library.properties"); while (resources.hasMoreElements()) { URL url = (URL)resources.nextElement(); Properties p = readProperties(url); String id = p.getProperty("tapestry.library.id"); String path = p.getProperty("tapestry-library.specification-path"); if (id != null && path != null) { LibraryInfo info = new LibraryInfo(); info.id = id; info.path = path; list.add(info); } } } catch (IOException ex) { ex.printStackTrace(); } return list; }

I expect that the HiveMind integration in Tapestry 3.1 will make this type of auto-discovery of libraries and components a standard feature with a much more elegant implementation. I hope so, reducing configuration requirements to a bare minimum, with reasonable defaults can lower the barrier to entry for developers wanting to take Tapestry out for a spin. This lack of configuration requirements could even be a distinguishing factor of Tapestry.

Until then I'll use a patched tapestry-3.0.jar and a patched tapestry-contrib-3.0.jar or apply a source patch to Tapestry.