TopQuadrant Home
corner
TopBraid Suite
TopBraid Composer
Standard Editon
Maestro Editon
Download
Purchase
Community
Support
TopBraid Live
TopBraid Ensemble
SPARQLMotion
Products Solutions Services Resources Company corner
products

TopBraid Composer Plug-in Development Guide

by Holger Knublauch (latest change: April 22, 2008 - for Version 2.5.3)

Introduction
Getting Started
Extension Points Overview
Key Concepts of TopBraid Composer
Example 1: Creating a View
Example 2: Creating a Resource Action
Where To Go From here

Reference: TopBraid Composer API (JavaDoc)

 

Introduction

TopBraid Composer is a very flexible platform that enables Java programmers to add customized extensions or to develop stand-alone Semantic Web applications. For example, it is fairly easy to add new kinds of windows, editors, menu entries or even new storage formats to Composer. This guide will help you get started.

Composer is built on the Eclipse platform. Eclipse is the standard Java tooling platform with a generic architecture based on the notion of plug-ins. A plug-in (aka bundle) contributes a specific functionality to the overall system. In order to write extensions to Composer, you need to understand the Eclipse plug-in architecture (which is based on an architecture called OSGi). The Eclipse web page provides pointers to technical documents about this topic, and there is also a couple of books about Eclipse plug-in development. Eclipse itself is open-source, and it provides various convenience services for plug-in development. I therefore strongly recommend using Eclipse as your development environment for Composer extensions.

Beside the Eclipse platform, the main API you will work is Jena, an industrial-strength open-source API. Only small parts of the TopBraid API will be needed to create plug-ins, so that developers familiar with Eclipse and Jena will find it easy to get around.

TopBraid Composer has been designed to completely separate the user interface modules from non-visual control components. Most functionality that does not closely depend on the Eclipse windowing system SWT has been placed in plug-ins starting with org.topbraid, while those specific to the Eclipse UI are found in org.topbraidcomposer. The org.topbraid packages are shared among Composer and products of the TopBraid Suite, such TopBraid Live and TopBraid Ensemble. In a nutshell this means that plug-ins can be developed that work both in TopBraid Composer or on a TopBraid Live server. This tutorial focusses on plug-in development for TopBraid Composer.

 

Getting Started

You can use your existing TopBraid Composer installation as a plug-in development environment. Install and run Composer, close any open files and then create a new plugin project (File > New > Project...):

New Plug-in Project

In the next page, enter a project name. Plug-ins are typically named after the contained Java packages.

New Plugin 2

Finish the wizard and OK to switch Eclipse to the Plug-in Development perspective. Your screen should then look like the following.

New plugin start page

Eclipse provides some very convenient editor pages that can be used to configure your plug-ins. For example, the Dependencies page can be used to tell the system which other plug-ins are required in order to execute your own plug-in. This is an important setting because without declaring these dependencies, you cannot access the classes of Jena and Composer in your plug-in code. In the most common cases, you should declare dependency on some of TopBraid's core, jena and UI plug-ins as shown in the next screen.

Plugin dependencies

Now that we have created the basic project, we can start to look into something more interesting.

 

Extension Points Overview

The following image shows some commonly used extension points for TopBraid Composer extensions. Some of these extension points are plain Eclipse while others are specifically custom-tailored to Composer.

Plugin types overview

The extension points shown in the image above are:

  1. Adding items to the Eclipse main menu can be accomplished through a combination of org.eclipse.ui.actionSets and org.eclipse.ui.actionSetPartAssociations. The actionSetPartAssociation needs to point to the id org.topbraidcomposer.editors.ResourceEditor so that the items are activated whenever TopBraid's ResourceEditor is the selected editor.
  2. The same extension points like in 1. are used to define those actions that shall appear in the global tool bar.
  3. Adding items to view-specific tool bars and drop-down menus can also be achieved through a standard Eclipse extension point called org.eclipse.ui.viewActions. A list of ids of Composer's standard views can be found in the documentation of the class org.topbraidcomposer.ui.IDs.
  4. The org.topbraid.actions.resourceActions extension point can be used to add items to the main Resource menu and the drop down menu in the upper right corner of the forms. Each resource action is a Java class implementing the interface IResourceAction (typically it is easier to subclass AbstractResourceAction). These classes contain methods that will tell the system whether the action shall appear for the selected resource. We will look at an example for this later.
  5. In order to add triple-specific items to the drop down menu behind a resource form widget row, you can use the org.topbraid.actions.statementActions extension point. Plug-ins of this type must point to an implementation of the IStatementAction interface or implement AbstractStatementAction.
  6. Customized displays of resource types such as SWRL rules or OWL class expressions are implemented using the extension point org.topbraid.strings.labelsPlugins. Implementations of ILabelsPlugin essentially create a string for a root resource. In order to validate editing such values the extension point org.topbraid.strings.rowEditorDrivers can be implemented. The associated implementations of IRowEditorDriver take responsibility for editing certain kinds of statements.
  7. Adding new view types is possible by means of the org.eclipse.ui.views Eclipse extension point. Implementations have complete control over what appears inside the boundaries of their windows. Views can access the currently selected model and resource as described in an example later.
  8. New file types and alternative storage back-ends can be introduced using TopBraid's org.topbraid.core.graphStores extension point. Each graph store declares the file type that it handles (such as n3, rdfa, jenadb) and points to an implementation of IGraphStore that knows how to load and save a Jena Graph object from the file.
  9. In order to add items to pop-up menus inside the views, you can use the Eclipse extension point org.eclipse.ui.popupMenus.

