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).
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.
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> <service-point id="Consumer" interface="Consumer"> <invoke-factory> <construct class="impl.Consumer"> <set-service property="provider" service-id="Provider"/> </invoke-factory> </service-point> </module>
Step Two: Add the override
<module id="ex.override" version="1.0.0"> <implementation service-id="ex.default.Provider"> <create-instance class="impl.OverrideProviderImpl"/> </implementation> </module>
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.