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

org.eclipse.esmf.aspectmodel.loader.AttributeValueRetriever Maven / Gradle / Ivy

There is a newer version: 2.9.5
Show newest version
/*
 * Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
 *
 * See the AUTHORS file(s) distributed with this work for additional
 * information regarding authorship.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 *
 * SPDX-License-Identifier: MPL-2.0
 */

package org.eclipse.esmf.aspectmodel.loader;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import org.eclipse.esmf.aspectmodel.AspectLoadingException;
import org.eclipse.esmf.metamodel.vocabulary.SammNs;

import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.RDFList;
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;

/**
 * This class provides utilities to retrieve attribute values from model elements, e.g., a samm:Property's samm:characteristic.
 * It knows how to handle:
 * 
    *
  • optionality (e.g., samm-c:upperBoundDefinition on a samm-c:RangeConstraint is not mandatory)
  • *
  • n-ary attributes (e.g., samm:preferredName and samm:description can appear multiple times)
  • *
  • abstract Properties (i.e., a bnode with samm:extends used as a Property)
  • *
  • Property references (i.e., a bnode with samm:property used as a Property)
  • *
*/ public class AttributeValueRetriever { /** * Returns the value of an attribute on a model element (or its super elements) * * @param modelElement the model element * @param attribute the given attribute * @return the statement asserting the value * @throws AspectLoadingException when the attribute is not present or is present multiple times, or if samm:extends is used wrong */ protected Statement attributeValue( final Resource modelElement, final Property attribute ) { return optionalAttributeValue( modelElement, attribute ).orElseThrow( () -> new AspectLoadingException( "Missing attribute " + attribute + " on " + modelElement ) ); } /** * Returns the optional value of an attribute on a model element (or its super elements) * * @param modelElement the model element * @param attribute the given attribute * @return the optional statement asserting the value */ protected Optional optionalAttributeValue( final Resource modelElement, final Property attribute ) { return attributeValues( modelElement, attribute ).stream().findFirst(); } private boolean isRdfList( final Resource resource ) { return resource.isAnon() && ( resource.hasProperty( RDF.rest ) || resource.equals( RDF.nil ) ); } /** * Returns the values of n-ary attributes on a model element (or its super elements), or if a given attribute is an rdf:List, the list * elements. The list will be ordered by precedence, e.g., if a Property is present on both the current element and it's superelement, * the assertion on the current element will be on a lower list index. Duplicate attribute assertions are removed and only the assertion * with the highest precedence will be returned (bottom-most in the inheritance tree), this includes multiple assertions for the same * attribute with rdf:langString values with the same language tag. For example: *

* :SuperEntity a samm:AbstractEntity ; * samm:description "I'm abstract"@en ; * samm:description "Ich bin abstrakt"@de ; * samm:properties () . *

* :MyEntity a samm:Entity ; * samm:extends :SuperEntity ; * samm:description "I'm concrete"@en ; * samm:properties () . *

* Here, attributeValues( :MyEntity, samm:description ) will return: * List( Statement( :MyEntity samm:description "I'm contrete"@en ), * Statement( :SuperEntity samm:description "Ich bin abstrakt"@de ) ) *

* The attribute that is overridden with a new value takes precedence, the one that is not overridden is inherited. * * @param modelElement the model element * @param attribute the given attribute * @return the list of statements asserting values for the attribute */ public List attributeValues( final Resource modelElement, final Property attribute ) { // Attribute values defined directly on the resource go into the result final List result = new ArrayList<>(); for ( final StmtIterator iterator = modelElement.listProperties( attribute ); iterator.hasNext(); ) { final Statement statement = iterator.next(); // If the value happens to be an rdf:List, unroll the list if ( statement.getObject().isResource() && isRdfList( statement.getObject().asResource() ) ) { statement.getObject().as( RDFList.class ) .mapWith( listValue -> modelElement.getModel().createStatement( modelElement, attribute, listValue ) ) .forEach( result::add ); } else { result.add( statement ); } } // If the model element is a bnode with samm:property given, it's a Property reference. Follow it to retrieve the sought-for // attribute assertions. final StmtIterator referenceIterator = modelElement.listProperties( SammNs.SAMM.property() ); if ( referenceIterator.hasNext() ) { final RDFNode referencedElement = referenceIterator.next().getObject(); if ( !referencedElement.isResource() ) { throw new AspectLoadingException( "samm:property on " + modelElement + " must point to a Property" ); } result.addAll( attributeValues( referencedElement.asResource(), attribute ) ); return result; } // If the model element is samm:extends another element, retrieve attribute assertions from this supertype as well. final StmtIterator extendsIterator = modelElement.listProperties( SammNs.SAMM._extends() ); if ( extendsIterator.hasNext() ) { final RDFNode superElementNode = extendsIterator.next().getObject(); if ( !superElementNode.isResource() ) { throw new AspectLoadingException( "samm:extends on " + modelElement + " must point to a valid model element" ); } result.addAll( attributeValues( superElementNode.asResource(), attribute ) ); } // Filter duplicate assertions by precedence final List filteredResult = new ArrayList<>(); final Set assertedLanguageTags = new HashSet<>(); for ( final Statement statement : result ) { if ( statement.getObject().isLiteral() ) { final String languageTag = statement.getObject().asLiteral().getLanguage(); if ( !languageTag.isEmpty() ) { if ( assertedLanguageTags.contains( languageTag ) ) { continue; } assertedLanguageTags.add( languageTag ); } } filteredResult.add( statement ); } return filteredResult; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy