Extension points

Extension points are the mechanism that Eclipse uses to allow the plugins to extend and modify other plugins' behavior. The main goal of the extension point concept is to provide a loosely-coupled architecture, exposing a few interfaces that can be implemented by other plugins. Both the extension points and its implementations are declared in the plugin.xml file.

The Eclipse platform provides a number of these extension points to allow plugins to contribute to various elements of the IDE. We will take a look at some of these extension points throughout this chapter, but a complete list of them can be found in the eclipse documentation, which can be found at http://help.eclipse.org/indigo/topic/org.eclipse.platform.doc.isv/reference/extension-points/index.html.

Our Hello World plugin implements one of these extension points. Let's see how it looks like by opening the Extensions tab in the plugin manifest editor.

Extension points

The Extensions tab shows us that, in order to add a button to the toolbar or a new entry to a menu, our plugin implements an extension point called org.eclipse.ui.actionSets. You can have more information about this extension point by selecting it in the extensions list and clicking on Show extension point description.

Declaring an extension point

Currently, our HelloWorldPlugin project only implements extension points provided by other plugins, but doesn't declare any extension points itself. Let's learn how to do it by expanding our Hello World plugin to declare one. We will create an extension point that allows other plugins to provide the message displayed when clicking on the toolbar button.

To create a new extension point, select the Extension Points tab in the plugin manifest editor and click on the Add button in it. You will be prompted to provide three properties: ID, Name, and Schema. The ID is an internal unique identifier of your extension point. To guarantee its uniqueness, you might want to use the reverse domain name notation to create the ID, containing the domains from less to more specific to which your extension point belongs. Let's use com.packt.messageProvider as ID. As you fill this property, the Schema is automatically filled with the same content, followed by the .exsd extension. The Point Name property is a human-readable name for the extension point. Let's use Message provider here. When you're done, click on Finish. A new editor called schema editor will be opened. The following screenshot shows an example of schema editor:

Declaring an extension point

Schemas are XML files that describes extension points. These files are identified by a .exsd extension and, just like we did with plugin.xml, build.properties, and MANIFEST.MF files, we will use an editor to add content to it instead of editing it directly. The schema editor contains three horizontal tabs: Overview, Definition, and Source.

The first horizontal tab contains a basic description of your plugin. It also allows you to add documentation to your extension point, which will be shown directly in the Eclipse interface, making it easy for other developers to find information about how to implement your extension point. Remember the org.eclipse.ui.actionSets description that we saw in the Extensions tab? That's where it comes from. It's very important to thoroughly describe your extension point, as well as provide usage examples and API information.

Now, we have to describe what the extension point contains, that is, what other plugins can provide to our plugin. For this, we have to add new elements to the extension point. Open the Definition tab of the schema editor to see a list of the extension point's elements.

Click on New Element and change the new element's name to hello_message. You can add a small description to the element. Now add an attribute to this element by selecting it and clicking on New Attribute. Rename it to value. The other properties of the attribute allow you to choose the type that must be provided (string, Boolean, resource, Java classes, or identifiers). In our case, we want the extensions to provide a string. Your Definition tab should look as follows:

Declaring an extension point

Once the element is defined, we must declare how it composes the extension point. If we had another type of message (a goodbye_message, for example), we could require that the extension point implementation had one or more of each. Element compositions are achieved by adding choices and sequences to the "extension" element. Choices are an "or" composition, while sequences are an "and" composition. These elements can be used together to create more sophisticated compositions.

Since we just want one hello_message element per extension point implementation, let's add a new sequence to the extensions element by selecting it and clicking on New Sequence. Configure both Min Occurrences and Max Occurrences to be 1. Now, right-click on the Sequence entry, and select new | hello_message to declare that we need a hello_message element implementation.

Choices work in a very similar fashion. Add a choice to extension element and add elements to this choice. If any of the elements inside the choice are satisfied, the extension point is successfully implemented.

Providing interfaces

One of the most utilized mechanisms of extension points is to provide interfaces that can be implemented by other plugins. To give an example of how this works, let's modify our extension point a little: instead of requiring a string from other plugins, we'll ask for a class that implements a IMessageProvider interface.

Let's start by creating the interface in our plugin. The interface must be placed inside a package that will be exported in order to be implemented by other plugins, so make sure you create a new package to store the interface. Create a new interface in the project's src folder called IMessageProvider.java with the following content:

public interface IMessageProvider {

    public String getHelloMessage();

}

As you can see, the interface only requires a getHelloMessage() method that returns a string to be implemented.

