The Witheboard Pattern is a variation or at least a similar concept for the Obsercer pattern, replacing the commonly used Java Listener Pattern in a highly dynamic World, where Event Sources have to deal with the abrupt dissappearance of Event Listeners and vice versa (this aspect is often neglected in traditional Applications, since there is full control of the lifecycles of the Event Source and all Event Listeners). In a more dynamic world, where collaborators could come and go at any time, there may should be some compensation logic to handle this fact.
When applying the Witheboard Pattern, you adress this issue by delegating the tracking of the collaborator’s lifcycles to a ‘tracking component’ that’s provided by the ‘infrastructure’. In an OSGi environment, this is typically done by the Service Registry.
Again you will have a kind of Listener interface, that is implemented by some classes that are interessted in the occurence of some Events. Those classes may be included in one more Bundles. On the other side, there is an Event Source that typically resides in another Bundle.
The funny thing is now, that the Event Source doesn’t offer some methods like addLister() or removeListener() anymore. Accordingly, Listeners don’t get attached directly to the Event Source. Instead they get registered as a kind of ‘Service’ at the OSGi Service Registry while using the Listener interface as ‘Service Interface’.
Now every time the Event Source wants to publish a certain Event, it will look up all currently available Listeners by retrieving them (by their exposed ‘Service Interface’) from the Service Registry, so only those Listeners get informed, that are currently available.
On the other side, the registration of Listeners is decoupled from the Event Source (since there is at least only a reference to the Service Registry for the ‘Registrator’ of a Listener), so the disappearance of the Event Source doesn’t affect a Listener (Listeners then simply won’t receive Events for the downtime of the Event Source). More interestingly, even if the Event Source will be available again, there is no need to track that fact (by the Listeners ‘Registrator’) and to attach the Listeners again to the Event Source, since there is only an indirect link between them via the Service Registry (that will keep track): The Event Source will simply ask for all availabe Listeners again for publishing the occurance of another event.
An interesting issue is the question on how to identify the relationship between an Event Source and the relating Listener interface it serves by publishing appropriate Events. Since the Event Source doesn’t express it’s capability to serve a specific Listener Interface any longer – remember, now there aren’t such methods like addListener( aSpecificListenerInterface) or removeListener( aSpecificListenerInterface ) – it’s not clear which Listener Interface to use or if a certain class acts as an Event Source at all. Because of the mentioned decoupling, this relationship can’t be detected by looking at a class’ Interface and therefor has to be ‘documented’ in some other ways.
In a first solution, you could provide the Listener Interface along with the Event Source within the same Bundle. But there may be some other Event Sources within the same Bundle, exposing their own Listener interfaces, so it may be not clear which Listener Interface belong to which Event Source. Of course you could place the Listener Interface into the same package as the Event Source, but this may bind the Listener Interface to the Event Source way to close.
On the other side, you could place the Listener Interface within an own Bundle, so that it may be re-usable by different Event Sources (if you take a look at the Swing API, this is not an uncommon scenario). Again, there is no direct relationship between such a Listener Interface and an Event Source. In addition to that, Event Sources may have to face the problem of identifying the appropriate set of Listener instances to notify at runtime, if there are at least two Event Sources using the same Listener Interface. Of course you could use some properties (provided by the OSGi Specification – you are allowed to optionally expose a set of properties along with a Service at the Service Registry for further distinction resp. enhanced service description) to filter and distinguish between the Listeners registered for Event Source One and those registered for Event Source Two, but that will even increase the amount of information that have to be expressed for a certain Event Source: You now not only have to document the Listener Interface that is going to be served by an Event Source but additionally all the properties along with the claimed property values that are appropriate for that certain Event Source.
For now, i see no appropriate solution for this issue. Of cource, you could always express the supported Listener Interfaces and claimed Properties by using some kind of documentation, like Javadoc or any external form of documents. But since the documentation and the underlying implemantation is very highly ‘decoupled’ (they may run out of sync, having no instruments to automatically detect that fact), it’s not quite a statisfying solution.
Do you have some more appropriate suggestions?