mulgara - semantic store

skip navigation

SHOW SITE NAV
fixed
fluid
straight

Resolvers

Once the factory and content wrapper are written, the final step is to create the resolver. Resolver instances are created on an as required basis by the resolver factory and are responsible for taking a model URI and performing model creation, deletion, modification, or querying against constraints.

Most often a resolver is written to resolve constraints against a file or store that is not naturally in RDF, with the protocol managed by a Resolver implementation, and the content to triples conversion managed by a ContentHandler implementation. For this reason, if a new mime type is to be resolved then a ContentHandler should be written instead of a Resolver, and vice versa for new protocols.

Most of the design decisions should already have been made during the creation of the factory and content classes, leaving the process of actually resolving a query for the resolver. However, you do need to decide what operations are permitted on models of this protocol type. Since querying a model is compulsory (as it is the main purpose of a resolver) that leaves model creation, modification of data and removal of models. For the moment you want the protocol resolver to just read and resolve constraints against the triples without any model manipulation. If you are writing an internal resolver, then it is important to implement these methods.

 
Writing a Resolver

A Resolver implementation requires two classes, the Content implementation for handling content under the resolver's protocol and the Resolver implementation itself. Instances of the class are created by the factory and are given constraints to resolve the query against which are used in conjunction with Statements found by the ContentHandler, which matches the mime type of the resource. In addition to query resolution, it should also handle model creation, deletion, or content modification if required.

The following source is how the http protocol resolver is written (extracted from HttpResolver.java):

package org.mulgara.resolver.http;

// Java 2 standard packages
import java.net.*;
import java.util.*;

// Third party packages
import org.apache.log4j.Logger;
import org.jrdf.graph.Node;
import org.jrdf.graph.URIReference;

// Locally written packages
import org.mulgara.content.Content;
import org.mulgara.content.ContentHandler;
import org.mulgara.content.ContentHandlerManager;
import org.mulgara.content.ContentHandlerException;
import org.mulgara.content.ContentResolver;
import org.mulgara.resolver.spi.*;

public class HttpResolver extends ContentResolver {
/**
* Logger.
*/
private static Logger logger = Logger.getLogger(HttpResolver.class.getName());

/**
* Construct a resolver.
*
* @param resolverSession the session this resolver is associated with
* @param contentHandlers the available {@link ContentHandler}s
* @throws IllegalArgumentException if resolverSession is
* null
*/
HttpResolver(ResolverSession resolverSession,
Resolver systemResolver,
ContentHandlerManager contentHandlers) {

super(resolverSession, systemResolver, contentHandlers);
}

//
// Methods implementing ContentResolver
//

/**
* Convert a local node number representing a http: model into
* {@link HttpContent}.
*
* @param model the local node number of a http: URL
* @throws ResolverException if the model doesn't correspond to a
* {@link URL} with the http: protocol.
*/
protected Content toContent(long model) throws ResolverException {

// Container for our model's URI
URI modelURI;

// Container for our globalised node
Node globalModel = null;

try {

// Globalise the model
globalModel = resolverSession.globalize(model);
} catch (GlobalizeException e) {

throw new ResolverException("Couldn't globalize http model", e);
}

if (!(globalModel instanceof URIReference)) {

// Check that our node is a URIReference
throw new ResolverException(
"Model parameter " + globalModel + " isn't a URI reference");
}

// Get the URI from the globalised node
modelURI = ((URIReference) globalModel).getURI();

assert modelURI != null;

// Validate the URI
if (!modelURI.getScheme().toLowerCase().startsWith("http")) {

throw new ResolverException(modelURI + " doesn't use the http(s): scheme");
}

// Container for our URL
URL modelURL = null;

try {

// Convert the URI to a URL
modelURL = modelURI.toURL();
} catch (MalformedURLException malformedURLException) {

throw new ResolverException(
"Failed to convert the model's URI to a valid URL [" +
modelURI +"]", malformedURLException);
}

try {
return new HttpContent(modelURL);
}
catch (URISyntaxException e) {
throw new ResolverException(
"Couldn't create HttpContent from " + modelURL, e
);
}
}
}

An analysis of the class is as follows:

package org.mulgara.resolver.http;

// Java 2 standard packages
import java.net.*;
import java.util.*;

// Third party packages
import org.apache.log4j.Logger;
import org.jrdf.graph.Node;
import org.jrdf.graph.URIReference;

// Locally written packages
import org.mulgara.content.Content;
import org.mulgara.content.ContentHandler;
import org.mulgara.content.ContentHandlerManager;
import org.mulgara.content.ContentHandlerException;
import org.mulgara.content.ContentResolver;
import org.mulgara.resolver.spi.*;

Due to the way resolvers are constructed, the packaging should be set up so that they are always in the same package as their factory. Resolvers also require access to the Resolver SPI and tuples packages. Extra imports depend on your specific implementation.

public class HttpResolver implements ContentResolver {

Most of the implementation for resolvers is already managed in the ContentResolver class, which should be extended for a protocol resolver or any other resolver involving Content implementations. If the resolver being written is not a protocol resolver, then a proper implementation of the Resolver interface should be written. This is not covered in this tutorial.

/**
* Construct a resolver.
*
* @param resolverSession the session this resolver is associated with
* @param contentHandlers the available {@link ContentHandler}s
* @throws IllegalArgumentException if resolverSession is
* null
*/
HttpResolver(ResolverSession resolverSession,
Resolver systemResolver,
ContentHandlerManager contentHandlers) {

super(resolverSession, systemResolver, contentHandlers);
}

Resolver constructors should be package specific as all creation and instantiation occurs within the factory and nowhere else. To comply with the super class, they require a ResolverSession to allow for globalization and localization of nodes, a link to the system resolver and the ContentHandlerManager object, which contains a list all the content handlers available in the database. Extra parameters can be used as long as the factory is set up to manage them. Usually a resolver only needs to call the super constructor, but if extra initialization needs to be carried out then it can also be done in the constructor.

/**
* Convert a local node number representing a http: model into
* {@link HttpContent}.
*
* @param model the local node number of a http: URL
* @throws ResolverException if the model doesn't correspond to a
* {@link URL} with the http: protocol.
*/
protected Content toContent(long model) throws ResolverException {

// Container for our model's URI
URI modelURI;

// Container for our globalised node
Node globalModel = null;

try {

// Globalise the model
globalModel = resolverSession.globalize(model);
} catch (GlobalizeException e) {

throw new ResolverException("Couldn't globalize http model", e);
}

if (!(globalModel instanceof URIReference)) {

// Check that our node is a URIReference
throw new ResolverException(
"Model parameter " + globalModel + " isn't a URI reference");
}

// Get the URI from the globalised node
modelURI = ((URIReference) globalModel).getURI();

assert modelURI != null;

// Validate the URI
if (!modelURI.getScheme().toLowerCase().startsWith("http")) {

throw new ResolverException(modelURI + " doesn't use the http(s): scheme");
}

// Container for our URL
URL modelURL = null;

try {

// Convert the URI to a URL
modelURL = modelURI.toURL();
} catch (MalformedURLException malformedURLException) {

throw new ResolverException(
"Failed to convert the model's URI to a valid URL [" +
modelURI +"]", malformedURLException);
}

try {
return new HttpContent(modelURL);
}
catch (URISyntaxException e) {
throw new ResolverException(
"Couldn't create HttpContent from " + modelURL, e
);
}
}

The only compulsory method for a resolver is the toContent(long) method, which is used by the super class to obtain a content object that is suitable for the desired protocol. It is responsible for taking the model node id passed in and creating a Content object that encapsulates the data represented by the model for resolving against the constraints. Since models are passed in as a node id, they should be globalized to obtain the proper URI that can then be verified and used in a Content object.

Valid XHTML 1.0 TransitionalValid CSS 3.0!