The Use of RDF2Go in Aperture

Aperture is built on top RDF2Go. It is an abstract layer that allows Aperture to work easily with all popular RDFStores like Sesame, Jena. For a complete list of supported RDF Stores and detailed documentation see RDF2Go homepage at http://wiki.ontoworld.org/wiki/RDF2Go

This guide is not intended to serve as detailed documentation of RDF2go. It is only intended to make the developer aware of certain RDF2Go issues that may be important to use the full power of Aperture. This chapter requires some knowledge of Aperture, so if you're new, please acquaint yourself with the rest of this tutorial before coming here.

RDF2Go basics

The most important interface in RDF2Go is a Model. It encapsulates the RDF store of choice and provides methods to interact with it. Since RDF2Go is only an abstract layer, every user needs a concrete model implementation to work with. There are quite a few of them (see here). For each supported RDF store there is an adapter, a jar file containing the implementation of Model and all other necessary interfaces. You need to have the rdf2go jars (both of them: api and impl.base), the adapter jar and the jar of your rdf store implementation of choice. (That's at least four).

Initializing a model

There are many ways to initialize a model. An average developer should be aware of at least three. The first one is the simplest. (Example uses the classes from the Sesame2 implementation, it should be similar enough for all other stores).

Model model = new RepositoryModel(false)

The above one uses one of the constructors from the RepositoryModel class. This creates a simple, non-inferencing, in-memory repository. It should be enough for many cases. If you need more flexibility, and are willing to learn the complexities of your implementation (or already know them all by heart :-) you can create an instance of the repository yourself and pass it to the RepositoryModel constructor. Like this:

// you can initialize the repository like you want, add any elements
// to the sail stack, use hard disk or data base persistence ...
// the full power of sesame lies at your fingertips
Repository repository = 
    new RepositoryImpl(
    new RDFSRules(
    new NativeStore(
    new File("path/to/the/store/folder"))));
Model model = new Model(repository);

The third part comes in handy if you need you code to be indepenent of any concrete rdf2go implementation, but still would like to create models. (Like Aperture for example :-) RDF2go provides a singleton class called RDF2Go. Yes, I know it's uncommon to call a class with the name of the library itself :-). This class is capable of detecting installed RDF2Go adapter implementations at runtime. It follows a pattern similar to that found in the SLF4J logging framework. It is enough to have the adapter jar on the classpath for the RDF2Go to detect it. You can override this behaviour with explicit calls to RDF2Go.register() and RDF2Go.unregister() methods. With it creating a model is even more simple:

Model model = RDF2Go.getModelFactory().createModel();

Opening and closing

Opening and closing a model

RDF2Go models often need certain resources to work. These may include opened files, database connections, http connections or anything else the underlying implementation might need. As such it is necessary to explicitly acquire those resources before using the model and return them when they are no longer needed. This is a price you have to pay for having a single unified API to access a simple in-memory model with 5 triples and a massive database with millions of them.

Thus working with a model follows a following pattern;

Model model = prepareTheModelAndTheUnderlyingImplementation();
model.open(); // 'open' the model and aquire all necessary system resources
doYourWork(model);
model.close(); // return the resources...

or, more often:

Model model = null;
try {
    model = prepareTheModelAndTheUnderlyingImplementation();
    model.open(); // 'open' the model and aquire all necessary system resources
    doYourWork(model); 
} catch (Exception e) {
    doSomethingWithTheException(e);
} finally {
    if (model != null) model.close(); // return the resources...
}

It is necessary to remeber about it. You will get errors if you try to use an unopened model and warnings if don't properly close it. This characteristic is important, because it implied other design decisions in Aperture.

Opening and closing an RDFContainer

RDFContainer wraps a model. As such in order to work with the container the model has to be opened. Remeber that when you pass the model to the RDFContainer constructor - the model is opened automatically, at least in the default implementation.

When you stop working with an RDFContainer - you need to dispose of it. We discourage you from closing the underlying model manually via a call to container.getModel().close(). There are many situations when multiple RDFContainers share the same model, they represent properties of various resources stored in the same model. If you stop working with one container and want to close the underlying model - all other containers will become invalid. This may lead to subtle bugs.

We have introduced a way to avoid this. Constructors of RDFContainerImpl may accept a third boolean argument. Set it to true, and the underlying model will be considered shared and disposing the RDFContainer will not close the underlying model. Keep this in mind when designing your application.

Opening and closing a DataObject

DataObject wraps (indirectly) two RDFContainers. The actual metadata container and the configuration of the data source. The first one is available through dataObject.getMetadata() and the second one through dataObject.getDataSource().getConfiguration().

When you dispose the data object, the metadata container IS disposed with it. (I'd like to underline that the container is disposed, not that underlying metadata model is closed.) The configuration of the data source is NOT. There is no DataSource.dispose() method, so when you create a DataSource instance you need to remember to take care about the configuration RDFCOntainer when you don't need it anymore.