Dynamic Plug-ins provide the ability to insert and remove plug-ins into a running instance of Eclipse. A reusable component with the potential to be unloaded, Dynamic Plug-ins provide an easy way to help you track the comings and goings of plug-ins.
A dynamic plug-in may not remain for the life of the application, as such, it is essential to ensure that when the component goes away everything is cleaned up. When listeners are hooked on the Workbench and items are registered, they remain there after shut down, these plug-ins must be aware that they need to clean up.
The assumption that on start up, a read through of all the implementations of the extension point will be sufficient for the life of the application is false as that will not work. You must ensure that either the listener is hooked or that nothing is ever cached, so that registry changes are listened for. It is important to understand that items in the workbench are not necessarily static, they are in fact transient and could go away at any time. If you're writing a plug-in for a specific view first ensure that the view is still there.
As a plug-in developer you need to ensure that any extensions you may utilize are allowed to appear and disappear at any given point. When they disappear you should acknowledge their disappearance by cleaning up any internal structures that may represent the extensions and remove any UI artifacts that they may drive. When they appear you should augment your internal structures and possibly create new UI artifacts. Assume that your application is reading from the registry and has an extension, you create a record for it and assign its location. Upon its conclusion, you would be notified that a clean up is required. In addition, a listener will announce when new items come in and create them.
The org.eclipse.core.runtime.dynamicHelpers.IExtensionTracker and associated interfaces provide a mechanism by which plug-in developers can easily track the coming and going of extensions and manage the resources generated by such actions.
The following example assumes that you have an extension point in your plug-in called widgets and that you are using IExtensionTracker. Internally, you have WidgetDescriptors that encapsulate widget extensions and a WidgetRegistry to manage them.
public class WidgetRegistry implements IExtensionChangeHandler { public WidgetRegistry() { IExtensionTracker tracker = PlatformUI.getWorkbench() .getExtensionTracker();
IExtensionPoint point = Platform.getExtensionRegistry() .getExtensionPoint("my.plugin.namespace", "widget");
IExtension[] extensions = point.getExtensions();
// initial population
for (int i = 0; i < extensions.length; i++) { addExtension(tracker, extensions[i]);
} tracker
.registerHandler(this, tracker
.createExtensionPointFilter(point)); } public void addExtension(IExtensionTracker tracker, IExtension extension){ WidgetDescriptor descriptor = new WidgetDescriptor(extension); tracker.registerObject(extension, descriptor,
IExtensionTracker.REF_STRONG); addToInternalStructure(descriptor) } private void addToInternalStructure(WidgetDescriptor descriptor) { // registry specific logic } public void removeExtension(IExtension extension, Object[] objects) { for (int i = 0; i < objects.length; i++) { WidgetDescriptor descriptor = (WidgetDescriptor) objects[i];
removeFromInternalStructure(descriptor);
}
} private void removeFromInternalStructure(WidgetDescriptor descriptor) { // registry specific logic }
} public void dispose() { PlatformUI.getWorkbench() .getExtensionTracker().unregisterHandler(this)
} }
In this example Platform UI provides IExtensionTracker instances at various levels of the Workbench. If you're tracking objects that live for the life of the workbench you should use the tracker provided by IWorkbench.getExtensionTracker(). If your objects are relevant to particular workbench windows or pages, you should use the trackers provided by IWorkbenchWindow.getExtensionTracker() or IWorkbenchPage.getExtensionTracker(). For instance, Workbench tracks view descriptors at the Workbench level but tracks actual view instances at the workbench page level. Your handlers may be registered against particular extension points via providing an IFilter instance to IExtensionTracker.registerHandler(). Your handler will only be called when extensions matching the IFilter object are added or removed.
When an extension enters the runtime this method will be called. Your handler then has the opportunity to incorporate the new extension into its associated model. Any objects created based on the IExtension provided to this interface should be registered against the tracker via IExtensionTracker.registerObject(). When an extension leaves the runtime this method will be called. Any objects previously registered against the extension will be passed as arguments. Your handler may then clean up and dispose of the objects as necessary. It's good practice to unregister your handlers so that your registries are not leaked.