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

openllet.Openllint Maven / Gradle / Ivy

There is a newer version: 2.6.5
Show newest version
// Copyright (c) 2006 - 2008, Clark & Parsia, LLC. 
// This source code is available under the terms of the Affero General Public
// License v3.
//
// Please see LICENSE.txt for full license terms, including the availability of
// proprietary exceptions.
// Questions, comments, or requests for clarification: [email protected]

package openllet;

import static openllet.OpenlletCmdOptionArg.NONE;
import static openllet.OpenlletCmdOptionArg.REQUIRED;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
import openllet.core.utils.FileUtils;
import openllet.pellint.lintpattern.LintPattern;
import openllet.pellint.lintpattern.LintPatternLoader;
import openllet.pellint.lintpattern.axiom.AxiomLintPattern;
import openllet.pellint.lintpattern.ontology.OntologyLintPattern;
import openllet.pellint.model.Lint;
import openllet.pellint.model.OntologyLints;
import openllet.pellint.model.Severity;
import openllet.pellint.rdfxml.OWLSyntaxChecker;
import openllet.pellint.rdfxml.RDFLints;
import openllet.pellint.rdfxml.RDFModel;
import openllet.pellint.rdfxml.RDFModelReader;
import openllet.pellint.rdfxml.RDFModelWriter;
import openllet.pellint.util.CollectionUtil;
import openllet.pellint.util.IllegalPellintArgumentException;
import openllet.shared.tools.Log;
import org.apache.jena.rdf.model.Statement;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.io.StreamDocumentTarget;
import org.semanticweb.owlapi.io.XMLUtils;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyChangeException;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;
import org.semanticweb.owlapi.model.UnknownOWLOntologyException;
import org.semanticweb.owlapi.profiles.OWL2DLProfile;
import org.semanticweb.owlapi.profiles.OWLProfileReport;
import org.semanticweb.owlapi.profiles.OWLProfileViolation;
import org.semanticweb.owlapi.util.OWLOntologyImportsClosureSetProvider;
import org.semanticweb.owlapi.util.OWLOntologyMerger;

