P4APIOverview
Protege 4 APIs
Pointers for developers of plugins and understanding the core APIs of Protege 4.
Work in progress
Overview
Protege 4.0 OWL support is built on top of the OWL API, which provides all of the model manipulation and querying functionality.
On top of this, Protege supports further functionality for developer's convenience - hierarchies, renderer management, search etc.
Most of the behaviour of the application can be accessed through the main points below, whether accessing the model or the UI.
However, there are also many utility classes provided by Protege or the OWL API.
Access points
The most important three Protege 4 classes you will have access to from most plugins are:
OWLModelManager
Access to the ontologies, reasoners, search renderings, change management etc. Useful services that it provides are described below. The most important thing to understand about the OWLModelManager is how active ontologies are managed.
Active ontologies
A single editor kit in P4 can have several ontologies loaded (whether these are imports or otherwise). There needs to be some way to determine which ontology edits are performed on by default. It is reasonable that the user might want to look at, edit or reason with only a subset of those loaded ontologies.
- Active ontology is the ontology currently visible in the navigation bar at the top of the workspace. By convention all new additions to the model are made in the active ontology.
- Active ontologies is a set of ontologies including the active ontology. These are the ontologies whose contents are visible in the interface. The ontologies in this set is determined by which strategy is currently selected in the Ontologies menu. The active ontologies are all sent to the reasoner when classification is requested. Edits that affect multiple ontologies should act on the active ontologies.
- Loaded ontologies is the set of all ontologies loaded into this OWLModelManager. Any ontologies that are loaded but not active should not show up in the interface.
The OWLModelManager simply uses the OWL API's OWLOntologyManager to manage these ontologies, however the OWL API manager only has a notion of loaded ontologies. If you write code that is designed to be portable (by using the OWL API OWLOntologyManager directly) you should respect the active ontologies and operate on this set only by passing them around (or having a central manager). In other words, don't just operate on all the loaded ontologies by default.
OWLWorkspace
Access to the UI elements (menus, cell renderers, handy entity selectors), global selection management etc
OWLEditorKit
The central access point for all of the model and UI elements of the OWL editor - you can get to both of the above from the editor kit
Useful subsidiary classes
OWLEntityRenderer
The current renderer can be retrieved from the OWLModelManager and is used to get the short name for any entity based on the renderer preferences.
EntityFinder
The finder can be used to find classes, properties and individuals by partial name or regular expression match. This is different from the utility methods on OWLModelManager which perform an exact match.
OWLEntityFactory
The current factory attached to the OWLModelManager should be used to create classes, properties and individuals using the naming conventions in the New entities preferences. The factory returns a creation set which contains the changes required to create the entity. This must be applied explicitly by your code.
OWLReasoner (OWLAPI)
The current reasoner as selected in the reasoner menu can be retrieved from the OWLModelManager. To check if it currently contains a classified model with isClassified().
OWLHierarchyManager
A central place to get to shared OWLObjectHierarchyProviders. These providers are convenient tree models that can be directly handed to a OWLModelManagerTree or used to traverse the various asserted or inferred hierarchies of classes and properties. Get this from the OWLModelManager.
Events
Protege has several event models that can be subscribed to in order to keep your plugins aware of changes to the model or the system.
OWLModelManager events
You can add an OWLModelManagerListener using addListener to be notified about large granularity changes to the set of ontologies loaded. Get the type of the event to determine the change that has occured ACTIVE_ONTOLOGY_CHANGED, ONTOLOGY_VISIBILITY_CHANGED, ENTITY_RENDERER_CHANGED, ENTITY_RENDERING_CHANGED, REASONER_CHANGED, ABOUT_TO_CLASSIFY, ONTOLOGY_CLASSIFIED, ONTOLOGY_CREATED, ONTOLOGY_LOADED, ONTOLOGY_RELOADED, ONTOLOGY_SAVED
Adding an OWLOntologyChangeListener will allow you to keep track of changes to any of the loaded ontologies to allow you to keep a view in sync with the model for example. You will receive a list of the changes to determine if they are pertinent to your plugin.
An IOListener can be useful to get notification before or after an ontology is loaded or saved. This could be used to provide standard transforms or quality control warnings on ontology loading/serialisation.
OWL API basics
Ontologies, classes, properties, individuals, datatypes class expressions, axioms, changes, reasoners and other fundamental parts of the OWL model are managed by the OWL API.
Full docs for the OWL API are available on the OWL API website, but here some some pointers:
OWL what Manager?
Don't be confused by some classes that have a name similar to the OWLModelManager class:
- OWLOntologyManager is a class in the OWL API that is not specific to Protege 4. The OWLOntologyManager plays a central role in the development of OWLAPI code. It provides access to the ontologies, change management, etc. An OWLModelManager has a getter method that will recover the OWLOntologyManager.
- OWLManager is utility class in the OWL API that you can use to create an OWLOntologyManager class. In general you probably won't need this when writing Protege 4 code but it is the starting point for most OWL API code.
Creating OWL objects
All OWL objects (classes, properties, expressions, axioms) are created by an OWLDataFactory that can be retrieved from the OWLModelManager or directly from the OWLOntologyManager (it is the same factory).
The factory provides a getter method for every object
eg getOWLObjectProperty(uri) or getOWLSubClassOfAxiom(expr, expr)
The objects returned are immutable and implement structural equality, therefore two OWL objects of the same type that were created at different times but with the same parameters are considered the same object. All OWL objects can exist independent of an ontology.
Making changes to the ontology
An OWL ontology is simply a set of OWLAxioms plus a few annotations and a name. In order to change the ontology you can add or remove axioms from the ontology. First, create the axiom using the OWLDataFactory or search for an appropriate axiom in the ontology. Then, create an AddAxiom or RemoveAxiom OWLOntologyChange object - there is no factory for these, just create them as needed - by supplying the axiom plus the ontology the change will affect.
If you have a compound change (multiple axioms added or removed) then add all of these to a list.
Use the OWLOntologyManager (or, for convenience the OWLModelManager) applyChanges(changes) method to cause the changes to take effect. Anything that has an OWLOntologyChangeListener attached to this manager will get notified.
Visitors
Because the OWL vocabulary is fixed(!), there are a set number of OWLObject types that an algorithm may want to act on.
In many cases an algorithm may want to implement behaviour for a broad range range of OWLObject - say we want to be able to render any class expression.
Instead of having a large if statement with lots of
if (expr instanceof OWLObjectSomeRestriction){ OWLObjectSomeRestriction restr = (OWLObjectSomeRestriction)expr; // do something } else if (expr instanceof OWLObjectAllRestriction){ OWLObjectAllRestriction restr = (OWLObjectAllRestriction)expr; // do something else } else...
OWLObjects are implemented so they can use the visitor pattern:
MyRenderer myRenderer = new MyRenderer(); expr.accept(myRenderer);
class MyRenderer extends OWLDescriptionVisitorAdapter{ // or implement OWLDescriptionVisitor if you want behaviour for all expressions public void visit(OWLObjectSomeRestriction r){ // do something with r } public void visit(OWLObjectAllRestriction r){ // do something else with r } }