Wiki

Clone wiki

lmf / Sesame-Connection-How-To

describes how to properly use sesame connections in the LMF

Introduction

Since snapshot 2.3.6, the LMF implements all RDF-related functionality through the Sesame API. Using the Sesame API should from now on be the only means to access the triple store. This How-To briefly describes typical patterns for using the Sesame API in other services.

Sesame Service

There is a new service called "!SesameService" that should be used for obtaining a connection to the triple store. You can inject this service in the same way as all other services. The !SesameService gives you access to new sesame connections, as well as to the repository itself. Other services should in almost all cases only use the connection directly and never the repository or value factory.

The !SesameService can be injected as follows:

@Inject private SesameService sesameService;

Sesame Connections

Depending on the underlying backend implementation, Sesame connections need to maintain a certain state and keep connections to in-memory resources (e.g. transactions or database connections). It is therefore mandatory to properly release all open connections. A typical usage pattern for a connection would be as follows:

try { RepositoryConnection conn = sesameService.getConnection();

try { // do your stuff } finally { conn.commit(); conn.close(); } } catch(RepositoryException ex) { // handle error }

Note that if you close a connection without committing it first, it will rollback any active transaction. This might result in unexpected behaviour, so it is recommended to follow the pattern above.

Sesame Repository Results

The Sesame API provides an extended form of iterator to work with repository query results, e.g. when listing triples. This iterator works lazily, i.e. fetches additional results as needed, and is aware of the underlying connection. It is therefore necessary to explicitly close an iterator when it is no longer needed. For example, the following code lists statements in the repository:

// connection starting before

RepositoryResult<Statement> triples = conn.getStatements(subject,predicate,object,true,context); while(triples.hasNext() { Statement triple = triples.next();

// do something with the triple

} triples.close();

// connection ending later

Sesame Resource Handling

Unlike the LMF, Sesame does not manage resources separately from triples. Therefore, it does not offer any means to e.g. create and persist a resource independent from a triple, or list all resources that are available in the system. This has a number of consequences on the use of the Sesame API in the LMF:

never use the value factory outside a connection

Currently, resources in the LMF are part of the transaction and therefore can only be created in the scope of an active transaction. In contrast, in Sesame the value factory can also be accessed directly from the repository. To ensure that services work independent of the backend, it is therefore recommended best practice to create resources only through the value factory that can be obtained from the connection. The following code example shows how:

try { RepositoryConnection conn = sesameService.getConnection();

try { URI resource = conn.getValueFactory().createURI("http://www.example.com/my/resource");

// do something with the resource

} finally { conn.commit(); conn.close(); } } catch(RepositoryException ex) { // handle error }

use !ResourceUtils for commonly needed functionality

There is a new utility class called !ResourceUtils that offers commonly needed resource-centric ways of accessing the triple store like listing resources, setting properties, etc. It should eventually replace all direct uses of the (old) !ResourceService.

All methods of !ResourceUtils take an active !RepositoryConnection as first argument, and most take the current resource as second argument. Please make sure to properly open, commit, and close the connection as described above.

Sesame "Views"

Sesame has a nice feature that allows wrapping a filter around a repository connection, more or less like a view in databases. The filter is working for both, query and update operations, and potentially even SPARQL.

To implement a filter, it is necessary to extend the RepositoryConnectionInterceptorAdapter and override the two methods "add" and "remove". Both methods should return true if the operation should be blocked, or false if the operation should be performed. Example of a filter:

/* - A filter/view on repositories that displays only the metadata for a resource / private static class ResourceSubjectMetadata extends RepositoryConnectionInterceptorAdapter {

    private Resource subject;

    private ResourceSubjectMetadata(Resource subject) {
        this.subject = subject;
    }

    @Override
    public boolean add(RepositoryConnection conn, Resource s, org.openrdf.model.URI p, Value o, Resource... contexts) {
         if (s instanceof org.openrdf.model.URI && subject instanceof org.openrdf.model.URI ) {
            // if s is a URI and subject a KiWiUriResource, return
            // true if they are different
            return !s.stringValue().equals(((KiWiUriResource) subject).getUri());
        } else if (s instanceof BNode && subject instanceof BNode) {
            // if s is a BNode and subject a KiWiAnonResource,
            // return true if they are different
            return !s.stringValue().equals(((KiWiAnonResource) subject).getAnonId());
        } else {
            // in all other cases, return true to filter out the
            // triple
            return true;
        }
    };

    @Override
    public boolean remove(RepositoryConnection conn, Resource s, org.openrdf.model.URI p, Value o, Resource... contexts) {
        if (s instanceof org.openrdf.model.URI && subject instanceof org.openrdf.model.URI ) {
            // if s is a URI and subject a KiWiUriResource, return
            // true if they are different
            return !s.stringValue().equals(subject.stringValue());
        } else if (s instanceof BNode && subject instanceof BNode) {
            // if s is a BNode and subject a KiWiAnonResource,
            // return true if they are different
            return !s.stringValue().equals(subject.stringValue());
        } else {
            // in all other cases, return true to filter out the
            // triple
            return true;
        }
    }
}

Filters can be wrapped around a connection by wrapping it in a InterceptingRepositoryConnection. Example:

InterceptingRepositoryConnection connection = new InterceptingRepositoryConnectionWrapper(sesameService.getRepository(), sesameService.getConnection()); connection.addRepositoryConnectionInterceptor(new ResourceSubjectMetadata(subject));

Updated