Writing a Simple Plugin in Protégé 4.0
Writing plugins for Protégé 4.0 alpha is very straightforward once you have a build environment up and running. There are three parts to a simple plugin, a java implementation of one of the abstract plugin classes (e.g. AbstractOWLClassViewComponent), an xml file that describes the plugin, and a manifest file that describes the plugin dependencies.
The API and plugin mechanism makes for very easy and flexible plugin implementation, meaning that it is very straightforward putting together views, menu actions and tabs (and possible through elipse's equinox on which Protégé sits to create new plugin types).
Simple Example - try out the view in Protégé first
We introduce a simple example - implementation of a view plugin that renders the subclasses of the selected class as a tab indented list. The code is available as a compiled plugin.
To see it in action
- download and unzip into your Protégé plugins/ folder
- run Protégé
- Open or create an OWL ontology
- select the Classes Tab
- In the menu, select Views->Class Views->Tabbed Subclasses
- move your mouse over the tab to where you would like to drop the view
- Select a class, and the view should be updated something like this
- Whenever a new class is selected, the view updates
- Try the buttons on the top right of the view - these allow splitting, floating and removing the view. Cloned views do not follow the selection anymore.
Get the source
You can develop straight from the distribution jars (actually you will have to unzip the dependant plugins -
org.editor.protege.owl, org.protege.editor.core.application and org.semanticweb.owl.owlapi),
but if prefered, source code is available from the
Protégé Subversion Repository. Setup of your IDE
in this case is individual to your environment, and is outside the scope of this introduction.
There is a more comprehensive set of instructions
for Eclipse available - building Protégé 4.0.
Write some code
At the minimum, you need to set up your classpath for compilation to include the plugins above (including any jar in each of their lib/ folders.
Then you are ready to start coding - the code for this view is below.
To extend AbstractOWLClassViewComponent you must implement the following:
initialiseClassView()called when the view is created - typically used to create the GUI.updateView()called when the global class selection has changed - use to reflect the new selection.disposeView()called when the view is being removed - use to tidy up listeners etc
The most useful method on the plugin getOWLModelManager() gives you access to the hub of the Protégé framework.
The OWLModelManager provides access to the ontologies, expression parsers, renderers, reasoners, change management, events, and serialisation.
For user interface related access to the framework, getOWLWorkspace() returns the GUI, providing access to the selection model, tabs, results panel etc.
package org.coode.taxonomy; import org.protege.editor.owl.ui.view.AbstractOWLClassViewComponent; import org.protege.editor.owl.ui.renderer.OWLModelManagerEntityRenderer; import org.protege.editor.owl.model.hierarchy.OWLObjectHierarchyProvider; import org.semanticweb.owl.model.OWLClass; import javax.swing.*; import java.awt.*; /** * Author: Nick Drummond * http://www.cs.man.ac.uk/~drummond * * The University Of Manchester * Bio Health Informatics Group * Date: Jul 10, 2007 * * * Shows a tab indented tree of descendants for the selected class */ public class TabbedHierarchyView extends AbstractOWLClassViewComponent { private JTextArea namesComponent; // convenience class for querying the asserted subsumption hierarchy directly private OWLObjectHierarchyProvider<OWLClass> assertedHierarchyProvider; // provides string renderings of Classes/Properties/Individuals, reflecting the current output settings private OWLModelManagerEntityRenderer ren; // create the GUI public void initialiseClassView() throws Exception { setLayout(new BorderLayout(6, 6)); // in our implementation, just create a simple text area in a scrollpane namesComponent = new JTextArea(); namesComponent.setTabSize(2); add(new JScrollPane(namesComponent), BorderLayout.CENTER); } // called automatically when the global selection changes protected OWLClass updateView(OWLClass selectedClass) { namesComponent.setText(""); if (selectedClass != null){ assertedHierarchyProvider = getOWLModelManager().getOWLClassHierarchyProvider(); ren = getOWLModelManager().getOWLEntityRenderer(); render(selectedClass, 0); } return selectedClass; } // render the class and recursively all of its subclasses private void render(OWLClass selectedClass, int indent) { for (int i=0; i<indent; i++){ namesComponent.append("\t"); } namesComponent.append(ren.render(selectedClass)); namesComponent.append("\n"); // the hierarchy provider gets subclasses for us for (OWLClass sub: assertedHierarchyProvider.getChildren(selectedClass)){ render(sub, indent+1); } } // remove any listeners and perform tidyup (none required in this case) public void disposeView() { } }
Specify the plugin
The second part of the process is to describe the plugin so that Protégé can find it. You will need to create a plugins.xml file
pretty similar to that below. This file describes the plugin(s), with an identifier, a label, a pointer to the java class implementation and then some
setup specific to the view plugin (like where it is in the menu, and what colour its header is).
<?xml version="1.0" ?> <plugin> <extension id="org.coode.taxonomy.TabbedHierarchyView" point="org.protege.editor.core.application.ViewComponent"> <label value="Tabbed Subclasses"/> <class value="org.coode.taxonomy.TabbedHierarchyView"/> <headerColor value="@org.protege.classcolor"/> <category value="@org.protege.classcategory"/> </extension> </plugin>
Specify the manifest
The manifest file sets up the dependencies between plugins (the OWL editor kit is itself a plugin that we need to include),
sets further paths (local). You will need to create a MANIFEST.MF file in a directory called META-INF in your plugin.
Warning! Do not cut and paste this code as manifest files appear to be very sensitive to whitespace (as we have found after extreme pain).
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Taxonomy Example View
Bundle-SymbolicName: org.coode.taxonomy;singleton:=true
Bundle-Category: protege
Bundle-Description: An example view to demonstrate the plugin mechanism for developers
Bundle-Vendor: The CO-ODE Group
Bundle-DocURL: http://www.co-ode.org
Bundle-ClassPath: .
Import-Package: org.osgi.framework,
org.apache.log4j
Bundle-Version: 1.0.0
Bundle-Activator: org.protege.editor.core.plugin.DefaultPluginActivator
Require-Bundle: org.eclipse.equinox.registry,
org.eclipse.equinox.common,
org.protege.editor.core.application,
org.protege.editor.owl,
org.semanticweb.owl.owlapi
Bundle the plugin and run
Make sure that you compile or copy the class packages and the plugins.xml file into a suitable folder in the plugins/ directory in your Protégé installation (The src and update.xml are not required). Make sure the manifest is also included in its META-INF directory. The final plugin structure should look like this:
Run Protégé, and check that your plugin has been picked up correctly.
Read up on the technology
The OWL editor kit is implemented on top of the Wonderweb OWL API. Many of the peripheral details like loading and saving, reasoner access etc are dealt with using the OWLModelManager but you will use the API for the ontology entities themselves. A short introduction to the design decisions (including use of the Visitor pattern) are available at the OWL API pages.
The Eclipse Equinox OSGi framework is used to handle the plugin mechanisms within Protégé and is flexible enough to allow you to create new plugin types. Read more about equinox here.
