/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 2007.
*
* Licensed under the Aduna BSD-style license.
*/
package org.openrdf.model.util;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import info.aduna.collections.iterators.ConvertingIterator;
import info.aduna.collections.iterators.Iterators;
import org.openrdf.OpenRDFUtil;
import org.openrdf.model.Graph;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
/**
* Utility methods for working with {@link Graph} objects.
*
* @author Arjohn Kampman
*/
public class GraphUtil {
/**
* Gets the subject of the statements with the specified predicate, object
* and (optionally) contexts from the supplied graph. Calling this method is
* equivalent to calling <tt>graph.match(null, pred, obj, contexts)</tt>
* and extracting the subjects of the matching statements from the returned
* iterator. See {@link Graph#match(Resource, URI, Value, Resource[])} for a
* description of the parameter values.
*/
public static Iterator<Resource> getSubjectIterator(Graph graph, URI pred, Value obj, Resource... contexts)
{
Iterator<Statement> iter = graph.match(null, pred, obj, contexts);
return new ConvertingIterator<Statement, Resource>(iter) {
@Override
protected Resource convert(Statement st)
throws RuntimeException
{
return st.getSubject();
}
};
}
/**
* Gets the subject of the statements with the specified predicate, object
* and (optionally) contexts from the supplied graph. Calling this method is
* equivalent to calling <tt>graph.match(null, pred, obj, contexts)</tt>
* and adding the subjects of the matching statements to a set. See
* {@link Graph#match(Resource, URI, Value, Resource[])} for a description of
* the parameter values.
*/
public static Set<Resource> getSubjects(Graph graph, URI pred, Value obj, Resource... contexts) {
Iterator<Resource> iter = getSubjectIterator(graph, pred, obj, contexts);
return Iterators.addAll(iter, new LinkedHashSet<Resource>());
}
/**
* Gets the subject of the statement(s) with the specified predicate and
* object from the specified contexts in the supplied graph. The combination
* of predicate, object and contexts must match at least one statement. In
* case more than one statement matches -- for example statements from
* multiple contexts -- all these statements should have the same subject. A
* {@link GraphUtilException} is thrown if these conditions are not met. See
* {@link Graph#match(Resource, URI, Value, Resource[])} for a description of
* the parameter values.
*
* @return The subject of the matched statement(s).
* @throws GraphUtilException
* If the statements matched by the specified parameters do not have
* exactly one unique subject.
*/
public static Resource getUniqueSubject(Graph graph, URI pred, Value obj, Resource... contexts)
throws GraphUtilException
{
Set<Resource> subjects = getSubjects(graph, pred, obj, contexts);
if (subjects.size() == 1) {
return subjects.iterator().next();
}
else if (subjects.isEmpty()) {
throw new GraphUtilException("Missing property: " + pred);
}
else {
throw new GraphUtilException("Multiple " + pred + " properties found");
}
}
/**
* Utility method that casts the return value of
* {@link #getUniqueSubject(Graph, URI, Value, Resource[])} to a URI, or
* throws a GraphUtilException if that value is not a URI.
*
* @return The subject of the matched statement(s).
* @throws GraphUtilException
* If such an exception is thrown by
* {@link #getUniqueSubject(Graph, URI, Value, Resource[])} or if its
* return value is not a URI.
*/
public static URI getUniqueSubjectURI(Graph graph, URI pred, Value obj, Resource... contexts)
throws GraphUtilException
{
Resource subject = getUniqueSubject(graph, pred, obj, contexts);
if (subject instanceof URI) {
return (URI)subject;
}
else {
throw new GraphUtilException("Expected URI for subject " + subject);
}
}
/**
* Gets the subject of the statement(s) with the specified predicate and
* object from the specified contexts in the supplied graph. If the
* combination of predicate, object and contexts matches one or more
* statements, all these statements should have the same subject. A
* {@link RepositoryConfigException} is thrown if this is not the case. See
* {@link Graph#match(Resource, URI, Value, Resource[])} for a description of
* the parameter values.
*
* @return The subject of the matched statement(s), or <tt>null</tt> if no
* matching statements were found.
* @throws GraphUtilException
* If the statements matched by the specified parameters have more
* than one unique subject.
*/
public static Resource getOptionalSubject(Graph graph, URI pred, Value obj, Resource... contexts)
throws GraphUtilException
{
Set<Resource> subjects = getSubjects(graph, pred, obj, contexts);
if (subjects.isEmpty()) {
return null;
}
else if (subjects.size() == 1) {
return subjects.iterator().next();
}
else {
throw new GraphUtilException("Multiple " + pred + " properties found");
}
}
/**
* Utility method that casts the return value of
* {@link #getOptionalSubject(Graph, URI, Value, Resource[])} to a URI, or
* throws a GraphUtilException if that value is not a URI.
*
* @return The subject of the matched statement(s), or <tt>null</tt> if no
* matching statements were found.
* @throws GraphUtilException
* If such an exception is thrown by
* {@link #getOptionalSubject(Graph, URI, Value, Resource[])} or if
* its return value is not a URI.
*/
public static URI getOptionalSubjectURI(Graph graph, URI pred, Value obj, Resource... contexts)
throws GraphUtilException
{
Resource subject = getOptionalSubject(graph, pred, obj, contexts);
if (subject instanceof URI) {
return (URI)subject;
}
else {
throw new GraphUtilException("Expected URI for subject " + subject);
}
}
/**
* Gets the objects of the statements with the specified subject, predicate
* and (optionally) contexts from the supplied graph. Calling this method is
* equivalent to calling <tt>graph.match(subj, pred, null, contexts)</tt>
* and extracting the objects of the matching statements from the returned
* iterator. See {@link Graph#match(Resource, URI, Value, Resource[])} for a
* description of the parameter values.
*/
public static Iterator<Value> getObjectIterator(Graph graph, Resource subj, URI pred, Resource... contexts)
{
Iterator<Statement> iter = graph.match(subj, pred, null, contexts);
return new ConvertingIterator<Statement, Value>(iter) {
@Override
protected Value convert(Statement st)
throws RuntimeException
{
return st.getObject();
}
};
}
/**
* Gets the objects of the statements with the specified subject, predicate
* and (optionally) contexts from the supplied graph. Calling this method is
* equivalent to calling <tt>graph.match(subj, pred, null, contexts)</tt>
* and adding the objects of the matching statements to a set. See
* {@link Graph#match(Resource, URI, Value, Resource[])} for a description of
* the parameter values.
*/
public static Set<Value> getObjects(Graph graph, Resource subj, URI pred, Resource... contexts) {
Iterator<Value> iter = getObjectIterator(graph, subj, pred, contexts);
return Iterators.addAll(iter, new LinkedHashSet<Value>());
}
/**
* Gets the object of the statement(s) with the specified subject and
* predicate from the specified contexts in the supplied graph. The
* combination of subject, predicate and contexts must match at least one
* statement. In case more than one statement matches -- for example
* statements from multiple contexts -- all these statements should have the
* same object. A {@link GraphUtilException} is thrown if these conditions
* are not met. See {@link Graph#match(Resource, URI, Value, Resource[])} for
* a description of the parameter values.
*
* @return The object of the matched statement(s).
* @throws GraphUtilException
* If the statements matched by the specified parameters do not have
* exactly one unique object.
*/
public static Value getUniqueObject(Graph graph, Resource subj, URI pred, Resource... contexts)
throws GraphUtilException
{
Set<Value> objects = getObjects(graph, subj, pred, contexts);
if (objects.size() == 1) {
return objects.iterator().next();
}
else if (objects.isEmpty()) {
throw new GraphUtilException("Missing property: " + pred);
}
else {
throw new GraphUtilException("Multiple " + pred + " properties found");
}
}
/**
* Adds the specified statement and makes sure that no other statements are
* present in the Graph with the same subject and predicate. When contexts
* are specified, the (subj, pred) pair will occur exactly once in each
* context, else the (subj, pred) pair will occur exactly once in the entire
* Graph.
*/
public static void setUniqueObject(Graph graph, Resource subj, URI pred, Value obj, Resource... contexts) {
Iterator<Statement> iter = graph.match(subj, pred, null, contexts);
while (iter.hasNext()) {
iter.next();
iter.remove();
}
graph.add(subj, pred, obj, contexts);
}
/**
* Utility method that casts the return value of
* {@link #getUniqueObject(Graph, Resource, URI, Resource[])} to a Resource,
* or throws a GraphUtilException if that value is not a Resource.
*
* @return The object of the matched statement(s).
* @throws GraphUtilException
* If such an exception is thrown by
* {@link #getUniqueObject(Graph, Resource, URI, Resource[])} or if
* its return value is not a Resource.
*/
public static Resource getUniqueObjectResource(Graph graph, Resource subj, URI pred)
throws GraphUtilException
{
Value obj = getUniqueObject(graph, subj, pred);
if (obj instanceof Resource) {
return (Resource)obj;
}
else {
throw new GraphUtilException("Expected URI or blank node for property " + pred);
}
}
/**
* Utility method that casts the return value of
* {@link #getUniqueObject(Graph, Resource, URI, Resource[])} to a URI, or
* throws a GraphUtilException if that value is not a URI.
*
* @return The object of the matched statement(s).
* @throws GraphUtilException
* If such an exception is thrown by
* {@link #getUniqueObject(Graph, Resource, URI, Resource[])} or if
* its return value is not a URI.
*/
public static URI getUniqueObjectURI(Graph graph, Resource subj, URI pred)
throws GraphUtilException
{
Value obj = getUniqueObject(graph, subj, pred);
if (obj instanceof URI) {
return (URI)obj;
}
else {
throw new GraphUtilException("Expected URI for property " + pred);
}
}
/**
* Utility method that casts the return value of
* {@link #getUniqueObject(Graph, Resource, URI, Resource[])} to a Literal,
* or throws a GraphUtilException if that value is not a Literal.
*
* @return The object of the matched statement(s).
* @throws GraphUtilException
* If such an exception is thrown by
* {@link #getUniqueObject(Graph, Resource, URI, Resource[])} or if
* its return value is not a Literal.
*/
public static Literal getUniqueObjectLiteral(Graph graph, Resource subj, URI pred)
throws GraphUtilException
{
Value obj = getUniqueObject(graph, subj, pred);
if (obj instanceof Literal) {
return (Literal)obj;
}
else {
throw new GraphUtilException("Expected literal for property " + pred);
}
}
/**
* Gets the object of the statement(s) with the specified subject and
* predicate from the specified contexts in the supplied graph. If the
* combination of subject, predicate and contexts matches one or more
* statements, all these statements should have the same object. A
* {@link RepositoryConfigException} is thrown if this is not the case. See
* {@link Graph#match(Resource, URI, Value, Resource[])} for a description of
* the parameter values.
*
* @return The object of the matched statement(s), or <tt>null</tt> if no
* matching statements were found.
* @throws GraphUtilException
* If the statements matched by the specified parameters have more
* than one unique object.
*/
public static Value getOptionalObject(Graph graph, Resource subj, URI pred, Resource... contexts)
throws GraphUtilException
{
Set<Value> objects = getObjects(graph, subj, pred, contexts);
if (objects.isEmpty()) {
return null;
}
else if (objects.size() == 1) {
return objects.iterator().next();
}
else {
throw new GraphUtilException("Multiple " + pred + " properties found");
}
}
/**
* Utility method that casts the return value of
* {@link #getOptionalObject(Graph, Resource, URI, Resource[])} to a
* Resource, or throws a GraphUtilException if that value is not a Resource.
*
* @return The object of the matched statement(s), or <tt>null</tt> if no
* matching statements were found.
* @throws GraphUtilException
* If such an exception is thrown by
* {@link #getOptionalObject(Graph, Resource, URI, Resource[])} or if
* its return value is not a Resource.
*/
public static Resource getOptionalObjectResource(Graph graph, Resource subj, URI pred)
throws GraphUtilException
{
Value obj = getOptionalObject(graph, subj, pred);
if (obj == null || obj instanceof Resource) {
return (Resource)obj;
}
else {
throw new GraphUtilException("Expected URI or blank node for property " + pred);
}
}
/**
* Utility method that casts the return value of
* {@link #getOptionalObject(Graph, Resource, URI, Resource[])} to a URI, or
* throws a GraphUtilException if that value is not a URI.
*
* @return The object of the matched statement(s), or <tt>null</tt> if no
* matching statements were found.
* @throws GraphUtilException
* If such an exception is thrown by
* {@link #getOptionalObject(Graph, Resource, URI, Resource[])} or if
* its return value is not a URI.
*/
public static URI getOptionalObjectURI(Graph graph, Resource subj, URI pred)
throws GraphUtilException
{
Value obj = getOptionalObject(graph, subj, pred);
if (obj == null || obj instanceof URI) {
return (URI)obj;
}
else {
throw new GraphUtilException("Expected URI for property " + pred);
}
}
/**
* Utility method that casts the return value of
* {@link #getOptionalObject(Graph, Resource, URI, Resource[])} to a Literal,
* or throws a GraphUtilException if that value is not a Literal.
*
* @return The object of the matched statement(s), or <tt>null</tt> if no
* matching statements were found.
* @throws GraphUtilException
* If such an exception is thrown by
* {@link #getOptionalObject(Graph, Resource, URI, Resource[])} or if
* its return value is not a Literal.
*/
public static Literal getOptionalObjectLiteral(Graph graph, Resource subj, URI pred)
throws GraphUtilException
{
Value obj = getOptionalObject(graph, subj, pred);
if (obj == null || obj instanceof Literal) {
return (Literal)obj;
}
else {
throw new GraphUtilException("Expected literal for property " + pred);
}
}
/**
* Utility method that removes all statements matching the specified criteria
* from a graph.
*
* @param graph
* The graph to remove the statements from.
* @param subj
* The subject of the statements to match, <tt>null</tt> to match
* statements with any subject.
* @param pred
* The predicate of the statements to match, <tt>null</tt> to match
* statements with any predicate.
* @param obj
* The object of the statements to match, <tt>null</tt> to match
* statements with any object.
* @param contexts
* The contexts of the statements to match. If no contexts are
* specified, statements will match disregarding their context. If one
* or more contexts are specified, statements with a context matching
* one of these will match.
* @throws IllegalArgumentException
* If a <tt>null</tt>-array is specified as the value for
* <tt>contexts</tt>. See
* {@link OpenRDFUtil#verifyContextNotNull(Resource[])} for more
* info.
*/
public static void remove(Graph graph, Resource subj, URI pred, Value obj, Resource... contexts) {
Iterator<Statement> statements = graph.match(subj, pred, obj, contexts);
while (statements.hasNext()) {
statements.next();
statements.remove();
}
}
}