Introduction

This repository contains interfaces for, and an implementation of, an API for OWL ontologies along with some sample applications of the API.

Building

The code can be built using the supplied ant scripts (ant 1.5 required). You will also need to have the optional JUnit tasks installed for ant.

The build structure is set up so that each module is contained in its own directory. Modules can be built separately — if module a depends on b then b will be built if necessary. Directory owlapi contains a build file that relates to the entire release. Each module can be built independently by running ant tasks within the appropriate subdirectory, or the entire project can be built by running ant tasks within the owlapi directory.

The following describes the default build structure. The build structure uses included XML fragments to share targets and properties between the various modules. These include:

names.xml
Standard directory names
common.xml
Common targets
modules.xml
Module definitions
ext.xml
External dependencies

If required, locations of the directories and files can be changed by editing the included xml files.

In the following description, we assume that the distribution is in directory $OWL.

Source

Each module has its own directory, where source for classes and tests are kept. For example, for module validation we have:

$OWL
 |- validation
     |- src
     |   <java source>
     |- tests
         <java source for tests>

We will used module validation throughout this description when operations relating to a module are being discussed.

Task Summary

The command:

> ant -projecthelp

can be used to determine the tasks that can be run. A brief summary of the tasks available in module directories is as follows.

compile
Compile module.
jar
Build a jar.
compile.test
Compile tests.
jar.test
Build a jar of test classes.
run.test
Run tests.

Tasks available for the owlapi build are as follows.

compile
Compile all modules.
compile.test
Compile all tests.
run.test
Run all tests.
distribution.bin
Build a binary distribution.
distribution.src
Build a source distribution.
distribution
Build distributions.
clean
Remove generated code.
clean.all
Remove generated code and directories.

Dependencies

Compile time dependencies are shown in the figure below

Although applications such as the validation and servlets require an implementation, the particular classes to use are determined at run time.

Classes

To build a module, run the compile task:

> cd $OWL/validation
> ant compile

When compiled, generated class files are produced in a directory $OWL/build/validation/classes. Generated class files for tests are produced in $OWL/build/validation/test.classes:

$OWL
 |- build
    |- validation
       |- classes
       |   <generated java classes>
       |- test.classes
           <generated java test classes>

Jar Files

To build a jar, run the jar task:

> cd $OWL/validation
> ant jar

Generated jar files (one for each module) will be built in directory $OWL/build/owlapi/lib.

$OWL
 |- build
    |- owlapi
       |- lib
          |- validation.jar

Documentation

Javadoc documentation for an individual module can be built using:

> cd $OWL/validation
> ant javadoc

This will produce module documention in the $OWL/build/validation/javadoc directory.

Documentation for all modules can be built using:

> cd $OWL/owlapi
> ant javadoc

This will produce documention in the $OWL/build/owlapi/javadoc directory.

Servlet application

A demonstration application consisting of some simple servlets is included in the servlet directory. To build the servlet, run

> cd $OWL/servlet
> ant war

This will build an OWL.war in $OWL/build/servlet/webapps. This file can then be deployed in any appropriate servlet engine such as Tomcat or Jetty. Directory $OWL/servlet/src contains configuration information relating to the servlet.

Testing

A suite of JUnit tests are included in the distribution.

Some of these (for instance the build tests of the validator and consistency checkers) make use of the OWL Test Cases. Network connectivity is (of course) required to run these tests. The resources directory contains a number of resources relating to testing (such a list of test manifests). The list of manifests used during testing can be set using the property tests.manifests in common.xml.

Test for each module can be run from the module directory.

> cd $OWL/validation
> ant run.test

In this case, test results will appear in directory $OWL/build/validation/test.results. Alternatively, the entire test suite (for all modules) can be run from the owlapi directory:

> cd $OWL/owlapi
> ant run.test

In this case, all results will appear in $OWL/build/owlapi/test.results.

Overview

We provide a very brief overview here of the interfaces and class in the API — more detail is provided in the Javadoc documentation. The example classes may also help to illustrate how to use the API. We include some simple code fragments — note that these are not intended to be complete and compilable!

