All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.uniroma2.art.semanticturkey.trivialinference.sail.TrivialInferencerConnection Maven / Gradle / Ivy

There is a newer version: 13.1
Show newest version
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 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 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 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 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