Element factories are used to recreate workbench model objects from data that was saved during workbench shutdown.
Before we look closely at the element factory extension, we need to review a general technique that is used throughout the platform to add plug-in specific behavior to common platform model objects.
When browsing the various workbench classes, you will notice that many of the workbench interfaces extend the IAdaptable interface.
Plug-ins use adapters to add specific behavior to pre-existing types in the system. For example, the workbench may want resources to answer a label and an image for display purposes. We know that it's not good design to add UI specific behavior to low-level objects, so how can we add this behavior to the resource types?
Plug-ins can register adapters that add behavior to pre-existing types. Application code can then query an object for a particular adapter. If there is one registered for it, the application can obtain the adapter and use the new behaviors defined in the adapter.
By providing a facility to dynamically query an adapter for an object, we can improve the flexibility of the system as it evolves. New adapters can be registered for platform types by new plug-ins without having to change the definitions of the original types. The pattern to ask an object for a particular adapter is as follows:
//given an object o, we want to do "workbench" things with it. if (!(o instanceof IAdaptable)) { return null; } IWorkbenchAdapter adapter = (IWorkbenchAdapter)o.getAdapter(IWorkbenchAdapter.class); if (adapter == null) return null; // now I can treat o as an IWorkbenchAdapter ...
If there is no adapter registered for the object in hand, null will be returned as the adapter. Clients must be prepared to handle this case. There may be times when an expected adapter has not been registered.
The workbench uses adapters to obtain UI information from the base platform types, such as IResource. Adapters shield the base types from UI-specific knowledge and allow the workbench to evolve its interfaces without changing the definitions of the base.
Without adapters, any class that might be passed around in the workbench API would have to implement the UI interfaces, which would increase the number of class definitions, introduces tight coupling, and create circular dependencies between the core and UI classes. With adapters, each class implements IAdaptable and uses the adapter registry to allow plug-ins to extend the behavior of the base types.
Throughout the workbench code, you'll see cases where a platform core type is queried for an adapter. The query is used to obtain an object that knows how to answer UI oriented information about the type.
When the workbench is shut down by the user, it must save the current state of the IAdaptable objects that are shown in the workbench. An object's state is stored by saving the primitive data parameters of the object in a special format, an IMemento. The id of a factory that can recreate the object from an IMemento is also stored and the data is saved in the file system.
When the platform is restarted, the workbench finds the element factory associated with the IMemento's factory id. It finds the factory by checking the plug-in registry for contributions to the org.eclipse.ui.elementFactories extension.
The markup is pretty simple. We just have to specify the id of the factory and the corresponding class that implements the factory.
The following code snippet is from the workbench plugin.xml.
<extension point="org.eclipse.ui.elementFactories"> <factory class="org.eclipse.ui.internal.model.ResourceFactory" id="org.eclipse.ui.internal.model.ResourceFactory"> </factory> <factory class="org.eclipse.ui.internal.model.WorkspaceFactory" id="org.eclipse.ui.internal.model.WorkspaceFactory"> </factory> <factory class="org.eclipse.ui.part.FileEditorInputFactory" id="org.eclipse.ui.part.FileEditorInputFactory"> </factory> <factory class="org.eclipse.ui.internal.dialogs.WelcomeEditorInputFactory" id="org.eclipse.ui.internal.dialogs.WelcomeEditorInputFactory"> </factory> <factory class="org.eclipse.ui.internal.WorkingSetFactory" id="org.eclipse.ui.internal.WorkingSetFactory"> </factory> </extension>