Adapting

Over the past week or so, I’ve been discussing how you can make your objects adaptable into different forms. This is great for getting your objects to tightly integrate with existing parts of the Eclipse infrastructure, while remaining loosely coupled with the actual implementation. Loose coupling with tight integration is pretty powerful stuff.

A while back, I created an “Image Preview” view that displays the image (if one is available) for a file selected in the workbench (it works best for image files). The best part is that the view is completely decoupled from the Resources API. That is, it doesn’t know anything about files, directories, workspaces, or anything along those lines. By implementing the image viewer using adapters, I can “teach” my view to display an image for different kinds of selected objects by providing a new adapter. A natural extension of this is that I can use my Image Preview view in an RCP application to display an image for my domain objects (assuming that this makes sense, of course).

The Image Preview view listens to the workbench selection service. When a selection occurs in a view (such as the Package Explorer, or Navigator), the selection service notifies registered listeners (see here for more information on the selection service). When the Image Preview view is notified of the selection change, it attempts to adapt the selected object to the ImageProvider interface (which is part of my implementation). The ImageProvider is then used to obtain an image. The getImageProvider method in the Image Preview view looks like this:

private ImageProvider getImageProvider(Object object) {
	// First, if the object is an ImageProvider, use it.
	if (ImageProvider.class.isInstance(object)) return (ImageProvider)object;

	// Second, if the object is adaptable, ask it to get an adapter.
	ImageProvider provider = null;
	if (object instanceof IAdaptable)
		provider = (ImageProvider)((IAdaptable)object).getAdapter(ImageProvider.class);

	// If we haven't found an adapter yet, try asking the AdapterManager.
	if (provider == null)
		provider = (ImageProvider)Platform.getAdapterManager().loadAdapter(object, ImageProvider.class.getName());

	return provider;
}

The first step, is to see if the selected object already implements our interface. If it does, we cast and return it. If we make it to the second step, we ask the object if it is adaptable (i.e. does it implement the IAdaptable interface). If it does, we use that method to attempt to find an adapter. If that method fails (returns null), the AdapterManager is used. Ultimately, this method may fail to find an appropriate adapter and return null.

The selected object doesn’t need to know anything about the Image Preview view. Conversely, my Image Preview view knows nothing about files. The adapter interface knows about both (it really only knows about the ImageProvider interface).

I’m curious about the history of this little pattern (which is repeated many times). It seems that there is an opportunity here to have a higher-level API in the AdapterManager that takes all of these steps, but I assume that there is a good (or at least historical) reason for it being the way that it is.

Note that there are two different ways to ask the AdapterManager to adapt an object: getAdapter or loadAdapter (which is highlighted in the snippet). Both methods will find programmatically- and declaratively-registered adapters, however the getAdapter method will only find declaratively-registered adapters if the bundle that contributes them has been activated. The loadAdapter will load and activate the bundle (if required) as part of the process.

This entry was posted in Eclipse 101, Examples. Bookmark the permalink.

5 Responses to Adapting

  1. Evan Williams says:

    Hi Wayne,

    thanks for the informative article.

    I’ve recently had cause to experiment with your Image Viewer plug-in … it was really handy for auto-magically viewing images from a photo management catalog. It’s an amazing feeling when you just “plug” these together and it just works!

    I’ve a little write-up on my blog here … http://evans-stuff.blogspot.com/2007/11/photoshop-elements-explorer.html

    cheers,
    Evan

  2. boris says:

    Hi Wayne,
    Can you help?
    Problem: In RCP View (Eclipse 3.4M3) “is included” Excel file.
    It can be changed, but how it can be saved? “File” menu is not seen!
    Boris Starchev – teacher (bstarchev@ru.acad.bg)

    public class ViewExcel extends ViewPart {
    public static final String ID = “ExcelTest.view”;
    private OleClientSite site;
    private File file=
    new File(“C:/Documents and Settings/boris starchev/Desktop/12a05_3_4/ChemaTest9class.xls”);
    public void createPartControl(Composite parent) {
    System.out.println(file);
    try {
    OleFrame frame = new OleFrame(parent, SWT.NONE);
    site = new OleClientSite(frame, SWT.NONE, “Excel.Sheet” , file);
    } catch (SWTError e) {
    System.out.println(“Unable to open activeX control”);
    return;
    }
    }
    public void setFocus() {
    // Have to set the focus see https://bugs.eclipse.org/bugs/show_bug.cgi?id=207688
    site.setFocus();
    }
    }
    (This was from http://www.vogella.de/articles/EclipseMicrosoftIntegration/article.html)

    See a picture:
    http://bstarchev_eclipse.googlegroups.com/web/071105ProblemExcel.doc?gda=sY61w0cAAADh93w6-WNHpVf2W8Z-lM4zin2jnIJoR-atINEtg1iMA2G1qiJ7UbTIup-M2XPURDRTEhUGje7nwTm_l0BqJy_YZJfXf-Vqa3UfNpgE1vLlHg

  3. Pingback: Adapting with generics « Rambling about…

  4. Pingback: Eclipse hints, tips, and random musings » Blog Archive » “20 Things”

Leave a comment