Note that Composer and Eclipse provide many other extension points that are not handled here. Composer itself is essentially a bundle of Eclipse plug-ins, and Composer itself makes use of its own plug-in architecture.

 

Key Concepts of TopBraid Composer

In order to develop plug-ins, a basic understanding of Composer's internal structure is helpful. While plug-ins will typically do most of the work through the Jena API, TopBraid's API is still needed to get a handle on the currently selected Jena objects, and to control model manipulation.

The starting point for most model operations is the singleton class TB. TB has static pointers to various objects that manage the state of TopBraid, including the loaded Jena Graphs, the selected OntModel and the selected resource.

Sessions and OntModels

The user-specific state of TopBraid Composer is encapsulated in an instance of ISession. Use TB.getSession() to get the current session. In a multi-user setting on the TopBraid Live server, multiple session instances may exist, but this is not relevant here.

The session maintains information about the selected Jena Resource and the currently focused OntModel. Whenever the user opens a new file or switches files, the globally selected OntModel changes. The ISession can also be used to get notified when the selection changes, so that views and other components can react.

The resulting OntModels consist of multiple sub-graphs. The base graph is the primary editing target, i.e. when the user adds a class or instance then the resulting triples are added to the base graph. If the base graph has owl:imports, then all imported sub-graphs are transitively added to the OntModel as well.

The OntModels do not have any automated inferencing policy, i.e. queries return only the asserted triples. However, Composer distinguishes between asserted triples and inferred triples: inferred triples (e.g. those triples created when the user presses the classify buttons) are stored in a separate inference graph - one for each OntModel. Finally, each OntModel contains a system graph with all RDF Schema and OWL vocabulary triples.

Each graph and its associated OntModel are accessible by a base URI. This is why Composer forces each model to declare a base URI (one way or another). The base URI is the URI that appears inside owl:imports statements. If two separate OntModels import the same base URI, then only one Graph object is maintained, i.e. a Graph is potentially shared among multiple OntModels.

Changes and Operations

Whenever a plug-in wants to perform changes (write-access, such as adding a triple) to a graph or OntModel, it should obey a few rules. All changes should be performed within the execute method of an IChange object. This method is called by the IChangeEngine of the session, accessible from TB.getSession().getChangeEngine(). This enables Composer to maintain the undo history and to update necessary inferences. In particular though, Changes bundle atomic units of work so that they can be reacted on correctly. For example, a complex OWL DL class expression tree consists of multiple triples, and displays should only update after all triples have been created.

The IChange object will execute the changes in a background thread and notify its listeners after the operation has been finished. Note that this notification happens from a non-UI thread, and visual components that need to react on the event must ensure that they only access SWT resources from within the UI thread. A typical solution is to use Display.getDefault().asyncExec() to schedule UI work in the correct thread.

Note that a plug-ins should check whether it has write access to the selected target Graphs. For example, triples from a read-only graph cannot be deleted. The method ISession.isDeletable() can be used for this purpose.

Composer comes with a growing library of reusable standard IChanges - see the org.topbraid.change plug-in.

Labels and Icons

Most plug-ins will want to display resources in a consistent format. The singletons Labels and Images can be used to access these using the standard conventions. The Images class will return platform independent objects of type ImageMetadata, which can be transformed into real SWT images using the getImage() method in the TBC singleton.

 

Example 1: Creating a View

We will now create a simple plug-in to get you started. This view will simply display the label of the currently selected resource. The view will refresh when the global selection changes, and will close when all files are closed.

Creating new views requires us to use the org.eclipse.ui.views Eclipse extension point. Starting with our empty project created above, we will create an extension using the Eclipse PDE. Switch to the Extensions tab and add the corresponding extension point.

Example view 1

Then right click on org.eclipse.ui.views and create a new view. Fill in the fields on the right. Click on the small class*: link to create a new class com.example.myplugin.LabelView, yielding the following screenshot:

Example View 2

Now we only need to implement the class com.example.myplugin.LabelView. Let's make this a subclass of TopBraid's base class AbstractView so that we inherit some common functionality. If you are new to Eclipse: A convenient way of doing this is to enter extends AbstractView behind the class name, move your cursor over AbstractView and then press CTRL+Shift+M to add the missing import statement (make sure you have saved your project before this). Once we have inherited from AbstractView we can remove any existing method from this class. Your screen should look like the following:

Example View 3

Now we just need to implement two methods to define the contents of this view. Using the small red X beside the erroneous line, we can let Eclipse add the missing method headers:

Example View 4

Here is the complete source code - feel free to play with it.

package com.example.myplugin;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.topbraid.core.TB;
import org.topbraid.core.session.IResourceSelectionListener;
import org.topbraid.strings.Labels;
import org.topbraidcomposer.ui.views.AbstractView;
import com.hp.hpl.jena.rdf.model.Resource;
/**
 * A simple example View displaying the currently selected Jena
 * Resource in an SWT label.  The label updates when the global
 * resource selection changes.  The view closes when the global
 * selection becomes null, i.e. all TopBraid windows are closed.
 * 
 * @author Holger Knublauch
 */
public class LabelView extends AbstractView 
             implements IResourceSelectionListener {
   
    // The SWT label showing the name of the selected resource 
    private Label label;
                         
    /**
     * Fills the main area of this control.
     */
    protected void createMainControls(Composite parent) {
   
        label = new Label(parent, SWT.NONE);
   
        // Ensure that this will be notified when the selection changes
        TB.getSession().addResourceSelectionListener(this);
    }
   
   
    /**
     * Ensures that the ResourceSelectionListener is removed when this
     * view is closed.
     */
    public void dispose() {
        super.dispose();
        TB.getSession().removeResourceSelectionListener(this);
    }
                         
    /**
     * Called by TopBraid when the global selection changes.
     * @param r  the new selected resource or null 
     */
    public void resourceSelected(final Resource r) {
        if(r != null) {
            asyncExec(new Runnable() {
                public void run() {
                    String str = Labels.getLabel(r);
                    label.setText(str);
                }
            });
        }
        else {
            close();
        }
    }
 
    public void setFocus() {
    }
}

Once this class is completed, we are ready to launch our plug-in to see it in action! To do so, switch to the Overview pane of the plugin.xml file (com.example.myplugin):

Example View 5

Select Launch an Eclipse application to start your plug-in inside a new Eclipse instance. The first time you launch this, you can configure its projects and open an example OWL file. Then go to Window > Show View > Other... > TopBraid to open the LabelView:

Example View 6

Our new, spectacular plug-in view will then appear in the bottom right corner of our screen! Change the selection to see how it switches its contents.

 

Example 2: Creating a Resource Action

This plug-in will add an entry to the drop down menu in the upper right corner of the forms, i.e. using extension point number 4 of the overview. The action will only show up in the drop down menu of classes, and it will create three example instances of the class. As a side effect of this exercise, you will also see how to manipulate a model in a Composer plug-in.

For convenience, we will start with the plug-in skeleton developed in Example 1. On the Extensions page of the plug-in, add the extension point org.topbraid.actions.resourceActions. Then click on class*: and enter CreateInstancesAction as class name and save:

Example Resource Action 1

Now we only need to fill in the corresponding Java class. This must implement the IResourceAction interface. The easiest way to do this is to subclass AbstractResourceAction.

We need to implement a constructor, a run method, and the three methods. These methods determine to what Jena resources the action shall be visible and enabled for, and in which group it shall appear. Each time the user opens the drop down menu, Composer will look through the registered resource actions and ask them whether they are visible for the currently selected resource. If yes, then the system will add them to the menu into an optional group. The menu item will be enabled only if the corresponding method returns true. Here is the source code of these methods:

Example Resource Action 3

In the isVisibleFor method, we use a Jena API call to test whether the resource has owl:Class as one of its rdf:types. The condition for isEnabledFor is identical, because this action will work for any instance. The group name is just a string that we made up for this example. If we were to add more actions in the future, then reusing the same group name will make them appear in the same section of the menu.

Now the only missing thing is to implement the "action" part itself, i.e. the run method which is called whenever the user clicks on the menu item. We implement the run method with code that creates an IChange and then executes it. The IChange (here derived from AbstractChange) is the unit of work that will create three instances of the current class.

Example Resource Action 4

After we have completed this class, we can execute our new plug-in. If we select an owl:Class, the new menu item will appear in the drop down in the upper right corner, or in the Resource main menu:

Clicking on the menu item will execute the action and add three dummy instances to the model:

 

Where To Go From Here

This short introduction with its simple examples should be enough to put you into a position where you can write simple plug-ins. For additional information, please make sure to check the documentation of the Eclipse Plug-in architecture and Plug-in Development Environment. Needless to say, a good command over the Jena API is necessary for serious plug-in development work. Both Eclipse and Jena are supported by very active mailing lists so that help will always be just a few mouse clicks away. For Composer specific questions, feel free to contact us. TopQuadrant also offers professional services to develop custom-tailored plug-ins for your needs.

One of the advantages of Composer is that it can serve as an application development framework: programmers can develop components as plug-ins and benefit from the rich features of Composer to run experiments and tests against real-world data. When the functionality has been sufficiently tested, the module can be deployed into a stand-alone application, especially on the TopBraid Suite platform.