Now let's modify the extension point's schema to require an interface implementation instead of a string. To begin with, the name "value" doesn't make much sense anymore, so let's change it to message_provider. Now change the Type property from string to Java. Two new properties will appear: Extends and Implements. Since we are providing an interface, let's fill the Implements field (remember that classes are extended and interfaces are implemented). Click on the Browse button and select our IMessageProvider. Remember that you can use the filter to easily find it. Click on OK.

The following screenshot shows how our extension point will look in the end:

Providing interfaces

Plugins do not externalize source packages by default. This means that the interface will not be visible to other plugins, thus making it impossible to be implemented. To export the package that contains the interface, we will switch to the Runtime tab of the plugin manifest editor. Click on the Add button under the Exported Packages section, select the package that contains the interface, and click on OK.

Using extension points implementation in code

Once the extension point is declared, code in our plugin must be modified in order to utilize what other plugins are providing through it. In our example plugin, this means switching a hardcoded Hello World message for a message provided by an extension point implementation.

Let's take a look at where in the code the Hello World message is actually being displayed. The following piece of code is in the SampleAction class, which has been generated by the Hello World plugin project template:

  public void run(IAction action) {
         MessageDialog.openInformation(
                window.getShell(),
                "HelloWorldPlugin",
                "Hello, Eclipse world");
  }

This is where we'll work. The first step of utilizing the content coming from the extension points is verifying if there are extensions available and, if there's more than one, which extension the plugin should use. Keep in mind that the whole idea of extension points is to decouple plugins, so your plugin should not crash if there are no implementations to your extension point.

A registry of the available extension point implementations is provided by the Eclipse platform. Once you have it, your code must verify for implementations for your specific extension point, and then look for the elements you need.

This is an example of how the run method should be refactored in order to utilize the message coming from the extension point:.

public void run(IAction action) {

    String helloMessage = null; 
    IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
    IConfigurationElement[] elements = extensionRegistry.getConfigurationElementsFor("com.packt.messageProvider");
    try{
          for (IConfigurationElement element : elements) {
                Object object = element.createExecutableExtension("message_provider");
                if (object instanceof IMessageProvider){
                      IMessageProvider messageProvider = (IMessageProvider)object;
                      helloMessage = messageProvider.getHelloMessage();
                }
          }
    } catch (CoreException e){
          e.printStackTrace();
    }

    if(helloMessage == null){
          helloMessage = "No providers found";
    }

    System.out.println(helloMessage);
    MessageDialog.openInformation(
          window.getShell(),
          "HelloWorldPlugin",
          helloMessage);
}

In the preceding code, we use the getExtensionRegistry static method from the Platform class to get an IExtensionRegistry object that contains all the information about extension points available in the platform. We then use this object to get all the configuration elements available for the com.packt.messageProvider extension point. Note that there's no real concern on which extension should be used in case there's more than one it will simply iterate through every configuration element available and assign it to the helloMessage variable. There's a fallback in the case where no extensions are found and we get a printed message "No providers found". So regardless of the number of implementations available to our extension point, our plugin code will execute just fine.

Implementing an extension point

Now that we have created the extension point, let's create a new plugin that implements it. Start by creating a new plugin project named MessageProvider. We don't want to use any templates this time, so unmark the Create a plugin using one of the templates checkbox in the Templates page of the new plugin project wizard.

Before we start working with the extension point, we have to declare that the MessageProvider plugin depends on HelloWorldPlugin, If there's no HelloWorldPlugin in the platform, there's no extension point to implement and MessageProvider plugin is pointless. To declare the dependency, let's open the plugin manifest editor for the MessageProvider project and switch to the Dependencies tab. Click on the Add button in the Required Plug-ins section and type HelloWorldPlugin. The following screenshot shows how the Dependencies tab should look like:

Implementing an extension point

Now we have to declare that our plugin contains an implementation of the messageProvider extension point. Switch to the Extensions tab, and click on the Add button. Select the com.packt.messageProvider extension point.

The next step is to actually implement the messageProvider extension point. As you can see, the com.packt.messageProvider extension already contains a hello_message element. The Extension Element Details pane shows us what we already know. We need a class that implements IMessageProvider to implement this extension point.

You can create the class by simply clicking on the message_provider* link in the Extension Elements Details pane. Now copy the following code into it:

import helloworldplugin.IMessageProvider;

public class MyMessageProvider implements IMessageProvider {

    @Override
    public String getHelloMessage() {
           return "Hello world from MessageProvider";
    }

}

As you can see, this is a very basic implementation. We are now ready to test our extension point and its implementation. Select one of the two projects that we've just created and select Run | Run as | Eclipse Application. The message coming from the extension point is displayed when we click on the button, as shown in the following screenshot:

Implementing an extension point
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset