package net.fortytwo.sesametools;
import info.aduna.iteration.CloseableIteration;
import org.openrdf.model.IRI;
import org.openrdf.model.Model;
import org.openrdf.model.Namespace;
import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.Value;
import org.openrdf.model.ValueFactory;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.RepositoryResult;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
/**
* An adapter which wraps a RepositoryConnection as a Graph
*
* @author Joshua Shinavier (http://fortytwo.net)
*/
public class RepositoryGraph implements Model {
private static final boolean INFER = false;
private final RepositoryConnection rc;
public RepositoryGraph(final RepositoryConnection rc) throws RepositoryException {
this.rc = rc;
}
@Override
public ValueFactory getValueFactory() {
return rc.getValueFactory();
}
@Override
public Model unmodifiable() {
throw new UnsupportedOperationException();
}
@Override
public Set<Namespace> getNamespaces() {
Function<Namespace, Namespace> f = identity();
return toSet(rc.getNamespaces(), f);
}
private <T> Function<T, T> identity() {
return new Function<T, T>() {
@Override
public T apply(T t) {
return t;
}
};
}
private <T, S> Set<S> toSet(CloseableIteration<T, RepositoryException> iter,
Function<T, S> mapping) {
Set<S> result = new HashSet<>();
try {
while (iter.hasNext()) {
result.add(mapping.apply(iter.next()));
}
} finally {
iter.close();
}
return result;
}
@Override
public void setNamespace(Namespace namespace) {
rc.setNamespace(namespace.getPrefix(), namespace.getName());
}
@Override
public Optional<Namespace> removeNamespace(String s) {
rc.removeNamespace(s);
return Optional.empty();
}
@Override
public boolean contains(Resource resource, IRI iri, Value value, Resource... resources) {
try (CloseableIteration<Statement, RepositoryException> iter
= rc.getStatements(resource, iri, value, resources)) {
return iter.hasNext();
}
}
@Override
public boolean add(Resource s, IRI p, Value o, Resource... c) {
try {
rc.begin();
rc.add(s, p, o, c);
rc.commit();
return true;
} catch (RepositoryException e) {
throw new RepositoryGraphRuntimeException(e);
}
}
@Override
public boolean clear(Resource... resources) {
rc.clear(resources);
// note: we don't know whether any statements are removed
return false;
}
@Override
public boolean remove(Resource resource, IRI iri, Value value, Resource... resources) {
rc.remove(resource, iri, value, resources);
// note: we don't know whether any statements are removed
return false;
}
@Override
public Model filter(Resource resource, IRI iri, Value value, Resource... resources) {
throw new UnsupportedOperationException();
}
@Override
public Set<Resource> subjects() {
Function<Statement, Resource> f = new Function<Statement, Resource>() {
@Override
public Resource apply(Statement statement) {
return statement.getSubject();
}
};
return toSet(rc.getStatements(null, null, null), f);
}
@Override
public Set<IRI> predicates() {
Function<Statement, IRI> f = new Function<Statement, IRI>() {
@Override
public IRI apply(Statement statement) {
return statement.getPredicate();
}
};
return toSet(rc.getStatements(null, null, null), f);
}
@Override
public Set<Value> objects() {
Function<Statement, Value> f = new Function<Statement, Value>() {
@Override
public Value apply(Statement statement) {
return statement.getObject();
}
};
return toSet(rc.getStatements(null, null, null), f);
}
// note: the returned iterator contains a CloseableIteration which will not be closed
@Override
public Iterator<Statement> match(Resource s, IRI p, Value o, Resource... c) {
RepositoryResult<Statement> result;
try {
result = rc.getStatements(s, p, o, INFER, c);
} catch (RepositoryException e) {
throw new RepositoryGraphRuntimeException(e);
}
return new RepositoryResultIterator(result);
}
@Override
public int size() {
try {
return (int) rc.size();
} catch (RepositoryException e) {
throw new RepositoryGraphRuntimeException(e);
}
}
@Override
public boolean isEmpty() {
return 0 == size();
}
@Override
public boolean contains(Object o) {
if (o instanceof Statement) {
Statement st = (Statement) o;
try {
try (RepositoryResult result = rc.getStatements(
st.getSubject(), st.getPredicate(), st.getObject(), INFER, st.getContext())) {
return result.hasNext();
}
} catch (Exception e) {
throw new RepositoryGraphRuntimeException(e);
}
} else {
return false;
}
}
@Override
public Iterator<Statement> iterator() {
return match(null, null, null);
}
@Override
public Object[] toArray() {
int size = size();
Object[] a = new Object[size];
if (size > 0) try {
int i = 0;
try (RepositoryResult result = rc.getStatements(null, null, null, INFER)) {
while (result.hasNext()) {
a[i] = result.next();
i++;
}
}
} catch (Exception e) {
throw new RepositoryGraphRuntimeException(e);
}
return a;
}
@Override
public <T> T[] toArray(T[] ts) {
// TODO: only Statement is acceptable as T
return (T[]) toArray();
}
@Override
public boolean add(Statement statement) {
try {
rc.add(statement);
} catch (RepositoryException e) {
throw new RepositoryGraphRuntimeException(e);
}
// the RepositoryConnection API does not provide an efficient means
// of knowing whether the repository was changed
return false;
}
@Override
public boolean remove(Object o) {
if (o instanceof Statement) {
Statement st = (Statement) o;
try {
rc.remove(st.getSubject(), st.getPredicate(), st.getObject(), st.getContext());
} catch (RepositoryException e) {
throw new RepositoryGraphRuntimeException(e);
}
}
// the RepositoryConnection API does not provide an efficient means of knowing whether a statement was removed
return false;
}
@Override
public boolean containsAll(Collection<?> objects) {
for (Object o : objects) {
if (!contains(o)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends Statement> statements) {
for (Statement s : statements) {
add(s);
}
return false;
}
@Override
public boolean removeAll(Collection<?> objects) {
for (Object o : objects) {
remove(o);
}
return false;
}
@Override
public boolean retainAll(Collection<?> objects) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
try {
rc.clear();
} catch (RepositoryException e) {
throw new RepositoryGraphRuntimeException(e);
}
}
private class RepositoryResultIterator implements Iterator<Statement> {
private final RepositoryResult result;
private RepositoryResultIterator(RepositoryResult result) {
this.result = result;
}
public boolean hasNext() {
try {
return result.hasNext();
} catch (RepositoryException e) {
throw new RepositoryGraphRuntimeException(e);
}
}
public Statement next() {
try {
return (Statement) result.next();
} catch (RepositoryException e) {
throw new RepositoryGraphRuntimeException(e);
}
}
public void remove() {
try {
result.remove();
} catch (RepositoryException e) {
throw new RepositoryGraphRuntimeException(e);
}
}
}
public class RepositoryGraphRuntimeException extends RuntimeException {
public RepositoryGraphRuntimeException(final Throwable cause) {
super(cause);
}
}
}