Model

The API provides a number of classes and interfaces intended to represent OWL ontologies, which can be found in package org.semanticweb.owl.model. Ontologies consist of Classes, Properties and Individuals — within an ontology there may be definitions of these objects, for example statements that two classes are equal (e.g. have the same extension) or that one class is a specialization of another.

Interfaces are provided for each of the basic things that we find in an ontology:

These interfaces share some functionality, for example they all have a URI that provides an identifier for the object.

An important point to be aware of is that within the API, these objects can exist independently of an ontology — in fact, an object representing a class can appear in many ontologies. In addition, any assertions made about the class have to be made within the context of an ontology. Thus it does not make sense to simply ask "what are the superclasses of class X?". Instead, we must ask "what are the superclasses of class X in ontology O?". This is reflected in the accessor methods on, e.g. OWLClass:

Set getEnumerations(OWLOntology o)
Returns the enumerations that have been asserted as being equivalent to this class in the given ontology.
Set getEnumerations(Set ontologies)
Returns the enumerations that have been asserted as being equivalent to this class in any of the given ontologies.
Set getEquivalentClasses(OWLOntology o)
Returns equivalent classes to this class in the given ontology.
Set getEquivalentClasses(Set ontologies)
Returns equivalent classes to this class in any of the given ontologies.
Set getSuperClasses(OWLOntology o)
Returns the explicit superclasses of this class in the given ontology.
Set getSuperClasses(Set ontologies)
Returns the explicit superclasses of this class in any of the given ontologies.

There is often more than one way of saying something in OWL. For example, in order to represent the fact that all Persons are Animals, we may represent this as part of the "definition" of Person:

Class(Animal partial)
Class(Person partial Animal)

or as a subclass axiom:

Class(Animal partial)
Class(Person partial)
SubClassOf(Person Animal)

Both have the same semantic effect, but perhaps convey different modelling intentions. The API preserves this distinction. In the first case, the information can be represented through the addition of a superclass to the class Person (within the context of the ontology). In the second, the information is represented as an OWLSubClassAxiom (again added to the ontology in question).

Many of the classes and interfaces defined in the API make use of collections. For example, OWLNaryBooleanDescription has a collection of expressions which are (unsurprisingly) the operands to the operator. The interfaces use the type Set. This means that users of the API will have to cast objects as they are extracted from the lists, e.g. the operands of a conjunction may have to be cast to OWLDescription before they can be used. The issue here is in the trade-off between type-safety (providing a number of different typed collection classes) and keeping the interfaces small, easy to understand, maintain and implement.

Visitors

The Visitor Pattern (See Design Patterns, Gamma et. al. p.331 for a detailed description) is used throughout the API. Use of the Visitor architecture allows us to add application-specific functionality without "tainting" the data structure.

For example, in order to define operations over arbitrary OWLDescriptions (e.g. providing some kind of concrete representation), implement OWLDescriptionVisitorinterface accordingly. For each concrete class C in the OWLDescription hierarchy, a function visit( C ) must be provided. The expression can then be visited using the accept method.

The code fragment below illustrates how we might use a visitor to process the super classes of a class.

OWLOntology ontology;
OWLClass clazz;
URI uri;
OWLDescriptionVisitor visitor;
...
/* Some kind of initialization */
...
try {
  /* Try and get a particular class */
  clazz = ontology.getClass( uri );

  /* Find out the supers of the class in the context of the
     given ontology. */
  Set supers = clazz.getSuperClasses( ontology );

  /* Iterate over the supers */
  for (Iterator it = supers.iterator(); it.hasNext(); ) {
    /* They should be instances of OWLDescription */
    OWLDescription desc = (OWLDescription) it.next();

    /* Pass to the visitor for some processing. */
    desc.accept( visitor );
  }
} catch ( Exception e ) {
  /* Take necessary action */
  ...
}

Change

The org.semanticweb.owl.model package decribed above provides read-only access to the data structures representing an OWL Ontology. In order to change the ontological structure, e.g. add classes, define classes or add axioms, we have to use the change events provided in the org.semanticweb.owl.model.change package.

