UI Plugin Architecture
Overview
The Bloomreach Content user interface uses a modular architecture built on Apache Wicket. You can extend the UI by developing plugins that add interface elements, modify the appearance, or alter functionality.
Plugin Configuration
Each plugin maintains its own configuration, which acts as an indirection layer. This layer translates plugin-specific names into application-wide or cluster-wide names. For example, when a plugin needs to access the model service, it retrieves the value for the wicket.model key. The value could be perspective.browse.model, a UUID such as 935313c9-7fcb-42e8-9465-6080eb24693b, or another unique string. The critical requirement is that the plugin providing the service registers it under the same name that consuming plugins use for lookup.
Plugin Context
When a plugin is instantiated, it receives a plugin context through its constructor. The plugin context enables interaction with the framework and supports the following operations:
- Start a new cluster
You can start new plugins by providing a cluster configuration. The plugin that initiates the cluster controls its lifecycle. For example, if the original plugin is stopped, the associated cluster is also stopped. - Retrieve, register, or unregister a service
Any object implementingIClusterablecan be registered as a service. The service receives a unique service ID, which you can use to register decorator interfaces, create a naming scope, or retrieve the service when the plugin context is unavailable. - Register or unregister a service tracker
You can register a service tracker to receive notifications when a service is registered under a specific name. Use service trackers when services may appear or disappear unpredictably, especially if you store references to services outside the call stack.
The plugin context is private to the plugin. Plugins should not share their context with other plugins. The context manages the lifecycle of services and trackers. When a plugin stops, the context automatically unregisters its services and trackers, so manual cleanup is not required.
Because the plugin context model is abstract, use base classes that handle framework interactions when possible.
Dynamic Services
In some scenarios, you may need to instantiate plugins dynamically in response to user actions. For example, the workflow plugin starts and stops clusters of plugins to display available actions for a document.
Since the lifecycle of a consumed service is managed by another plugin, you cannot assume the service will always be available. Use one of the following approaches to safely consume services:
- Use
IPluginContext.getService(name, clazz)each time you need the service. Do not store persistent references to the service. - Register a service tracker if you need to store references. When the tracker notifies you that a service is no longer available, discard the reference.
- Store an
IServiceReferenceand use it to access the service when needed. This approach is required in dialogs where the plugin context is not directly accessible. For example, you can store anIServiceReferenceto a plugin registered as a service, such as subclasses ofRenderPlugin.