2009/04/15 - Apache HiveMind has been retired.

For more information, please explore the Attic.

Apache > HiveMind
Font size:      

Overriding a Service

It is not uncommon to want to override an existing service and replace it with a new implementation. This goes beyond simply intercepting the service ... the goal is to replace the original implementation with a new implementation. This occurs frequently in Tapestry where frequently an existing service is replaced with a new implementation that handles application-specific cases (and delegates most cases to the default implementation).

Plans are afoot to refactor Tapestry 3.1 to make considerable use of HiveMind. Many of the ideas represented in HiveMind germinated in earlier Tapestry releases.

In HiveMind 1.0, overriding a service required a "trick", involving indirection via a HiveMind symbol. This has changed in HiveMind 1.1, which supports service overrides directly.

In HiveMind 1.1, the service implementation (the <create-instance> or <invoke-factory>) inside the <service-point> is considered the default implementation.

The default implementation may be overriden by contributing an alternate service implementation using the <implementation> element. This may occur in the same module or in an entirely different module. This new implementation replaces the default implementation.

It is still an error to provide more than one overriding implementation.

If you wish your service to not be overridable, you may simply leave the implementation out of the <service-point> and provide an <implementation> element of your own. This will prevent any other module from overriding the service implementation.

A service must be visible (i.e., not private) to be overriden.

Step One: A service with default implementation

To describe this technique, we'll start with a ordinary, every day service. In fact, for discussion purposes, there will be two services: Consumer and Provider. Ultimately, we'll show how to override Provider. Also for discussion purposes, we'll do all of this in a single module, though (of course) you can as easily split it up across many modules.

To begin, we'll define the two services, and set Provider as a property of Consumer:

<module id="ex.default" version="1.0.0" package="ex.override">
  <service-point id="Provider" interface="Provider">
    <create-instance class="impl.ProviderImpl"/>
  <service-point id="Consumer" interface="Consumer">
      <construct class="impl.Consumer">
        <set-service property="provider" service-id="Provider"/>

Step Two: Add the override

An <implementation> element will override the default implementation from the <service-point>:

<module id="ex.override" version="1.0.0">

  <implementation service-id="ex.default.Provider">
    <create-instance class="impl.OverrideProviderImpl"/>

The Consumer service will get the functionality of the Provider service from the OverrideProviderImpl (instead of the original ProviderImpl). ProviderImpl will never be instantiated, just OverrideProviderImpl.