In order to enact a change, we must first create an object that encapsulates that change (providing any necessary arguments), then pass the change to a ChangeVisitor that will then perform the necessary actions. For example, to create a new class and then add it to an ontology, something like the following is required:

OWLDataFactory factory;
OWLOntology ontology;
ChangeVisitor visitor;
...
/* Ensure that visitor is really a visitor that 
   enacts changes over ontology */
...
try {
  /* Create a new OWLClass */
  OWLClass clazz = factory.getOWLClass( uri );

  /* Create a new change object representing the addition
     of clazz to ontology. The third argument is null signifying
     that there is no explicit cause for this change. */
  AddEntity ae = new AddEntity( ontology, clazz, null );

  /* Use the visitor to enact the change */
  ae.accept( visitor );

} catch ( Exception e ) {
  /* Any necessary cleanup */
  ...
}

Concrete Implementations

The OWL API as described above consists of a number of interface classes providing access to OWL ontologies. Particular concrete implementations can then implement the required functionality, but the applications (such as an editor or a parser) need not know about the particular details of an implementation. However, at some point, we must make a choice about the actual classes used to implement the interfaces. The API ships with a simple "reference" implementation — this section describes how to access this. Note that the reference implementation is a rather simple main-memory based implementation and is not particularly optimised.

Connections and Managers

The org.semanticweb.owl.util.OWLConnection class represents a connection to some implementation provider. An OWLOntology is unique with respect to its logical URI within a connection, and an instance of OWLConnection holds a single org.semanticweb.owl.model.OWLDataFactory. This data factory is then responsible for the creation of objects.

The org.semanticweb.owl.util.OWLManager class provides a manager for factories of OWL Ontologies (e.g. OWLConnections). It is the central point of access to OWLOntology implementations and thereby to OWL Ontologies.

Applications that create new ontology objects (such as parsers) should do so within the context of a particular connection. For example, the setConnection( OWLConnection ) method on org.semanticweb.io.Parser sets the particular connection that the parser uses to gain access to an implementation.

The code sample below shows how we might gain access to an instance of a connection and then use it.

OWLConnection connection = null;

try {
  Map parameters = new HashMap();
  /* Set up the implementation class */
  parameters.put(OWLManager.OWL_CONNECTION,
                 "org.semanticweb.owl.impl.model.OWLConnectionImpl");
  connection = OWLManager.getOWLConnection(parameters);

} catch ( OWLException e ) {
  System.err.println("Could not obtain connection:");
  System.err.println( e.getMessage());
  System.exit(-1);
}

/* From this point on, all code is in terms of interfaces and abstract 
   classes */

/* Get the data factory */
OWLDataFactory fact = connection.getDataFactory();

URI uri = new URI("http://example.org/ontologies/onto");

/* Get a new ontology */
OWLOntology ontology = connection.createOWLOntology( uri, uri );

/* Get a change visitor which will enact change events over the 
   ontology */
ChangeVisitor visitor = connection.getChangeVisitor( ontology );

/* Get some new classes. */
OWLClass clazz1 = 
  factory.getOWLClass( new URI("http://example.org/ontologies/onto#class1") );
OWLClass clazz2 = 
  factory.getOWLClass( new URI("http://example.org/ontologies/onto#class2") );
	
/* Get a change object representng the addition of clazz2 as a super
   of clazz1 */
OntologyChange oc = new AddSuperClass( ontology,
				       clazz1,
				       clazz2,
				       null );
/* Add it */
oc.accept( visitor );

Default implementation

The OWLManager class can supply a default implementation of OWLConnection. This is determine dynamically at run time using the following mechanisms:

Requirements

The OWL API requires Java2. The parser for the abstract syntax requires Java 1.4.2 or later as there appears to be a bug in the 1.4.1 JVM that causes problems with the ANTLR generated parser. As a result, in the current distribution, the basic tests for the abstract OWL parser are not run when the build tests are run.

Licensing

This code is being made available under the GNU Lesser General Public License (LGPL).

Contact

For questions regarding the API, please contact Sean Bechhofer.