
org.dspace.rdf.conversion.MetadataRDFMapping Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dspace-api Show documentation
Show all versions of dspace-api Show documentation
DSpace core data model and service APIs.
The newest version!
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.rdf.conversion;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.commons.lang3.StringUtils;
import org.apache.jena.rdf.model.Literal;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.rdf.model.Statement;
import org.apache.jena.rdf.model.StmtIterator;
import org.apache.jena.vocabulary.RDF;
import org.apache.logging.log4j.Logger;
/**
* @author Pascal-Nicolas Becker (dspace -at- pascal -hyphen- becker -dot- de)
*/
public class MetadataRDFMapping {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(MetadataRDFMapping.class);
protected final String name;
protected final Pattern fulfills;
protected final List results;
protected MetadataRDFMapping(String name, Pattern fulfills, List results) {
this.name = name;
this.fulfills = fulfills;
this.results = results;
}
public static MetadataRDFMapping getMetadataRDFMapping(
Resource mappingResource, String dsoIdentifier) {
// For better log message: try to get the uri of this mapping.
String uri = null;
if (mappingResource.getURI() != null) {
uri = " (" + mappingResource.getURI() + ")";
}
if (log.isDebugEnabled()) {
if (uri.equals("")) {
log.debug("Processing blank node MetadataRDFMapping.");
} else {
log.debug("Processing MetadataRDFMapping" + uri + ".");
}
}
// Parse the property DMRM.metadataName
RDFNode nameNode;
try {
nameNode = getSingularProperty(mappingResource, DMRM.metadataName);
} catch (IllegalArgumentException ex) {
log.error("The Property 'metadataName' exists multiple times in one "
+ "DSpaceMetadataRDFMapping, ignoring it" + uri + ".");
return null;
}
if (nameNode == null) {
log.error("Cannot find property 'metadataName', ignoring mapping" + uri + ".");
return null;
}
if (!nameNode.isLiteral()) {
log.error("Property 'metadataName' is not a literal, ignoring mapping"
+ uri + ".");
return null;
}
String name = nameNode.asLiteral().getLexicalForm();
log.debug("Found mapping name '" + name + "'.");
// Parse the property condition, if it exists.
RDFNode conditionNode;
try {
conditionNode = getSingularProperty(mappingResource, DMRM.condition);
} catch (IllegalArgumentException ex) {
log.error("There are multiple properties 'condition' in one "
+ "DSpaceMetadataRDFMapping, ignoring it" + uri + ".");
return null;
}
String regex = null;
Pattern condition = null;
if (conditionNode != null) {
if (conditionNode.isLiteral()) {
regex = conditionNode.asLiteral().getLexicalForm();
log.debug("Found property condition '" + regex + "'.");
} else {
log.error("Property 'condition' is not a literal, ignoring "
+ "mapping" + uri + ".");
return null;
}
} else {
// there is no property "condition". As this property is optional
// there is nothing to be done here.
log.debug("Didn't find a property \"condition\".");
}
if (regex != null) {
try {
condition = Pattern.compile(regex);
} catch (PatternSyntaxException ex) {
log.error("Property 'condition' does not specify a valid java "
+ "regex pattern. Will ignore mapping" + uri + ".", ex);
return null;
}
}
// parse all properties DMRM.creates.
List results = new ArrayList<>();
StmtIterator mappingIter = mappingResource.listProperties(DMRM.creates);
if (!mappingIter.hasNext()) {
log.warn("No 'creates' property in a DSpaceMetadataRDFMapping, "
+ "ignonring it" + uri + ".");
return null;
}
while (mappingIter.hasNext()) {
RDFNode result = mappingIter.nextStatement().getObject();
if (!result.isResource()) {
log.error("Mapping result" + uri + " is a Literal not a resource. "
+ "Ignoring mapping.");
return null;
}
results.add(result.asResource());
}
// create mapping
return new MetadataRDFMapping(name, condition, results);
}
public boolean matchesName(String name) {
return StringUtils.equalsIgnoreCase(this.name, name);
}
public boolean fulfills(String value) {
// if fulfills exists, we have to check the field value
if (this.fulfills == null) {
return true;
}
if (!this.fulfills.matcher(value).matches()) {
log.debug("Value '" + value + "' does not match regex '" + fulfills.toString() + "'.");
return false;
} else {
return true;
}
//return this.fulfills.matcher(value).matches();
}
public void convert(String value, String lang, String dsoIRI, Model m) {
log.debug("Using conversion for field " + name + " on value: " + value
+ " for " + dsoIRI + ".");
// run over all results
for (Iterator iter = this.results.iterator(); iter.hasNext(); ) {
try {
compileResult(m, iter.next(), dsoIRI, name, value, lang);
} catch (MetadataMappingException ex) {
log.error(ex.getMessage() + " Will ignore this mapping result.");
}
}
}
protected void compileResult(Model m, Resource result,
String dsoIRI, String name, String value, String lang)
throws MetadataMappingException {
// for better debug messages.
String uri = "";
if (result.isURIResource()) {
uri = " (" + result.getURI() + ")";
}
// check the subject
RDFNode subjectNode;
try {
subjectNode = getSingularProperty(result, DMRM.subject);
} catch (IllegalArgumentException ex) {
throw new MetadataMappingException("There are multiple 'subject' "
+ "properties in a mapping result" + uri + ".");
}
if (subjectNode == null) {
throw new MetadataMappingException("Mapping result" + uri
+ " does not have a subject.");
}
if (!subjectNode.isResource()) {
throw new MetadataMappingException("Subject of a result" + uri
+ " is a Literal not a URIResource.");
}
log.debug("Found subject: " + subjectNode.toString());
// check the predicate
RDFNode predicateNode;
try {
predicateNode = getSingularProperty(result, DMRM.predicate);
} catch (IllegalArgumentException ex) {
throw new MetadataMappingException("There are multiple 'predicate' "
+ "properties in a mapping result" + uri + ".");
}
if (predicateNode == null) {
throw new MetadataMappingException("Mapping result" + uri
+ " does not have a predicate.");
}
if (!predicateNode.isResource()) {
throw new MetadataMappingException("Predicate of a result" + uri
+ " is a Literal not a URIResource.");
}
log.debug("Found predicate: " + predicateNode.toString());
RDFNode objectNode;
try {
objectNode = getSingularProperty(result, DMRM.object);
} catch (IllegalArgumentException ex) {
throw new MetadataMappingException("There are multiple 'object' "
+ "properties in a mapping result" + uri + ".");
}
if (objectNode == null) {
throw new MetadataMappingException("Mapping result" + uri
+ " does not have a object.");
}
log.debug("Found object: " + objectNode.toString());
Resource subject = parseSubject(m, subjectNode.asResource(),
dsoIRI, name, value);
if (subject == null) {
throw new MetadataMappingException("Cannot parse subject of a "
+ "reified statement " + uri + ".");
}
Property predicate = parsePredicate(m, predicateNode.asResource(),
dsoIRI, name, value);
if (predicate == null) {
throw new MetadataMappingException("Cannot parse predicate of a "
+ "reified statement " + uri + ".");
}
RDFNode object = parseObject(m, objectNode, dsoIRI, name, value, lang);
if (object == null) {
throw new MetadataMappingException("Cannot parse object of a "
+ "reified statement " + uri + ".");
}
m.add(subject, predicate, object);
}
protected Resource parseSubject(Model m, Resource subject, String dsoIRI,
String name, String value) {
if (subject.hasProperty(RDF.type, DMRM.ResourceGenerator)) {
String generatedIRI = parseResourceGenerator(subject, value, dsoIRI);
if (generatedIRI == null) {
log.debug("Generated subject IRI is null.");
return null;
}
log.debug("Subject ResourceGenerator generated '" + generatedIRI + "'.");
return m.createResource(generatedIRI);
}
return subject;
}
protected Property parsePredicate(Model m, Resource predicate, String dsoIRI,
String name, String value) {
if (predicate.hasProperty(RDF.type, DMRM.ResourceGenerator)) {
String generatedIRI = parseResourceGenerator(predicate, value, dsoIRI);
if (generatedIRI == null) {
log.debug("Generated predicate IRI is null.");
return null;
}
log.debug("Property ResourceGenerator generated '" + generatedIRI + "'.");
return m.createProperty(generatedIRI);
}
String uri = predicate.getURI();
if (uri == null) {
log.debug("A result predicate is blank node, but not a "
+ "ResourceGenerator. Ignoring this result.");
return null;
}
return m.createProperty(uri);
}
protected RDFNode parseObject(Model m, RDFNode objectNode, String dsoIRI,
String name, String value, String lang) {
if (objectNode.isLiteral()) {
return objectNode;
}
Resource object = objectNode.asResource();
if (object.hasProperty(RDF.type, DMRM.LiteralGenerator)) {
Literal literalValue = parseLiteralGenerator(m, object, value, lang);
if (literalValue == null) {
return null;
}
return literalValue;
}
if (object.hasProperty(RDF.type, DMRM.ResourceGenerator)) {
String generatedIRI = parseResourceGenerator(object, value, dsoIRI);
if (generatedIRI == null) {
log.debug("Generated predicate IRI is null.");
return null;
}
log.debug("Property ResourceGenerator generated '" + generatedIRI + "'.");
return m.createProperty(generatedIRI);
}
if (object.isAnon()) {
Resource blank = m.createResource();
StmtIterator iter = object.listProperties();
while (iter.hasNext()) {
Statement stmt = iter.nextStatement();
Property predicate = stmt.getPredicate();
// iterate recursive over the object of a blank node.
blank.addProperty(predicate,
parseObject(m, stmt.getObject(), dsoIRI, name, value, lang));
}
return blank;
}
// object is not a literal, is not a blank node, is neither a
// IRIGenerator nor a LiteralGenerator => it must be a Resource => use
// it as it is.
return object;
}
protected String parseResourceGenerator(Resource resourceGenerator,
String value, String dsoIRI) {
if (resourceGenerator.isURIResource()
&& resourceGenerator.equals(DMRM.DSpaceObjectIRI)) {
return dsoIRI;
}
return parseValueProcessor(resourceGenerator, value);
}
protected Literal parseLiteralGenerator(Model m, Resource literalGenerator,
String value, String lang) {
if (literalGenerator.isURIResource()
&& literalGenerator.equals(DMRM.DSpaceValue)) {
return m.createLiteral(value);
}
String modifiedValue = parseValueProcessor(literalGenerator, value);
if (modifiedValue == null) {
return null;
}
// check if we should produce a typed literal
// Up the RDF spec lang tags are not significant on typed literals, so
// we can ignore them if we have a typed literal.
try {
RDFNode literalTypeNode = getSingularProperty(literalGenerator, DMRM.literalType);
if (literalTypeNode != null) {
if (literalTypeNode.isURIResource()) {
return m.createTypedLiteral(modifiedValue,
literalTypeNode.asResource().getURI());
} else {
log.warn("A LiteralGenerator has a property 'literalType' that "
+ "either is a blank node or a Literal. Ignoring it.");
}
}
} catch (IllegalArgumentException ex) {
log.error("A LiteralGenerator has multiple properties "
+ "'literalType'. Will ignore them.");
}
// check if a language tag should be generated
String languageTag = null;
try {
RDFNode langNode = getSingularProperty(literalGenerator, DMRM.literalLanguage);
if (langNode != null) {
if (langNode.isLiteral()) {
languageTag = langNode.asLiteral().getLexicalForm();
} else {
log.warn("Found a property 'literalLanguage', but its "
+ "object is not a literal! Ignoring it.");
}
}
} catch (IllegalArgumentException ex) {
log.warn("A LiteralGenerator has multiple properties "
+ "'literalLanguage'. Will ignore them.");
}
try {
RDFNode dspaceLangNode = getSingularProperty(literalGenerator,
DMRM.dspaceLanguageTag);
if (dspaceLangNode != null) {
boolean useDSpaceLang = false;
if (dspaceLangNode.isLiteral()) {
try {
useDSpaceLang = dspaceLangNode.asLiteral().getBoolean();
} catch (Exception ex) {
/*
* nothing to do here.
*
* this is for sure not the best coding style, but the
* one that works best here as jena throws some undeclared
* RuntimeExceptions if the detection of the boolean fails.
*/
}
}
if (useDSpaceLang && !StringUtils.isEmpty(lang)) {
if (lang.indexOf("_") == 2) {
languageTag = lang.replaceFirst("_", "-");
} else {
languageTag = lang;
}
}
}
} catch (IllegalArgumentException ex) {
log.error("A LiteralGenerator has multiple properties "
+ "'dspaceLanguageTag'. Will ignore them.");
}
if (languageTag != null) {
return m.createLiteral(modifiedValue, languageTag);
}
return m.createLiteral(modifiedValue);
}
protected String parseValueProcessor(Resource valueProcessor, String value) {
// look if there's a modifier.
RDFNode modifierNode;
try {
modifierNode = getSingularProperty(valueProcessor, DMRM.modifier);
} catch (IllegalArgumentException ex) {
log.error("The ResourceGenerator of a mapping result has "
+ "multiple 'modifier' properties, skipping this result.");
return null;
}
if (modifierNode != null) {
// in case there is a modifier find its matcher, its replacement and
// modifies the value
if (!modifierNode.isResource()) {
log.error("The modifier of a result is a Literal not an Resource! "
+ "Ignoring this result.");
return null;
}
Resource modifier = modifierNode.asResource();
RDFNode matcherNode;
try {
matcherNode = getSingularProperty(modifier, DMRM.matcher);
} catch (IllegalArgumentException ex) {
log.error("The modifier of a mapping result has multiple "
+ "'matcher' properties. Ignoring this result.");
return null;
}
if (matcherNode == null) {
log.error("Found a modifier property to a result, but no "
+ "matcher property! Ignoring this result!");
return null;
}
if (!matcherNode.isLiteral()) {
log.error("A matcher of a result modifier is not a Literal! "
+ "Ignoring this result.");
return null;
}
// get the replacement string
RDFNode replacementNode;
try {
replacementNode = getSingularProperty(modifier, DMRM.replacement);
} catch (IllegalArgumentException ex) {
log.error("The modifier of a mapping result has multiple "
+ "'replacement' properties. Ignoring this result.");
return null;
}
if (replacementNode == null) {
log.error("Found a modifier property to a result, but no "
+ "replacement property! Ignoring this result!");
return null;
}
if (!replacementNode.isLiteral()) {
log.error("A replacement of a result modifier is not a Literal! "
+ "Ignoring this result.");
return null;
}
String matcher = matcherNode.asLiteral().getLexicalForm();
String replacement = replacementNode.asLiteral().getLexicalForm();
try {
Pattern pattern = Pattern.compile(matcher);
String modifiedValue = pattern.matcher(value).replaceAll(replacement);
log.debug("Found matcher '" + matcher + "'.\n"
+ "Found replacement '" + replacement + "'.\n"
+ "modified '" + value + "' => '" + modifiedValue + "'.");
value = modifiedValue;
} catch (PatternSyntaxException ex) {
log.error("Property 'matcher' of a ValueModifider didn't specify a "
+ "valid java regex pattern. Will ignore this result.", ex);
return null;
}
}
// in case there is a modifier, we modified the value. Insert the
// (possibly modified) value in the pattern
RDFNode patternNode;
try {
patternNode = getSingularProperty(valueProcessor, DMRM.pattern);
} catch (IllegalArgumentException ex) {
log.error("The ValueProcessor of a mapping result has "
+ "multiple 'pattern' properties, skipping this result.");
return null;
}
if (patternNode == null) {
log.debug("Cannot find the property 'pattern' of a "
+ "ValueProcessor, will use \"$DSpaceValue\".");
patternNode = valueProcessor.getModel().createLiteral("$DSpaceValue");
}
if (!patternNode.isLiteral()) {
log.error("A 'pattern' property of a ValueProcessor is not a "
+ "Literal! Skipping this result.");
return null;
}
String pattern = patternNode.asLiteral().getLexicalForm();
String result = pattern.replace("$DSpaceValue", value);
log.debug("Found pattern " + pattern + ".\n"
+ "Created result: " + result);
return result;
}
protected static RDFNode getSingularProperty(Resource r, Property p)
throws IllegalArgumentException {
List stmts = r.listProperties(p).toList();
if (stmts.isEmpty()) {
return null;
}
if (stmts.size() > 1) {
throw new IllegalArgumentException("Property '" + p.getURI()
+ "' exists multiple times.");
}
return stmts.get(0).getObject();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy