Previous Topic

Next Topic

Jena

Jena is a JavaTM API that is commonly used to develop applications using RDF. This tutorial describes any changes or modifications to existing Jena code that are required for it to use KowariTM.

In This Section

Creating Sessions

Available Jena Interfaces

Using the Jena Maker Interfaces

Using Iterators

Exceptions and Logging

Threading

Porting an Existing Jena Application

See Also

Integration Tutorials

HTTP Resolver and MP3 Content Handler Tutorial

Perl

JavaServer Pages Tag Library

JRDF Tutorial

Creating Sessions

The Kowari server can be accessed using the the Jena API using either a local connection (in the same Java Virtual Machine (JVM)) or via a client/server interface.

The local connection provides the ability to create a new server or start an existing one and access it through the Jena API. The client/server interface connects to an existing server using RMI, if it exists, or if this fails, falls back to creating a new local server. Falling back to local server does not start the RMI registry and other external clients cannot access it unless started manually.

The main APIs in Jena are the Model and Graph interfaces. The Kowari server has its own implementation of these. To use these APIs you must first have a JenaSession. A JenaSession first requires a SessionFactory. To construct a new SessionFactory the URI of the server is required as well as an optional boolean parameter indicating whether the server is remote or not. If this boolean parameter is not provided, the server is assumed to be local (in the same JVM). For example:

// Create the host name
String hostname = InetAddress.getLocalHost().getCanonicalHostName();

// Create the URI of the server
serverURI = new URI("rmi", hostname, "/" + SERVER_NAME, null);

// Create a new session factory, ensure that it's local
SessionFactory sessionFactory = SessionFactoryFinder.newSessionFactory(serverURI, false);

// Get a local Jena session
LocalJenaSession session = (LocalJenaSession) sessionFactory.newJenaSession();

If a local server is created, the server configuration file is used to determine which directory to place the server's files in. See the Kowari Configuration File section in the Administrator Guide for more information.

If a remote Session Factory is used, then the session can only be cast to a JenaSession. For example:

// Create a new remote session factory
SessionFactory sessionFactory = SessionFactoryFinder.newSessionFactory(serverURI, true);

// Get a local Jena
JenaSession session = (JenaSession) sessionFactory.newJenaSession();

Available Jena Interfaces

The type of session determines which Jena interfaces are available. The client Jena interfaces consist of KModel and KGraph. The server side Jena interfaces are much larger and include Jena interfaces such as GraphMaker, ModelMaker, BulkUpdateHandler and the interfaces used in querying, reification, and transactions.

Using the Jena Maker Interfaces

Jena defines two interfaces responsible for the creation of new models and graphs. Kowari has its own implementation of these interfaces: ModelKowariMaker and GraphKowariMaker.

Once the session is successfully created you can construct a GraphKowariMaker, then a ModelKowariMaker and finally create a new model, as follows:

GraphKowariMaker graphMaker = new GraphKowariMaker(session, serverURI, ReificationStyle.Minimal);
ModelKowariMaker modelMaker = new ModelKowariMaker(graphMaker);
Model model = modelMaker.createModel("camera");

The above example creates a new model called rmi://mysite.com/server1#camera, where mysite.com is the fully qualified name of the machine Kowari is running on.

If code requires an ontology model, then use the following example:

// Create a new model with the default specification (OWL_MEM)
OntModel newModel = ModelFactory.createOntologyModel();

Assuming that the database and ModelKowariMaker are created in a method called createMaker, then the code becomes:

// Get ModelKowariMaker
ModelMaker maker = createMaker(ReificationStyle.Minimal);

// Specify ontology model type (OWL_MEM)
OntModelSpec spec = new OntModelSpec(OntModelSpec.OWL_MEM);
spec.setModelMaker(maker);

// Create a new base model.
Model baseModel = maker.createModel();

// Create a new ontology model.
OntModel m = ModelFactory.createOntologyModel(spec, baseModel);

The GraphKowariMaker interface defines the removeAll() and removeGraph(String) methods. These remove all model entries or an individual model's entry from the server's system model. This means that the models are no longer accessible and the data they were holding is lost.

Models and Graphs must be closed after use by calling close(). This ensures that the files and other resources used are closed correctly. If the objects are not closed, because of a hardware or other unexpected termination of the program, no data is lost and the database cleans up the file data on next start up.

The database and session that are created to create the Jena object implementations must also have close() called on them in order to correctly clean up resources that are being used.

Two calls are available to shutdown a database cleanly. The first, close(), just stops the database. The second, delete(), stops the database and removes all files associated with it. This permanently erases the database from the disk.

Using Iterators

The standard base iterator class for Jena is ClosableIterator. This is extended by other iterators such as ExtendedIterator, StmtIterator and TripleIterator. The default iterator implementation used in this Jena implementation is TuplesClosableIteratorImpl. It is backed by a Tuples object, which must be closed. Failure to close an iterator could lead to the system eventually running out of files and other resources.

Most Jena applications do not call close() on iterators. Most, but not all, of the standard Jena code does call close() on iterators. If you are unable to change the behavior of the code, objects such as FileTuples, log warning messages indicating they were not properly closed. To support iterators not being closed, functionality has been added into close() on GraphKowariMaker. It tracks the creation of iterators and closes any un-closed iterators. Best practice, however, is to ensure that iterators are closed as soon as possible.

In existing Jena code, calling listStatements usually takes the following form:

StmtIterator sti = model.listStatements();
while (sti.hasNext()) {
Statement st = (Statement) sti.next();
...
}

The usual way of ensuring that iterators are always closed is as follows:

StmtIterator sti = null;

try {
sti = model.listStatements();
while (sti.hasNext()) {
Statement st = (Statement) sti.next();
...
}
}
finally {
if (sti != null) {
sti.close();
}
}

If an iterator is to be reused you should also set the iterator to null within the finally block. For example:

ExtendedIterator iter = null;

// First use of iterator.
try {
...
iter = model.listClasses();
...
}
finally {
if (iter != null) {
iter.close();
iter = null;
}
}

// Next use of the same variable.
try {
...
iter = model.listOntProperties();
...
}
finally {
if (iter != null) {
iter.close();
}
}

Exceptions and Logging

The Jena API uses unchecked or runtime exceptions. The exception hierarchy begins with JenaException, which extends RuntimeException and there are specific exceptions for various parts of the Jena API.

Kowari follows the expected Jena semantics on exceptions. For example, GraphKowariMaker generates an AddedDeniedException exception if an add(Triple) method fails. However, most of the exceptions generated by the underlying store layers do not have equivalent Jena exceptions. For example, the construction of GraphKowariMaker generates a JenaException if any of the following occurs:

  • The given URI is invalid
  • The server is not found
  • Acquiring a session failed
  • The statement store failed to initialize

Currently, no new exceptions are created to wrap the semantics of these cases. Only JenaException is used.

In Kowari, whenever an exception occurs within the store layer it is logged as a warning or error and then rethrown, if appropriate, as a runtime exception. Some interfaces, such as ClosableIterator, are not expected to generate an exception so the TKS implementation, TuplesClosableIteratorImpl, simply logs the exception and continues. If an exception occurs, it returns null when calling next() and false when calling hasNext(). This provides the maximum compatibility with existing Jena implementations.

Threading

The implementation of Jena's Graph is tied to the implementation of the underlying store's session. Each session only supports a one-to-one mapping of threads to instances. This means that one and only one thread should access an instance of Graph.

Porting an Existing Jena Application

The following example goes through the steps to modify an application called SWOOP (Semantic Web Ontology Overview and Perusal) and present it using the Kowari implementation of the Jena APIs. The modified source (Swoop-src.zip) is also provided for you in the Resources directory of your Kowari installation.

SWOOP has two instances where it creates a new model. Both require a way to create ModelKowariMaker. This is implemented with the static createModelMaker added to SwoopCode.java:

...
// Static definition of the session
static LocalJenaSession session = null;
...

public static ModelMaker createMaker() {
boolean exceptionOccurred = true;
try {
String hostname = InetAddress.getLocalHost().getCanonicalHostName();
URI serverURI = new URI("rmi", hostname, "/server1", null);

if (session == null) {
SessionFactory sessionFactory = SessionFactoryFinder.newSessionFactory(serverURI, false);
session = (LocalJenaSession) sessionFactory.newJenaSession();
}

exceptionOccurred = false;
return new ModelKowariMaker(new GraphKowariMaker(session, serverURI, ReificationStyle.Convenient));
}
catch (Exception e) {

// You wouldn't normally do this - just for demonstration
// purposes
e.printStackTrace();
return null;
}
finally {
if ((exceptionOccurred) && (session != null)) {
session.close();
}
}

If successful, this method creates a ModelKowariMaker, otherwise it returns null and closes the database if required. The main difference between this and most other Jena implementations is the requirement to set aside a directory to persist the triples in the store. You need to ensure that the current user has exclusive access to the creation of the directory and to the files underneath. Multiple access to the same directory and set of files by separate Java instances is not supported.

Previously, the SWOOP code initialized the OntModel with the no-args constructor:

OntModel newModel = ModelFactory.createOntologyModel();

Following the example given in the Jena documentation, you construct a persistent ontology using the following code:

// Default OWL Model Specification
OntModelSpec spec = new OntModelSpec(OntModelSpec.OWL_MEM);

// Get ModelMaker - assume doesn't return null.
ModelMaker maker = createMaker();
spec.setModelMaker(maker);

// Create a new base model.
Model baseModel = maker.createModel();
OntModel newModel = ModelFactory.createOntologyModel(spec, baseModel);

Once the model is created, the SWOOP code lists the statements. Following the standard for iterators, transforms the coding in the following lines of SwoopCode.java to become:

StmtIterator sti = null;
try {
sti = model.listStatements();
while (sti.hasNext()) {
Statement st = (Statement) sti.next();
//System.out.println(st.toString());
boolean removeStatement = false;
try {
if (st.getSubject().getURI().startsWith(RDF)) removeStatement = true;
if (st.getSubject().getURI().startsWith(RDFS)) removeStatement = true;
if (st.getSubject().getURI().startsWith(OWL)) removeStatement = true;
}
catch (NullPointerException e) {
}

if (!removeStatement) newModel.add(st);
}
}
finally {  
if (sti != null) {
sti.close();
}
}

As noted in the previous section, this ensures that if an iterator is created, it is always closed even if an exception or other error occurs. Unclosed iterators do not generally cause a problem under normal usage. Under heavy load however, when the garbage collector does not collect the resources quickly enough, you can run out of resources.

Likewise, changes are made to access the static createMaker() from SwoopFrame.java in the addOntology() method:

OntModelSpec spec = new OntModelSpec(OntModelSpec.OWL_MEM);
ModelMaker maker = SwoopCode.createMaker();
spec.setModelMaker(maker);

// Create a new base model.
Model baseModel = maker.createModel();
OntModel newOntologyModel = ModelFactory.createOntologyModel(spec, baseModel);

The rest of the changes require modifying the use of iterators. They must always be closable iterators when working from the model and Kowari ensures that they are closed.

Latest News

Kowari 1.1.0 Pre-release 1 Released

Kowari 1.0.5 Released

Kowari 1.0.4.1 Released

Kowari 1.0.4 Released

DAWG Evaluates iTQL

Kowari article in XML.com

Kowari mentioned on XML.com

Kowari 1.0.3 Released

Kowari Lite Introduced

Kowari 1.0.2 Released

Kowari 1.0.1 Released

View all news items


Open Source logo Tucana Technologies Logo SourceForge.net Logo

© 2001-2004 Tucana Technologies, Inc. Some rights reserved.