/**
 * 

* Title: Pellint Main class *

*

* Description: Provides CLI and API interfaces for the Pellint program *

*

* Copyright: Copyright (c) 2008 *

*

* Company: Clark & Parsia, LLC. *

* * @author Harris Lin */ public class Openllint extends OpenlletCmdApp { private static final String CONFIGURATION_PROPERTY_NAME = "pellint.configuration"; private static final String DEFAULT_CONFIGURATION_FILE_NAME = "pellint.properties"; private static final IRI MERGED_ONTOLOGY_URI = IRI.create("tag:clarkparsia.com,2008:pellint:merged"); private boolean _doRDF = true; private boolean _doOWL = true; private boolean _doRootOnly = false; private String _inputOntologyPath; private String _outputOntologyPath; public Openllint() { } @Override public void parseArgs(final String[] args) { super.parseArgs(args); final String only = _options.getOption("only").getValueAsString(); if (only == null) { setDoRDF(true); setDoOWL(true); } else if (only.equalsIgnoreCase("RDF")) { setDoRDF(true); setDoOWL(false); } else if (only.equalsIgnoreCase("OWL")) { setDoRDF(false); setDoOWL(true); } else throw new OpenlletCmdException("Invalid argument to lint --only: " + only); setDoRootOnly(_options.getOption("root-only").getValueAsBoolean()); if (getInputFiles().length > 1) throw new OpenlletCmdException("lint doesn't handle multiple input files"); setInputOntologyPath(getInputFiles()[0]); setOutputOntologyPath(_options.getOption("fix").getValueAsString()); } @Override public String getAppId() { return "Pellint: Lint tool for OWL ontologies"; } @Override public String getAppCmd() { final String s1 = "openllet lint [options] ...\n"; final String s2 = "Note: openllet lint without arguments prints the lint report to STDOUT."; final String lb = System.getProperty("line.separator"); final String s = s1 + lb + lb + s2; return s; } @Override public OpenlletCmdOptions getOptions() { final OpenlletCmdOptions options = getGlobalOptions(); OpenlletCmdOption option = new OpenlletCmdOption("fix"); option.setShortOption("f"); option.setIsMandatory(false); option.setType("File"); option.setDescription("Apply any applicable fixes to ontology lints and save a new ontology to file in RDF/XML format."); option.setArg(REQUIRED); options.add(option); option = new OpenlletCmdOption("root-only"); option.setIsMandatory(false); option.setDefaultValue(false); option.setType("boolean"); option.setDescription("Lint the root ontology only; ignore its imports."); option.setArg(NONE); options.add(option); option = new OpenlletCmdOption("only"); option.setShortOption("o"); option.setIsMandatory(false); option.setType("RDF | OWL"); option.setDescription("Analyze only RDF declarations or OWL axioms, not both."); option.setArg(REQUIRED); options.add(option); option = new OpenlletCmdOption("exclude-valid-punning"); option.setIsMandatory(false); option.setDefaultValue(false); option.setDescription("Excludes valid punnings to be reported by lint. OWL 2 allows resources\n" + "to have certain multiple types (known as punning), e.g. a resource can\n" + "be both a class and an _individual. However, certain punnings are not\n" + "allowed under any _condition, e.g. a resource cannot be both a datatype\n" + "property and an object property. All punnings are reported by default\n" + "but if this option is used punnings valid for OWL 2 will be excluded\n" + "from the report."); option.setArg(NONE); options.add(option); return options; } public void setDoRDF(final boolean v) { _doRDF = v; } public void setDoOWL(final boolean v) { _doOWL = v; } public void setDoRootOnly(final boolean v) { _doRootOnly = v; } public void setInputOntologyPath(final String v) { _inputOntologyPath = v; } public void setOutputOntologyPath(final String v) { _outputOntologyPath = v; } public static OntologyLints lint(final List axiomLintPatterns, final List ontologyLintPatterns, final OWLOntology ontology) { final OntologyLints ontologyLints = new OntologyLints(ontology); ontology.axioms().forEach(axiom -> { for (final AxiomLintPattern pattern : axiomLintPatterns) { final Lint lint = pattern.match(ontology, axiom); if (lint != null) ontologyLints.addLint(pattern, lint); } }); for (final OntologyLintPattern pattern : ontologyLintPatterns) { final List lints = pattern.match(ontology); if (!lints.isEmpty()) ontologyLints.addLints(pattern, lints); } ontologyLints.sort((lint0, lint1) -> { final Severity severity0 = lint0.getSeverity(); final Severity severity1 = lint1.getSeverity(); if (severity0 != null && severity1 != null) return -severity0.compareTo(severity1); final Set classes0 = lint0.getParticipatingClasses(); final Set classes1 = lint1.getParticipatingClasses(); if (classes0 == null || classes1 == null) return 0; if (classes0.size() != 1 || classes1.size() != 1) return 0; final IRI uri0 = classes0.iterator().next().getIRI(); final IRI uri1 = classes1.iterator().next().getIRI(); if (uri0 == null || uri1 == null) return 0; final String fragment0 = XMLUtils.getNCNameSuffix(uri0); final String fragment1 = XMLUtils.getNCNameSuffix(uri1); if (fragment0 == null || fragment1 == null) return 0; return fragment0.compareTo(fragment1); }); return ontologyLints; } @Override public void run() { try { if (_inputOntologyPath == null) throw new IllegalPellintArgumentException("Input ontology is not specified"); if (_doRDF) runLintForRDFXML(); if (_doOWL) runLintForOWL(); } catch (final Exception e) { e.printStackTrace(); } } private void runLintForRDFXML() throws IOException { final RDFModelReader reader = new RDFModelReader(); RDFModel rootModel = null; try { rootModel = reader.read(_inputOntologyPath, !_doRootOnly); } catch (final Exception e) { throw new OpenlletCmdException(e); } final OWLSyntaxChecker checker = new OWLSyntaxChecker(); checker.setExcludeValidPunnings(_options.getOption("exclude-valid-punning").getValueAsBoolean()); final RDFLints lints = checker.validate(rootModel); output(lints.toString()); if (_outputOntologyPath != null && !_doOWL) { final List missingStmts = lints.getMissingStatements(); rootModel.addAllStatementsWithExistingBNodesOnly(missingStmts); final RDFModelWriter writer = new RDFModelWriter(); writer.write(new FileOutputStream(new File(_outputOntologyPath)), rootModel); output("Saved to " + _outputOntologyPath); } } private void runLintForOWL() throws OWLOntologyCreationException, OWLOntologyChangeException, UnknownOWLOntologyException, OWLOntologyStorageException, FileNotFoundException { final LintPatternLoader patternLoader = new LintPatternLoader(loadProperties()); final List axiomLintPatterns = patternLoader.getAxiomLintPatterns(); final List ontologyLintPatterns = patternLoader.getOntologyLintPatterns(); logLoadedPatterns(axiomLintPatterns, ontologyLintPatterns); final OWLOntologyManager manager = OWLManager.createOWLOntologyManager(); OWLOntology rootOntology = null; try { final String inputOntologyURI = FileUtils.toURI(_inputOntologyPath); rootOntology = manager.loadOntology(IRI.create(inputOntologyURI)); } catch (final Exception e) { throw new OpenlletCmdException(e); } output(getOWL2DLProfileViolations(rootOntology)); final OntologyLints rootOntologyLints = lint(axiomLintPatterns, ontologyLintPatterns, rootOntology); output(rootOntologyLints.toString()); if (!_doRootOnly) { final Set importClosures = manager.importsClosure(rootOntology).collect(Collectors.toSet()); importClosures.remove(rootOntology); if (importClosures.isEmpty()) output("\n" + rootOntology.getOntologyID() + " does not import other ontologies."); else { for (final OWLOntology importedOntology : importClosures) { output(getOWL2DLProfileViolations(importedOntology)); final OntologyLints importedOntologyLints = lint(axiomLintPatterns, ontologyLintPatterns, importedOntology); output(importedOntologyLints.toString()); } final OWLOntology mergedImportClosure = buildMergedImportClosure(manager, rootOntology); final OntologyLints mergedOntologyLints = lint(axiomLintPatterns, ontologyLintPatterns, mergedImportClosure); mergedOntologyLints.setRootOntology(rootOntology); output(mergedOntologyLints.toString()); } } if (_outputOntologyPath != null) { final Set unreparableLints = rootOntologyLints.applyFix(manager); if (!unreparableLints.isEmpty()) { output("Unreparable lints:"); for (final Lint lint : unreparableLints) output(lint.toString()); } manager.saveOntology(rootOntologyLints.getOntology(), new StreamDocumentTarget(new FileOutputStream(_outputOntologyPath))); output("Saved to " + _outputOntologyPath); } } private String getOWL2DLProfileViolations(final OWLOntology ontology) { final OWL2DLProfile owl2Profile = new OWL2DLProfile(); final OWLProfileReport profileReport = owl2Profile.checkOntology(ontology); if (profileReport.isInProfile()) return "No OWL 2 DL violations found for ontology " + ontology.getOntologyID().toString(); final StringBuffer result = new StringBuffer(); result.append("\n=========================================================\n"); result.append("OWL 2 DL violations found for ontology ").append(ontology.getOntologyID().toString()).append(":\n"); for (final OWLProfileViolation violation : profileReport.getViolations()) { result.append(violation.toString()); result.append("\n"); } return result.toString(); } private void logLoadedPatterns(final List axiomLintPatterns, final List ontologyLintPatterns) { if (!getLogger().isLoggable(Level.FINE)) return; final List allPatterns = CollectionUtil. copy(axiomLintPatterns); allPatterns.addAll(ontologyLintPatterns); Collections.sort(allPatterns, (p0, p1) -> p0.getName().compareTo(p1.getName())); getLogger().fine("Loaded lint patterns:"); for (final LintPattern pattern : allPatterns) { final StringBuilder builder = new StringBuilder(); builder.append(" "); if (pattern.isFixable()) builder.append("[fixable] "); else builder.append(" "); builder.append(pattern.getName()); getLogger().fine(builder.toString()); } } private static OWLOntology buildMergedImportClosure(final OWLOntologyManager manager, final OWLOntology rootOntology) throws OWLOntologyCreationException, OWLOntologyChangeException { final OWLOntologyImportsClosureSetProvider importClosureSetProvider = new OWLOntologyImportsClosureSetProvider(manager, rootOntology); final OWLOntologyMerger merger = new OWLOntologyMerger(importClosureSetProvider); return merger.createMergedOntology(manager, MERGED_ONTOLOGY_URI); } private static Properties loadProperties() { final Properties properties = new Properties(); final String configFile = System.getProperty(CONFIGURATION_PROPERTY_NAME); URL configURL = null; // if the user has not specified the pellint.configuration property, // we search for the file "pellint.properties" if (configFile == null) { configURL = Openllint.class.getClassLoader().getResource(DEFAULT_CONFIGURATION_FILE_NAME); if (configURL == null) _logger.severe("Cannot find Openllint configuration file " + DEFAULT_CONFIGURATION_FILE_NAME); } else { try { configURL = new URL(configFile); } catch (final MalformedURLException e) { e.printStackTrace(); // so, resource is not a URL - attempt to get the resource from // the class path configURL = Openllint.class.getClassLoader().getResource(configFile); } if (configURL == null) _logger.severe("Cannot find Openllint configuration file " + configFile); } if (configURL != null) try { properties.load(configURL.openStream()); } catch (final FileNotFoundException e) { Log.error(_logger, "Openllint configuration file cannot be found", e); } catch (final IOException e) { Log.error(_logger, "I/O error while reading Openllet configuration file", e); } return properties; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy