HiveMind Integration

Tapestry 4.0 is intimately integrated into the HiveMind microkernel. Building a complex system onto a dependency injection microkernel such as HiveMind has many benefits; the code is easier to write, test and maintain. HiveMind's flexible approach makes it easy to provide extension points ... many of the common kinds of customizations in Tapestry 3.0 that required code changes (such as subclassing BaseEngine ) are now accomplished by providing objects via a HiveMind module descriptor for your application.

In fact, you should not think of HiveMind as just Tapestry's infrastructure, but as infrastructure for your application as well. A very succesful design pattern in Tapestry is to keep pages and components very simple, and delegate as much logic as possible out to HiveMind services. Listener methods should ideally do little more than marshall together the correct information and pass it over to a service (this sidesteps most of the issues with testing pages and components, which tend to be abstract).

Warning:

Tapestry 4.0 is not compatible with HiveMind 1.0 . Tapestry 4.0 may only be used with HiveMind 1.1. The compatibility issues are related to the underlying Javassist library; HiveMind 1.0 and Tapestry 3.0 use one version of the library, HiveMind 1.1 and Tapestry 4.0 use a more recent version.

Injecting Services

But how to get access to those services? Tapestry allows you to inject your pages and components with HiveMind services (or other objects accessible from within a HiveMind registry). This is accomplished via the <inject> specification element:

<page-specification class=". . .">

  <inject property="mailSender" object="service:mymodule.MailSender"/>
  
</page-specification> 

This would create a new property on your page, mailSender, that would be connected to a HiveMind service, mymodule.MailSender. The object attribute is an object reference , consisting of a prefix ("service:") followed by a locator . The prefix identifies how the locator should be interpreted; in this case, as a full qualified service id. HiveMind itself defines a base set of prefixes , to which Tapestry adds the following:

Prefix Description Example
app-property The locator is the name of a property that is resolved using:
  • The application specification's <meta> properties
  • The servlet's <init-parameter> elements
  • The servlet context's <init-parameter> elements
  • The delegate property source (a <extension> )
  • A HiveMind symbol
app-property:org.apache.tapestry.template-extension
engine-service The locator is the name of an engine service (an instance of IEngineService ). engine-service:page
global-property The locator is the name of global property, defined as a servlet <init-parameter>, a servlet context <init-parameter>, or a HiveMind symbol. global-property:org.apache.tapestry.disable-caching
infrastructure The locator is the name of a property provided by the tapestry.Infrastructure service; this service provides access to the key Tapestry services. infrastructure:applicationSpecification
Note: More prefixes are forthcoming. You can access the service via the property. You can do this from a <binding> element, or from within the template, using an OGNL expression. For example: ognl:mailSender.sendMail(to, subject) would read the to and subject properties of the page, and pass them to the sendMail() method of the mymodule.MailSender service (which has been injected into the mailSender property). From within Java code, you can define an abstract accessor method:
public abstract class MyPage extends BasePage
{
  public abstract MailSender getMailSender();
  
  . . .
        
  public void myListener(IRequestCycle cycle)
  {
    String to = getTo();
    String subject = getSubject();
          
    getMailSender().sendMail(to, subject);
          
     . . .
  }
}

Bootstrapping the Registry

The ApplicationServlet is responsible for initializing HiveMind's Registry on startup. Note: The ApplicationServlet takes over all the roles usually supplied by HiveMind's HiveMindFilter. This includes the initial creation of the HiveMind Registry (as discussed), but also includes cleaning up thread local information at the end of each request, and shutting down the Registry when the servlet is destroyed.

The ApplicationServlet will create a default registry, consisting of all META-INF/hivemodule.xml files found on the servlet classpath. This is how the base HiveMind and Tapestry module descriptors are loaded. You may package module deployment descriptors inside libraries or even in your application WAR.

In addition, two other descriptors will be parsed if they exist:

  • /WEB-INF/ applicationId /hivemodule.xml
  • /WEB-INF/hivemodule.xml
Note: The descriptor will not be recognized if it is located in META-INF/ in the context root of a web application however it will if it is under the WEB-INF/ locations. The META-INF/ location is specific to libraries. Both of these files exist in the web application context; the applicationId is the name of the application servlet, as given in web.xml deployment descriptor (this is only useful in the very rare case that you package more than one Tapestry application in a single web application).

By subclassing ApplicationServlet and overriding the constructRegistry() method, you can easily extend these rules, loading additional descriptors from arbitrary locations.