/**
* Copyright (c) 2013/2014 Verein zur Foerderung der IT-Sicherheit in Oesterreich (SBA).
* The work has been developed in the TIMBUS Project and the above-mentioned are Members of the TIMBUS Consortium.
* TIMBUS is supported by the European Union under the 7th Framework Programme for research and technological
* development and demonstration activities (FP7/2007-2013) under grant agreement no. 269940.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including without
* limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTIBITLY, or FITNESS FOR A PARTICULAR
* PURPOSE. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise,
* unless required by applicable law or agreed to in writing, shall any Contributor be liable for damages, including
* any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this
* License or out of the use or inability to use the Work.
* See the License for the specific language governing permissions and limitation under the License.
*/
package net.timbusproject.extractors.modules.tavernaextractor;
import java.io.File;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import net.timbusproject.extractors.modules.tavernaextractor.provenance.ProvenanceAccessClient;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAssertionAxiom;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLDataPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLIndividual;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLObjectPropertyAssertionAxiom;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;
import org.semanticweb.owlapi.reasoner.ConsoleProgressMonitor;
import org.semanticweb.owlapi.reasoner.NodeSet;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.reasoner.OWLReasonerConfiguration;
import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
import org.semanticweb.owlapi.reasoner.SimpleConfiguration;
import org.semanticweb.owlapi.reasoner.structural.StructuralReasonerFactory;
import org.semanticweb.owlapi.vocab.OWL2Datatype;
/**
* Used to extend an existing ontology with provenance information.
*
* @author munterberger
*
*/
public class ExtendedOWL {
private ProvenanceAccessClient provenanceAccessClient;
private List<CSVEntry> provenanceEntries;
private OWLOntologyManager owlManager;
private OWLOntology ontology;
private OWLDataFactory owlDataFactory;
private Set<OWLAnnotation> EMPTY_OWL_ANNOTATIONS = Collections.<OWLAnnotation> emptySet();
private Logger logger = LogManager.getLogger("ExtendedOWL");
/**
* PREMIS Ontology
*/
final IRI IRI_PREMIS = IRI.create("http://multimedialab.elis.ugent.be/users/samcoppe/ontologies/Premis/premis.owl");
final IRI IRI_ARTIFACT = IRI.create("http://timbus.teco.edu/ontologies/DIO.owl#Artifact");
final OWLObjectProperty PREMIS_LINKING_SOURCE_OBJECTPROPERTY = OWLManager.getOWLDataFactory().getOWLObjectProperty(
IRI.create(IRI_PREMIS.toString() + "#", "linkingSourceObject"));
final OWLObjectProperty PREMIS_LINKING_HASOBJECTCHARACTERISTICS = OWLManager.getOWLDataFactory()
.getOWLObjectProperty(IRI.create(IRI_PREMIS.toString() + "#", "hasObjectCharacteristics"));
final OWLObjectProperty PREMIS_LINKING_HASFORMAT = OWLManager.getOWLDataFactory().getOWLObjectProperty(
IRI.create(IRI_PREMIS.toString() + "#", "hasFormat"));
final OWLObjectProperty PREMIS_LINKING_HASFORMATREGISTRY = OWLManager.getOWLDataFactory().getOWLObjectProperty(
IRI.create(IRI_PREMIS.toString() + "#", "hasFormatRegistry"));
final OWLClass PREMIS_OBJECTCHAR_CLASS = OWLManager.getOWLDataFactory().getOWLClass(
IRI.create(IRI_PREMIS.toString() + "#", "ObjectCharacteristics"));
final OWLClass PREMIS_FROMAT_CLASS = OWLManager.getOWLDataFactory().getOWLClass(
IRI.create(IRI_PREMIS.toString() + "#", "Format"));
final OWLClass PREMIS_FROMATREGISTRY_CLASS = OWLManager.getOWLDataFactory().getOWLClass(
IRI.create(IRI_PREMIS.toString() + "#", "FormatRegistry"));
final OWLClass PREMIS_OBJECTCHAR_PROPERTY = OWLManager.getOWLDataFactory().getOWLClass(
IRI.create(IRI_PREMIS.toString() + "#", "hasObjectCharacteristics"));
final OWLClass PREMIS_FILE_CLASS = OWLManager.getOWLDataFactory().getOWLClass(
IRI.create(IRI_PREMIS.toString() + "#", "File"));
/**
* PRONOM PUID
*/
public static final String PRONOM_REGISTRY_KEY_URI = "http://www.loc.gov/premis/rdf/v1#hasFormatRegistryKey";
public static final IRI PRONOM_REGISTRY_KEY_IRI = IRI.create(PRONOM_REGISTRY_KEY_URI);
public static final String PRONOM_REGISTRY_NAME_URI = "http://www.loc.gov/premis/rdf/v1#hasFormatRegistryName";
public static final IRI PRONOM_REGISTRY_NAME_IRI = IRI.create(PRONOM_REGISTRY_NAME_URI);
public ExtendedOWL() {
logger.setLevel(Level.DEBUG);
}
/**
* Just for testing purpose
*
* @param args
* @throws OWLOntologyCreationException
* @throws OWLOntologyStorageException
*/
public static void main(String[] args) throws OWLOntologyCreationException, OWLOntologyStorageException {
File ontologyFile = new File("C:\\Users\\munterberger\\Documents\\GeneratedOWLs\\MusicClassification.owl");
File droidCSVReport = new File("C:\\Users\\munterberger\\Desktop\\tmp\\myDroidFile.droid.csv");
ExtendedOWL extendOWL = new ExtendedOWL();
extendOWL.process(ontologyFile, droidCSVReport);
}
/**
* Adds PRONOM format information to an existing ontology.
*
* @param ontologyFile
* file which gets updated with provenance information.
* @param droidCSVReport
* DROID generated report file in CSV format.
* @throws OWLOntologyCreationException
* @throws OWLOntologyStorageException
*/
public void process(File ontologyFile, File droidCSVReport) throws OWLOntologyCreationException,
OWLOntologyStorageException {
if (ontologyFile == null || droidCSVReport == null) {
throw new IllegalArgumentException("Either 'ontologyFile' or 'droidCSVReport' file is null.");
}
// (1) Load OWL Model
owlManager = OWLManager.createOWLOntologyManager();
ontology = owlManager.loadOntologyFromOntologyDocument(ontologyFile);
owlDataFactory = owlManager.getOWLDataFactory();
// (2) Read entries from DROID CSV report file
provenanceAccessClient = new ProvenanceAccessClient();
provenanceEntries = provenanceAccessClient.filterEntries(provenanceAccessClient.readCSV(droidCSVReport));
if (provenanceEntries.isEmpty()) {
logger.info("Nothing to apply due to an empty provenance entry set.");
return;
}
if (ontology != null) {
logger.info("Start processing ...");
// initiate reasoner
OWLReasonerFactory reasonerFactory = new StructuralReasonerFactory();
ConsoleProgressMonitor progressMonitor = new ConsoleProgressMonitor();
OWLReasonerConfiguration config = new SimpleConfiguration(progressMonitor);
OWLReasoner reasoner = reasonerFactory.createReasoner(ontology, config);
reasoner.precomputeInferences();
OWLClass artifact = owlDataFactory.getOWLClass(IRI_ARTIFACT);
NodeSet<OWLNamedIndividual> individualsNodeSet = reasoner.getInstances(artifact, true);
Set<OWLNamedIndividual> individuals = individualsNodeSet.getFlattened();
logger.debug("Identified "+provenanceEntries.size()+" entry(ies).");
// iterate over all entries found in the DROID CSV report
for (CSVEntry entry : provenanceEntries) {
logger.debug(entry.toString());
for (OWLNamedIndividual ind : individuals) {
if (hasAnnotationValue(ind, ontology, entry.getNameForExtensionUsage()) && entry.getPUID() != null
&& !entry.getPUID().isEmpty()) {
logger.info("Found individual (" + ind.getIRI() + ") which has to be extended with PUID ("
+ entry.getPUID() + ")");
updateOWL(ind, entry);
}
}
}
// update ontology
logger.info("Update existing ontology (" + ontologyFile.getAbsolutePath() + ")");
owlManager.saveOntology(ontology);
}
}
// add a new individual to existing ontology
private void updateOWL(OWLNamedIndividual ind, CSVEntry entry) {
Queue<AddAxiom> changes = new LinkedList<>();
// Add File assertion
OWLClassAssertionAxiom swoClassAxiom_File = owlDataFactory.getOWLClassAssertionAxiom(PREMIS_FILE_CLASS, ind);
changes.add(new AddAxiom(ontology, swoClassAxiom_File));
// Create new ObjectCharacteristics
OWLNamedIndividual swoIndividual_ObjectCharacteristics = owlDataFactory.getOWLNamedIndividual(IRI.create("#",
replaceWhitespace(entry.getNameForExtensionUsage()) + "Characteristics"));
OWLClassAssertionAxiom swoClassAxiom_ObjectCharacteristics = owlDataFactory.getOWLClassAssertionAxiom(
PREMIS_OBJECTCHAR_CLASS, swoIndividual_ObjectCharacteristics);
changes.add(new AddAxiom(ontology, swoClassAxiom_ObjectCharacteristics));
changes.add(linkIndividuals(PREMIS_LINKING_HASOBJECTCHARACTERISTICS, ind, swoIndividual_ObjectCharacteristics));
// Create new Format
OWLNamedIndividual swoIndividual_Format = owlDataFactory.getOWLNamedIndividual(IRI.create("#",
replaceWhitespace(entry.getFORMAT_NAME())));
OWLClassAssertionAxiom swoClassAxiom_Format = owlDataFactory.getOWLClassAssertionAxiom(PREMIS_FROMAT_CLASS,
swoIndividual_Format);
changes.add(new AddAxiom(ontology, swoClassAxiom_Format));
changes.add(linkIndividuals(PREMIS_LINKING_HASFORMAT, swoIndividual_ObjectCharacteristics, swoIndividual_Format));
// Create new FormatRegistry
OWLNamedIndividual swoIndividual_FormatRegistry = owlDataFactory.getOWLNamedIndividual(IRI.create("#",
"PronomRegistry[" + entry.getNameForExtensionUsage() + "]"));
OWLClassAssertionAxiom swoClassAxiom_FormatRegistry = owlDataFactory.getOWLClassAssertionAxiom(
PREMIS_FROMATREGISTRY_CLASS, swoIndividual_FormatRegistry);
changes.add(new AddAxiom(ontology, swoClassAxiom_FormatRegistry));
changes.add(linkIndividuals(PREMIS_LINKING_HASFORMATREGISTRY, swoIndividual_Format,
swoIndividual_FormatRegistry));
// Create new FormatRegistry Data Property Assertion
OWLDataProperty owlp = owlDataFactory.getOWLDataProperty(PRONOM_REGISTRY_KEY_IRI);
OWLLiteral owlLiteral = owlDataFactory.getOWLLiteral("info:pronom/" + entry.getPUID(),
OWL2Datatype.RDFS_LITERAL);
OWLDataPropertyAssertionAxiom addProp = owlDataFactory.getOWLDataPropertyAssertionAxiom(owlp,
swoIndividual_FormatRegistry, owlLiteral);
changes.add(new AddAxiom(ontology, addProp));
OWLDataProperty owlp2 = owlDataFactory.getOWLDataProperty(PRONOM_REGISTRY_NAME_IRI);
OWLLiteral owlLiteral2 = owlDataFactory.getOWLLiteral("http://www.nationalarchives.gov.uk/PRONOM/",
OWL2Datatype.RDFS_LITERAL);
OWLDataPropertyAssertionAxiom addProp2 = owlDataFactory.getOWLDataPropertyAssertionAxiom(owlp2,
swoIndividual_FormatRegistry, owlLiteral2);
changes.add(new AddAxiom(ontology, addProp2));
// apply all changes to the Model
for (AddAxiom addAxiom : changes) {
owlManager.applyChange(addAxiom);
}
}
// checks if an individual has a specific annotation value
private boolean hasAnnotationValue(OWLNamedIndividual owlNamedIndividual, OWLOntology ontology, String value) {
for (OWLAnnotation a : owlNamedIndividual.getAnnotations(ontology)) {
if (a.getValue() instanceof OWLLiteral) {
OWLLiteral literal = (OWLLiteral) a.getValue();
if (literal.getLiteral().equals(value)) {
return true;
}
}
}
return false;
}
private AddAxiom linkIndividuals(OWLObjectProperty objectProperty, OWLIndividual source, OWLIndividual target) {
// Link the event individual to the entities
OWLObjectPropertyAssertionAxiom linkingSourceObjectPropertyAxiom = owlDataFactory
.getOWLObjectPropertyAssertionAxiom(objectProperty, source, target, EMPTY_OWL_ANNOTATIONS);
owlManager.applyChange(new AddAxiom(ontology, linkingSourceObjectPropertyAxiom));
OWLObjectPropertyAssertionAxiom linkingOutcomeObjectPropertyAxiom = owlDataFactory
.getOWLObjectPropertyAssertionAxiom(objectProperty, source, target, EMPTY_OWL_ANNOTATIONS);
return new AddAxiom(ontology, linkingOutcomeObjectPropertyAxiom);
}
// is used to replace whitespace in format names. like 'MPEG 2 Transport Stream' -> 'MPEG_2_Transport_Stream'
private String replaceWhitespace(String original) {
return original.replace(" ", "_");
}
}