# the reification SPI in Jena 2

author: Chris Dollin
version: 1.0
date: 1st May 2003

# 1. introduction

This document describes the reification SPI, the mechanisms by which the Graph family supports the Model API reification interface.

Graphs handle reification at two levels. First, their reifier supports requests to reify triples and to search for reifications. The reifier is responsible for managing the reification information it adds and removes - the graph is not involved.

Second, a graph may optionally allow all triples added and removed through its normal operations (including the bulk update interfaces) to be monitored by its reifier. If so, all appropriate triples become the property of the reifier - they are no longer visible through the graph.

A graph may also have a reifier that doesn't do any reification. This is useful for internal graphs that are not exposed as models. So there are three kinds of `Graph`:

- Graphs that do no reification;
- Graphs that only do explicit reficiation;
- Graphs that do implicit reification.

# 2. Graph operations for reification

The primary reification operation on graphs is to extract their `Reifier` instance. Handing reification off to a different class allows reification to be handled independantly of other Graph issues, eg query handling, bulk update.

## graph.getReifier() -> Reifier

Returns the `Reifier` for this `Graph`. Each graph has a single reifier during its lifetime. The reifier object need not be allocated until the first call of `getReifier()`.

## add(Triple), delete(Triple)

These two operations may defer their triples to the graph's reifier using `handledAdd(Triple)` and `handledDelete(Triple)`; see below for details.

# 3. interface Reifier

Instances of `Reifier` handle reification requests from their `Graph` and from the API level code (issues by the API class `ModelReifier`.

## reifier.getHiddenTriples() -> Graph

The reifier may keep reification triples to itself, coded in some special way, rather than having them stored in the parent `Graph`. This method exposes those triples as another `Graph`. This is a dynamic graph - it changes as the underlying reifications change. However, it is read-only; triples cannot be added to or removed from it.

> The `SimpleReifier` implementation currently does not implement a dynamic graph. This is a bug that will need fixing.

## reifier.getParentGraph() -> Graph

Get the `Graph` that this reifier serves; the result is never `null`. (Thus the observable relationship between graphs and reifiers is 1-1.)

## class AlreadyReifiedException

This class extends `RDFException`; it is the exception that may be thrown by `reifyAs`.

## reifier.reifyAs( Triple t, Node n ) -> Node

Record the `t` as reified in the parent `Graph` by the given `n` and returns `n`. If `n` already reifies a different `Triple`, throw a `AlreadyReifiedException`.

Calling `reifyAs(t,n)` is like adding the triples:

- `n rdf:type ref:Statement`
- `n rdf:subject t.getSubject()`
- `n rdf:predicate t.getPredicate()`
- `n rdf:object t.getObject()`

to the associated Graph; however, it is intended that it is efficient in both time and space.

## reifier.hasTriple( Triple t ) -> boolean

Returns true iff some `Node n` reifies `t` in this `Reifier`, typically by an unretracted call of `reifyAs(t,n)`.

The intended (and actual) use for `hasTriple(Triple)` is in the implementation of `isReified(Statement)` in `Model`.

## reifier.getTriple( Node n ) -> Triple

Get the single `Triple` associated with `n`, if there is one. If there isn't, return `null`.

A node reifies at most one triple. If `reifyAs`, with its explicit check, is bypassed, and extra reification triples are asserted into the parent graph, then `getTriple()` will simply return `null`.

## reifier.allNodes() -> ExtendedIterator

Returns an (extended) iterator over all the nodes that (still) reifiy something in this reifier.

This is intended for the implementation of `listReifiedStatements` in `Model`.

## reifier.allNodes( Triple t ) -> ClosableIterator

Returns an iterator over all the nodes that (still) reify the triple _t_.

## reifier.remove( Node n, Triple t )

Remove the association between `n` and the triple`t`. Subsequently, `hasNode(n)` will return false and `getTriple(n)` will return `null`.

This method is used to implement `removeReification(Statement)` in `Model`.

## reifier.remove( Triple t )

Remove all the associations between any node `n` and `t`; ie, for all `n` do `remove(n,t)`.

This method is used to implement `removeAllReifications` in `Model`.

## handledAdd( Triple t ) -> boolean

A graph doing reification may choose to monitor the triples being added to it and have the reifier handle reification triples. In this case, the graph's `add(t)` should call `handledAdd(t)` and only proceed with its add if the result is `false`.

A graph that does not use `handledAdd()` [and `handledDelete()`] can only use the explict reification supplied by its reifier.

## handledRemove( Triple t )

As for `handledAdd(t)`, but applied to `delete`.

# 4. SimpleReifier

`SimpleReifier` is an implementation of `Reifier` suitable for in-memory `Graph`s built over `GraphBase`. It operates in either of two modes: with and without triple interception. With interception enabled, reification triples fed to (or removed from) its parent graph are captured using `handledAdd()` and `handledRemove`; otherwise they are ignored and the graph must store them itself.

`SimpleReifier` keeps a map from nodes to the reification information about that node. Nodes which have no reification information (most of them, in the usual case) do not appear in the map at all.

Nodes with partial or excessive reification information are associated with `Fragments`. A `Fragments` for a node `n` records separately

- the `S`s of all `n ref:subject S` triples
- the `P`s of all `n ref:predicate P` triples
- the `O`s of all `n ref:subject O` triples
- the `T`s of all `n ref:type T[Statement]` triples

If the `Fragments` becomes singular, ie each of these sets contains exactly one element, then `n` represents a reification of the triple `(S, P, O)`, and the `Fragments` object is replaced by that triple.

(If another reification triple for `n` arrives, then the triple is re-exploded into `Fragments`.)