Developer Notes

9. Extension Point resourceExtensionProcessor

Eclipse has developed a complex set of extension points that allow plugins to announce themselves to other plugins and allow for an exchange of information between them. As well as using extension points widely within itself, Eclipse allows any plugin develper to write Plugins that define their own extension points. Pliny takes up this opportunity with the extension point named resourceExtensionProcessor.

Any other plugin (a "client") can announce that it wishes to exchange certain kinds of data with the basic Pliny plugin uk.ac.kcl.cch.jb.pliny by announcing in its (the client's) plugin.xml that it supports the Pliny extension resourceExtensionProcessor. By doing so, information about which plugin supports this Pliny extension is recorded in Eclipse's Extension Registry which all Plugins can consult. Then, the pliny base plugin can talk to the registry to find out what other plugins support resourceExtensionProcessor, and in this way can "discover" other plugins that wish to formally interact with Pliny's basic plugin.

The relationship that this established must, of course, be expressed formally by agreed to exchange of formal methods to talk to each other. In the case the resourceExtensionProcessor extension point, the formal task the client plugin has to take on is agree to provide a class that implements the interface uk.ac.kcl.cch.jb.pliny.dnd.IResourceExtensionProcessor. Once the Pliny base plugin has discovered this client plugin, it can then use an instance of the class provided by the client to formally interact inside the client plugin.

A client plugin that wishes to use Pliny's extension point resourceExtensionProcessor must put a reference to it in its plugin.xml file. The ImageRes plugin (which contains an implementation of the Image Resource Annotation editor) takes this up, and thus contains the following bit of XML in its plugin.xml:

   <extension
         point="uk.ac.kcl.cch.jb.pliny.resourceExtensionProcessor">
         <processor class="uk.ac.kcl.cch.jb.pliny.imageRes.dnd.ImageEditorResourceExtensionProcessor"/>
   </extension>

This bit of XML announces to Eclipse that this plugin should record that it implements extension uk.ac.kcl.cch.jb.pliny.resourceExtensionProcessor by providing a class called uk.ac.kcl.cch.jb.pliny.imageRes.dnd.ImageEditorResourceExtensionProcessor. When Pliny's base plugin uk.ac.kcl.cch.jb.pliny asks Eclipse's extension registry about what plugins support its extension resourceExtensionProcessor it will find out that the ImageRes plugin does, and that the base plugin can interact with the ImageRes plugin through the class uk.ac.kcl.cch.jb.pliny.imageRes.dnd.ImageEditorResourceExtensionProcessor.

A provides certan kinds of integration between the pliny basic plugin and a client plugin. The following sections briefly introIResourceExtensionProcessorduce the kinds of integration supported and name the methods in IResourceExtensionProcessor that are involved.

Resource Types and Classes

A processor can use IResourceExtensionProcessor to announce the the basic Pliny Plugin information about the kinds of Resource classes that it supports. Two methods support this activity:

  • getMyObjectType(): Pliny design allows for client plugins to have different Pliny resource classes, but when data is loaded from the backing DB the system has to know which kind of Resource class should be created in memory to hold the data. Pliny uses the uk.ac.kcl.cch.jb.pliny.model.ObjectType recorded in the Resource as an indicator of this. Thus, a client plugin who needs a special version of a Resource must associate with it a specific ObjectType for that kind of Resource, then the client plugin should announce that it's IResourceExtensionProcessor supports resources of this type by returning the associated ObjectType with this method.
  • makeMyResource(). Although a client Plugin works with Resources and can extend them so that they record specific data relevant to the client Plugin in-memory instances of a resource are often created by the basic Pliny plugin which will not have direct access to the client classes special Resource extended class. For this reason the basic Pliny plugin always uses this method to ask the cleint plugin to create a new empty Resource class for it.

When the basic Pliny plugin reads in resource data from the backing database it will look at the ObjectType key that came in with the new resource data and check through the various IResourceExtensionProcessors it knows about to see if any of them match the ObjectType key, and therefore support this kind of resource data. If it finds one it will invoke makeMyResource() with that processor to get an empty Resource object of the appropriate class, and will load the resource data it got from the DB into it.

Content display in an reference object

When Pliny is generating a reference/annotation area it will need content to display in any reference object it creates. For Notes it knows what to show -- the textual content. However, for other kinds of data it should ask the Plugin that supports it to provide a content draw2d figure. A client plugin like the Image Resource handler will generate a thumbnail of the figure to be used for this purpose, for example.

The Pliny base plugin will use any IResourceExtensionProcessor associated with the Resource to give it a suitable figure by calling getContentFigure(). Thus, although the base Pliny plugin is generating the annotation area, through this method it has access into the client plugin to get a content image that is suitable for that particular kind of resource.

Resource Explorer Drop

New Pliny resources can be created from non-pliny data by dragging the data to the appropriate ObjectType item in the Resource Explorer display and dropping it there. If one drags a reference to an HTML page, for example and drops it on the Resource Explorer's ObjectType item "Image", then the HTML page will be harvested for suitable images and these images will be turned into Pliny resources handled by the Image Resource Plugin.

This happens because each ObjectType heading in the resource explorer can consult the set of IResourceExtensionProcessors available, to see if there is one that supports its type. If there is one, the Resource Explorer will consult method canHandleObject() passing it an object representing the dropped data type (say, an HTML file or a reference to one). If the IResourceExtensionProcessor examines this item and decides that it can import data from that kind of object it returns true and the Resource Explorer will ask the drag and drop handler to display the "can drop here" icon to the user.

If the user then proceeds to drop the item on this ObjectType heading, this is interpreted as a request to process the dropped item and create suitable Resources from it. The Resource explorer will again take the IResourceExtensionProcessor it has for this ObjectType and call processDrop() with the same input data (say, the HTML file given in our example earlier). The processor then has the task of taking the object and creating new Resource objects from it, and also do whatever else the client plugin requires to make these resource objects work properly -- with the Image Resource plugin, for example, a copy of each imported image is stored in the plugin's cache area.

Exporting and Importing Pliny data

The Resource Explorer supports the exporting of Pliny data into a PLA archive, and can process an existing PLA archive to import data. The archive is actually a ZIP file and contains not only a dump of the contents of Pliny's backing store DB (in XML format), but also other data that client plugins want to store in the archive. The cached images created by the Image Resource plugin are stored in the PLA archive, for example.

For each Resource the exporter is exporting it checks to see if there is a IResourceExtensionProcessor for it. If there is one, it calls its method getCacheElements() and gives it the resource it is currently working with. The processor's getCacheElement decides what other data it wants to write to the archive -- creating one IResourceExtensionProcessor.CacheElement for each item to be stored in the archive. When the archive gets control back it can see what data the processor wanted archived with this resource and for each item, write a file containing it to the archive. With the Image Resource plugin, for example, the method getCacheElements() will return two CacheElements -- one pointing to the image file, and a second for the associated thumbnail version.

During importing a reverse process is used. As the archive importer gets data about resources it is supposed to create it also checks to see if there is a IResourceExtensionProcessor for that kind of resource. If there is one, the importer calls the processor's method processArchiveEntries() giving it a uk.ac.kcl.cch.jb.pliny.dnd.IGetsArchiveEntries class which can, in turn, pull items from the archive for the use of the processor. The processor uses this method to get data from the archive to create whatever data is needed -- for example, for an Image Resource plugin, both the main image and the thumbnail version can be pulled from the archive and restored in the Image Resource cache.


John Bradley
Center for Computing in the Humanities
King's College London