
it.uniroma2.art.semanticturkey.trivialinference.sail.TrivialInferencerConnection Maven / Gradle / Ivy
package it.uniroma2.art.semanticturkey.trivialinference.sail;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.eclipse.rdf4j.common.transaction.IsolationLevel;
import org.eclipse.rdf4j.common.transaction.IsolationLevels;
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.util.Models;
import org.eclipse.rdf4j.model.vocabulary.OWL;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.Dataset;
import org.eclipse.rdf4j.query.QueryEvaluationException;
import org.eclipse.rdf4j.query.QueryResults;
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.eclipse.rdf4j.sail.NotifyingSailConnection;
import org.eclipse.rdf4j.sail.SailConnection;
import org.eclipse.rdf4j.sail.SailConnectionListener;
import org.eclipse.rdf4j.sail.SailException;
import org.eclipse.rdf4j.sail.UpdateContext;
import org.eclipse.rdf4j.sail.helpers.NotifyingSailConnectionWrapper;
import org.eclipse.rdf4j.sail.helpers.SailWrapper;
import org.eclipse.rdf4j.sail.inferencer.InferencerConnectionWrapper;
/**
* A {@link SailConnection} for {@link TrivialInferencer}.
*
* @author Manuel Fiorelli
*
*/
public class TrivialInferencerConnection extends NotifyingSailConnectionWrapper {
private static abstract class GroundQuadruplePatternChange {
private final Resource subj;
private final IRI pred;
private final Value object;
private final Resource[] ctxs;
public GroundQuadruplePatternChange(Resource subj, IRI pred, Value obj, Resource...ctxs) {
this.subj = Objects.requireNonNull(subj);
this.pred = Objects.requireNonNull(pred);
this.object = Objects.requireNonNull(obj);
this.ctxs = Objects.requireNonNull(ctxs);
}
public Resource getSubject() {
return subj;
}
public IRI getPredicate() {
return pred;
}
public Value getObject() {
return object;
}
public Resource[] getContexts() {
return ctxs;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("subject", subj)
.append("predicate", pred)
.append("object", object)
.append("contexts", ctxs)
.toString();
}
public abstract void applyInverse(TrivialInferencerConnection trivialInferencerConnection, Set inverseProps);
}
private class GroundQuadruplePatternAddition extends GroundQuadruplePatternChange {
public GroundQuadruplePatternAddition(Resource subj, IRI pred, Value obj, Resource... ctxs) {
super(subj, pred, obj, ctxs);
}
@Override
public void applyInverse(TrivialInferencerConnection conn, Set inverseProps) {
for (IRI p2 : inverseProps) {
TrivialInferencerConnection.this.getWrappedConnection().addStatement((Resource)getObject(), p2, getSubject(), getContexts());
}
}
}
private class GroundQuadruplePatternRemoval extends GroundQuadruplePatternChange {
public GroundQuadruplePatternRemoval(Resource subj, IRI pred, Value obj, Resource... ctxs) {
super(subj, pred, obj, ctxs);
}
@Override
public void applyInverse(TrivialInferencerConnection trivialInferencerConnection, Set inverseProps) {
for (IRI p2 : inverseProps) {
TrivialInferencerConnection.this.getWrappedConnection().removeStatements((Resource)getObject(), p2, getSubject(), getContexts());
}
}
}
private TrivialInferencer sail;
private RepositoryConnection referenceSchemaConnection;
private RepositoryConnection editableSchemaConnection;
private List changesOfInterest = new LinkedList<>();
private SailConnectionListener listener = new SailConnectionListener() {
@Override
public void statementRemoved(Statement st) {
if (Objects.equals(st.getPredicate(), OWL.INVERSEOF)
|| Objects.equals(st.getPredicate(), RDF.TYPE)
&& Objects.equals(st.getObject(), OWL.SYMMETRICPROPERTY)) {
editableSchemaConnection.remove(st);
}
}
@Override
public void statementAdded(Statement st) {
if (Objects.equals(st.getPredicate(), OWL.INVERSEOF)
|| Objects.equals(st.getPredicate(), RDF.TYPE)
&& Objects.equals(st.getObject(), OWL.SYMMETRICPROPERTY)) {
editableSchemaConnection.add(st);
}
}
};
public TrivialInferencerConnection(TrivialInferencer sail, NotifyingSailConnection wrappedCon) {
super(wrappedCon);
this.sail = sail;
}
public boolean isPredicateInteresting(IRI pred) {
return referenceSchemaConnection.hasStatement(pred, OWL.INVERSEOF, null, true)
|| referenceSchemaConnection.hasStatement(pred, RDF.TYPE, OWL.SYMMETRICPROPERTY, true);
}
@Override
public void addStatement(Resource subj, IRI pred, Value obj, Resource... contexts) throws SailException {
super.addStatement(subj, pred, obj, contexts);
if (isPredicateInteresting(pred)) {
changesOfInterest.add(new GroundQuadruplePatternAddition(subj, pred, obj, contexts));
}
}
@Override
public void addStatement(UpdateContext modify, Resource subj, IRI pred, Value obj, Resource... contexts)
throws SailException {
super.addStatement(modify, subj, pred, obj, contexts);
if (isPredicateInteresting(pred)) {
changesOfInterest.add(new GroundQuadruplePatternAddition(subj, pred, obj, contexts));
}
}
@Override
public void removeStatement(UpdateContext modify, Resource subj, IRI pred, Value obj,
Resource... contexts) throws SailException {
super.removeStatement(modify, subj, pred, obj, contexts);
if (isPredicateInteresting(pred)) {
changesOfInterest.add(new GroundQuadruplePatternRemoval(subj, pred, obj, contexts));
}
}
@Override
public void removeStatements(Resource subj, IRI pred, Value obj, Resource... contexts)
throws SailException {
boolean interestingPredicate = false;
if (Objects.isNull(pred) || (interestingPredicate = isPredicateInteresting(pred))) {
if (subj != null & pred != null && obj != null && contexts.length > 0) { // ground deletion
changesOfInterest.add(new GroundQuadruplePatternRemoval(subj, pred, obj, contexts));
} else {
try (CloseableIteration extends Statement, SailException> it = super.getStatements(subj, pred, obj, false, contexts)) {
while (it.hasNext()) {
Statement s = it.next();
if (interestingPredicate || isPredicateInteresting(s.getPredicate())) {
changesOfInterest.add(new GroundQuadruplePatternRemoval(s.getSubject(), s.getPredicate(), s.getObject(), (Resource) s.getContext()));
}
}
}
}
}
super.removeStatements(subj, pred, obj, contexts);
}
@Override
public CloseableIteration extends Statement, SailException> getStatements(Resource subj, IRI pred, Value obj, boolean includeInferred, Resource... contexts) throws SailException {
flushUpdates();
return super.getStatements(subj, pred, obj, includeInferred, contexts);
}
@Override
public CloseableIteration extends BindingSet, QueryEvaluationException> evaluate(TupleExpr tupleExpr, Dataset dataset, BindingSet bindings, boolean includeInferred) throws SailException {
flushUpdates();
return super.evaluate(tupleExpr, dataset, bindings, includeInferred);
}
@Override
public boolean hasStatement(Resource subj, IRI pred, Value obj, boolean includeInferred, Resource... contexts) throws SailException {
flushUpdates();
return super.hasStatement(subj, pred, obj, includeInferred, contexts);
}
@Override
public CloseableIteration extends Resource, SailException> getContextIDs() throws SailException {
flushUpdates();
return super.getContextIDs();
}
@Override
public void begin() throws SailException {
begin(sail.getDefaultIsolationLevel());
}
@Override
public void begin(IsolationLevel level) throws SailException {
if (level == null) {
level = sail.getDefaultIsolationLevel();
}
super.begin(level);
Repository schemaCache = sail.getSchemaCache();
referenceSchemaConnection = schemaCache.getConnection();
referenceSchemaConnection.begin(IsolationLevels.SNAPSHOT);
referenceSchemaConnection.hasStatement(null, null, null, false);
editableSchemaConnection = schemaCache.getConnection();
editableSchemaConnection.begin(level);
editableSchemaConnection.hasStatement(null, null, null, false);
this.addConnectionListener(listener);
changesOfInterest.clear();
}
@Override
public void flush() throws SailException {
flushUpdates();
super.flush();
}
private void flushUpdates() throws SailException {
//getWrappedConnection().flush();
var it = changesOfInterest.iterator();
while (it.hasNext()) {
var rv = doTrivialInference(it.next());
if (rv) {
it.remove();
}
}
}
@Override
public void prepare() throws SailException {
flushUpdates();
super.prepare();
}
@Override
public void commit() throws SailException {
prepare();
referenceSchemaConnection.commit();
referenceSchemaConnection.close();
super.commit();
try {
try {
editableSchemaConnection.commit();
editableSchemaConnection.close();
} finally {
removeConnectionListener(listener);
}
} catch (Exception e) {
sail.invalidateCache();
}
}
@Override
public void rollback() throws SailException {
super.rollback();
changesOfInterest.clear();
try {
try {
editableSchemaConnection.rollback();
editableSchemaConnection.close();
} finally {
removeConnectionListener(listener);
}
} catch (Exception e) {
sail.invalidateCache();
}
}
@Override
public void close() throws SailException {
super.close();
if (referenceSchemaConnection != null && referenceSchemaConnection.isOpen()) {
referenceSchemaConnection.close();
}
if (editableSchemaConnection != null && editableSchemaConnection.isOpen()) {
editableSchemaConnection.close();
}
}
@FunctionalInterface
private interface EditOperation {
void execute(Resource subj, IRI pred, Value obj, Resource... contexts);
}
private boolean doTrivialInference(GroundQuadruplePatternChange change) {
if (!change.getObject().isResource()) {
return false;
}
if (!Objects.equals(change.getSubject(), change.getObject())) {
if (!getWrappedConnection().hasStatement((Resource)change.getObject(), null, null,false)) {
return false;
}
}
Set inverseProps = computePredicatesForInverseTriple(change.getPredicate());
change.applyInverse(this, inverseProps);
return true;
}
private Set computePredicatesForInverseTriple(IRI pred)
throws QueryEvaluationException, RepositoryException {
Set inverseProps = Models.objectIRIs(QueryResults
.asModel(referenceSchemaConnection.getStatements(pred, OWL.INVERSEOF, null, false)));
inverseProps.addAll(Models.subjectIRIs(QueryResults
.asModel(referenceSchemaConnection.getStatements(null, OWL.INVERSEOF, pred, false))));
if (referenceSchemaConnection.hasStatement(pred, RDF.TYPE, OWL.SYMMETRICPROPERTY, false)) {
inverseProps.add(pred);
}
return inverseProps;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy