UI Plugin Services
Introduction
Each frontend plugin in itself is an independent component. All frontend plugins together however form a complete application. Within such an application context, plugins are no longer independent, and need to communicate with each other. One plugin might cause an event, on which certain other plugins might react (by performing whatever action). Yet other plugins may stay unaffected.
Sharing Models
A very simple communication mechanism is provided in the form of sharing models between plugins. When one plugin provides an IModelService (a Perspective will do this for you), others can use it to obtain their IModel and to receive "model change" notifications.
The straightforward way to use this mechanism is to subclass the RenderPlugin and override the onModelChanged() method. Whenever the model changes in one of the other plugins, it will be invoked. If the plugin needs to be redrawn in response to the model update, call redraw().
This occurs for example when the page contains a BrowserPlugin. When a node is selected on the (JCR) tree, other plugins are notified. This mechanism is e.g. used to show workflow plugins for nodes that have a workflow.
public class ExamplePlugin extends RenderPlugin { public ExamplePlugin(IPluginContext context, IPluginConfig config) { super(context, config); } @Override public void onModelChanged() { // repaint the plugin when the model has changed. redraw(); } }
Advanced Communication Patterns
More advanced interactions between plugins can be achieved by registering services and/or trackers. Any object that implements IClusterable can be registered as a service. A number of patterns have emerged in the use of this basic premise.
Whiteboard Pattern
In the whiteboard pattern, the basic principle of "don't call us, we'll call you" is applied to a client/server situation. When several clients need to be notified, they don't register themselves directly with the server. Instead, they register a listener service with the plugin context. When the clients must be notified, the server retrieves the list of listeners and notifies them.
This pattern is actually used by the model sharing implementation. Each plugin that wants to be notified of model changes registers an IModelListener. The ModelService uses these listener services whenever a model changes.
Decorator Pattern
Sometimes it is desirable to extend services with extra interfaces. An example is the ITitleDecorator; it is used by the Perspective to provide a title to display for the tabbed panel.
Available Services
Some common services are provided by the framework and can be retrieved under well-known names.
IDialogService
This service gives plugins, even those without any visual parts, the possibility to display modal dialogs. AbstractRenderService sub-classes (such as RenderPlugins) can use the #getDialogService() method to locate the service. Other usages can leverage the plugin context with the service name IDialogService.class.getName(). Showing a dialog is therefore as simple as:
IDialogService dialogService = context.getService(IDialogService.class.getName(), IDialogService.class); dialogService.show(new ExampleDialog(context, flagService));
IPluginConfigService
The IPluginConfigService makes configurations of clusters of plugins available. It can be found under the name IPluginConfigService.class.getName() . It can be used to dynamically instantiate clusters of plugins.
As an example, consider the case of multiple editors in the CMS. Each editor has its own set of plugin instances and its own (node) model. To satisfy this last requirement, each editor uses a separate ModelService, configured by the plugin that instantiates editors.