CheckOWLProfile.java 6.93 KB
Newer Older
package fr.emse.gitlab.saref.jobs;

import java.io.File;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;

import org.semanticweb.HermiT.ReasonerFactory;
import org.semanticweb.owl.explanation.api.Explanation;
import org.semanticweb.owl.explanation.api.ExplanationGenerator;
import org.semanticweb.owl.explanation.api.ExplanationGeneratorFactory;
import org.semanticweb.owl.explanation.impl.blackbox.Configuration;
import org.semanticweb.owl.explanation.impl.blackbox.ContractionStrategy;
import org.semanticweb.owl.explanation.impl.blackbox.DivideAndConquerContractionStrategy;
import org.semanticweb.owl.explanation.impl.blackbox.EntailmentCheckerFactory;
import org.semanticweb.owl.explanation.impl.blackbox.ExpansionStrategy;
import org.semanticweb.owl.explanation.impl.blackbox.InitialEntailmentCheckStrategy;
import org.semanticweb.owl.explanation.impl.blackbox.StructuralTypePriorityExpansionStrategy;
import org.semanticweb.owl.explanation.impl.blackbox.checker.BlackBoxExplanationGeneratorFactory;
import org.semanticweb.owl.explanation.impl.blackbox.checker.InconsistentOntologyExplanationGeneratorFactory;
import org.semanticweb.owl.explanation.impl.blackbox.checker.SatisfiabilityEntailmentCheckerFactory;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyIRIMapper;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.profiles.OWL2DLProfile;
import org.semanticweb.owlapi.profiles.OWLProfileReport;
import org.semanticweb.owlapi.profiles.OWLProfileViolation;
import org.semanticweb.owlapi.util.SimpleIRIMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CheckOWLProfile extends AbstractJobRunner<Void> {

	static final Logger LOG = LoggerFactory.getLogger(CheckOWLProfile.class);
	static final String SHACL_WARNING = "http://www.w3.org/ns/shacl#Warning";
	static final String SHACL_VIOLATION = "http://www.w3.org/ns/shacl#Violation";

	static final String SELECT_VIOLATION = "PREFIX sh: <http://www.w3.org/ns/shacl#>\n"
			+ "SELECT ?focusNode ?resultMessage ?resultPath ?value ?severity\n" + "WHERE {   \n"
			+ "    ?violation sh:focusNode ?focusNode .\n" + "    ?violation sh:resultMessage ?resultMessage .\n"
			+ "    ?violation sh:resultSeverity ?severity .\n"
			+ "      OPTIONAL { ?violation sh:resultPath ?resultPath . }\n"
			+ "      OPTIONAL { ?violation sh:value ?value . } \n" + "}";

	static final Map<String, String> PREFIXES = new HashMap<String, String>();
	static {
		PREFIXES.put("owl", "http://www.w3.org/2002/07/owl#");
		PREFIXES.put("rdfs", "http://www.w3.org/2000/01/rdf-schema#");
		PREFIXES.put("xsd", "http://www.w3.org/2001/XMLSchema#");
		PREFIXES.put("dcterms", "http://purl.org/dc/terms/");
		PREFIXES.put("vann", "http://purl.org/vocab/vann/");
		PREFIXES.put("schema", "http://schema.org/");
		PREFIXES.put("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
		PREFIXES.put("voaf", "http://purl.org/vocommons/voaf#");
		PREFIXES.put("dce", "http://purl.org/dc/elements/1.1/");
		PREFIXES.put("dct", "http://purl.org/dc/terms/");
		PREFIXES.put("xml", "http://www.w3.org/XML/1998/namespace/");
		PREFIXES.put("saref", "https://saref.etsi.org/core/");
	}
	
	private final Set<OWLOntologyIRIMapper> mappers;

	public CheckOWLProfile(File dir, Set<OWLOntologyIRIMapper> mappers) {
		super("Check consistency of the ontology", dir);
		this.mappers = mappers;
	}

	@Override
	protected void doJob0() {
		String repoName = getRepoName();
		String ontologyName = repoName.equals("saref-core") ? "saref.ttl" : repoName + ".ttl";

		File ontologyFile = new File(directory, "ontology/" + ontologyName);
		final OWLDataFactory dataFactory = OWLManager.getOWLDataFactory();
		final OWLOntologyManager ontologyManager = OWLManager.createOWLOntologyManager();

		ontologyManager.setIRIMappers(mappers);

		final Supplier<OWLOntologyManager> m = () -> ontologyManager;
		final OWLOntology ontology;
		try {
			ontology = ontologyManager.loadOntologyFromOntologyDocument(ontologyFile);
		} catch (OWLOntologyCreationException ex) {
			error("Error while loading the ontology in OWLAPI", ex);
			return;
		}
		final OWLProfileReport report = new OWL2DLProfile().checkOntology(ontology);
		for (OWLProfileViolation v : report.getViolations()) {
			failure(v.toString());
		}
		final ReasonerFactory reasonerFactory = new ReasonerFactory();
		final InconsistentOntologyExplanationGeneratorFactory inconsistentOntologyExplanationFeneratorFactory = new InconsistentOntologyExplanationGeneratorFactory(
				reasonerFactory, ontologyManager.getOWLDataFactory(), m, 10000);
		final ExplanationGenerator<OWLAxiom> gen = inconsistentOntologyExplanationFeneratorFactory
				.createExplanationGenerator(ontology);
		final OWLAxiom inc = dataFactory.getOWLSubClassOfAxiom(dataFactory.getOWLThing(), dataFactory.getOWLNothing());
		try {
			final Set<Explanation<OWLAxiom>> incExplanation = gen.getExplanations(inc, 10);
			if (!incExplanation.isEmpty()) {
				StringWriter sw = new StringWriter();
				incExplanation.forEach(e -> {
					sw.append(e.getAxioms().toString()).append("\n");
				});
				error("The ontology is inconsistent.", "Explanations from OWLApi", sw.toString());
				return;
			}
		} catch (Exception ex) {
			error("Error while reasoning with the ontology", ex);
			return;
		}
		final EntailmentCheckerFactory<OWLAxiom> checker = new SatisfiabilityEntailmentCheckerFactory(reasonerFactory,
				m);
		final ExpansionStrategy<OWLAxiom> expansionStrategy = new StructuralTypePriorityExpansionStrategy<>(
				InitialEntailmentCheckStrategy.PERFORM, m);
		final ContractionStrategy<OWLAxiom> contractionStrategy = new DivideAndConquerContractionStrategy<>();
		final Configuration<OWLAxiom> config = new Configuration<>(checker, expansionStrategy, contractionStrategy,
				null, m);
		final ExplanationGeneratorFactory<OWLAxiom> explanationGeneratorFactory = new BlackBoxExplanationGeneratorFactory<OWLAxiom>(
				config);
		final ExplanationGenerator<OWLAxiom> fgen = explanationGeneratorFactory.createExplanationGenerator(ontology);
		ontology.classesInSignature().forEach(c -> {
			OWLAxiom axiom = dataFactory.getOWLSubClassOfAxiom(c, dataFactory.getOWLNothing());
			Set<Explanation<OWLAxiom>> explanation = fgen.getExplanations(axiom, 10);
			if (!explanation.isEmpty()) {
				StringWriter sw = new StringWriter();
				explanation.forEach(e -> {
					sw.append(e.getAxioms().toString()).append("\n");
				});
				failure(String.format("Class %s cannot be satisfied.", c), "Explanations from OWLApi", sw.toString());
			}
		});
	}

}