Skip to content

Commit

Permalink
Implement support for samm:Namespace
Browse files Browse the repository at this point in the history
Fixes eclipse-esmf#450. Properly supporting samm:Namespace in the element instantiation and
the DefaultNamespace implementation is a prerequisite for enabling the
PrettyPrinter to write Aspect Model files that don't contain an Aspect model
element definition.
  • Loading branch information
atextor committed Aug 7, 2024
1 parent 6f5be7f commit 825d425
Show file tree
Hide file tree
Showing 26 changed files with 256 additions and 126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.eclipse.esmf.metamodel.ModelElement;
import org.eclipse.esmf.metamodel.ModelElementGroup;
import org.eclipse.esmf.metamodel.Namespace;

import org.apache.jena.rdf.model.Model;

Expand All @@ -31,6 +32,10 @@ default List<String> headerComment() {

Optional<URI> sourceLocation();

default Namespace namespace() {
throw new UnsupportedOperationException( "Uninitialized Aspect Model" );
}

@Override
default List<ModelElement> elements() {
throw new UnsupportedOperationException( "Uninitialized Aspect Model" );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public String getNamespace() {
return getUri() + "#";
}

public Resource Namespace() {
return resource( "Namespace" );
}

public Property listType() {
return property( "listType" );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,27 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.eclipse.esmf.aspectmodel.loader.MetaModelBaseAttributes;
import org.eclipse.esmf.aspectmodel.loader.ModelElementFactory;
import org.eclipse.esmf.aspectmodel.resolver.modelfile.DefaultAspectModelFile;
import org.eclipse.esmf.aspectmodel.resolver.modelfile.MetaModelFile;
import org.eclipse.esmf.metamodel.AspectModel;
import org.eclipse.esmf.metamodel.ModelElement;
import org.eclipse.esmf.metamodel.Namespace;
import org.eclipse.esmf.metamodel.impl.DefaultAspectModel;
import org.eclipse.esmf.metamodel.impl.DefaultNamespace;
import org.eclipse.esmf.metamodel.vocabulary.SammNs;

import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
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.vocabulary.RDF;

Expand All @@ -45,13 +53,15 @@ public static AspectModel buildAspectModelFromFiles( final Collection<AspectMode

final List<ModelElement> elements = new ArrayList<>();
final List<AspectModelFile> files = new ArrayList<>();
final Map<AspectModelFile, MetaModelBaseAttributes> namespaceDefinitions = new HashMap<>();
for ( final AspectModelFile file : inputFiles ) {
final DefaultAspectModelFile aspectModelFile = new DefaultAspectModelFile( file.sourceModel(), file.headerComment(),
file.sourceLocation() );
files.add( aspectModelFile );
final Model model = file.sourceModel();
final ModelElementFactory modelElementFactory = new ModelElementFactory( mergedModel, Map.of(), element -> aspectModelFile );
final List<ModelElement> fileElements = model.listStatements( null, RDF.type, (RDFNode) null ).toList().stream()
.filter( statement -> !statement.getObject().isURIResource() || !statement.getResource().equals( SammNs.SAMM.Namespace() ) )
.map( Statement::getSubject )
.filter( RDFNode::isURIResource )
.map( resource -> mergedModel.createResource( resource.getURI() ) )
Expand All @@ -60,6 +70,42 @@ public static AspectModel buildAspectModelFromFiles( final Collection<AspectMode
aspectModelFile.setElements( fileElements );
elements.addAll( fileElements );
}

setNamespaces( files, elements );
return new DefaultAspectModel( files, mergedModel, elements );
}

private static void setNamespaces( final Collection<AspectModelFile> files, final Collection<ModelElement> elements ) {
final Map<String, List<ModelElement>> elementsGroupedByNamespaceUrn = elements.stream()
.filter( element -> !element.isAnonymous() )
.collect( Collectors.groupingBy( element -> element.urn().getNamespaceIdentifier() ) );
for ( final AspectModelFile file : files ) {
final Optional<String> optionalNamespaceUrn =
Optional.ofNullable( file.sourceModel().getNsPrefixURI( "" ) )
.map( urnPrefix -> urnPrefix.split( "#" )[0] )
.or( () -> file.elements().stream()
.filter( element -> !element.isAnonymous() )
.map( element -> element.urn().getNamespaceIdentifier() )
.findAny() );
if ( optionalNamespaceUrn.isEmpty() ) {
return;
}

final String namespaceUrn = optionalNamespaceUrn.get();
final Optional<MetaModelBaseAttributes> baseAttributes = elementsGroupedByNamespaceUrn.get( namespaceUrn ).stream()
.map( element -> element.getSourceFile().sourceModel() )
.filter( model -> model.contains( null, RDF.type, SammNs.SAMM.Namespace() ) )
.map( model -> {
final ModelElementFactory modelElementFactory = new ModelElementFactory( model, Map.of(), r -> null );
final Resource namespaceResource = model.listStatements( null, RDF.type, SammNs.SAMM.Namespace() )
.mapWith( Statement::getSubject )
.toList().iterator().next();
return modelElementFactory.createBaseAttributes( namespaceResource );
} )
.findFirst();
final Namespace namespace = new DefaultNamespace( namespaceUrn, elementsGroupedByNamespaceUrn.get( namespaceUrn ),
Optional.of( file ), baseAttributes );
( (DefaultAspectModelFile) file ).setNamespace( namespace );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ private Stream<String> getFilesFromJar( final String directory, final File jarFi
public AspectModelFile apply( final AspectModelUrn aspectModelUrn, final ResolutionStrategySupport resolutionStrategySupport ) {
final String modelsRootTrailingSlash = modelsRoot.isEmpty() ? "" : "/";
final String directory = String.format( "%s%s%s/%s", modelsRoot, modelsRootTrailingSlash,
aspectModelUrn.getNamespace(), aspectModelUrn.getVersion() );
aspectModelUrn.getNamespaceMainPart(), aspectModelUrn.getVersion() );
final URL namedResourceFile = resourceUrl( directory, aspectModelUrn.getName() + ".ttl" );

if ( namedResourceFile != null ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public StructuredModelsRoot( final Path path ) {

@Override
public Path directoryForNamespace( final AspectModelUrn urn ) {
return rootPath().resolve( urn.getNamespace() ).resolve( urn.getVersion() );
return rootPath().resolve( urn.getNamespaceMainPart() ).resolve( urn.getVersion() );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.eclipse.esmf.aspectmodel.AspectModelFile;
import org.eclipse.esmf.metamodel.ModelElement;
import org.eclipse.esmf.metamodel.Namespace;

import org.apache.jena.rdf.model.Model;

Expand All @@ -28,6 +29,7 @@ public final class DefaultAspectModelFile implements AspectModelFile {
private final List<String> headerComment;
private final Optional<URI> sourceLocation;
private List<ModelElement> elements;
private Namespace namespace = null;

public DefaultAspectModelFile( final Model sourceModel, final List<String> headerComment, final Optional<URI> sourceLocation ) {
this.sourceModel = sourceModel;
Expand Down Expand Up @@ -61,10 +63,19 @@ public List<ModelElement> elements() {
return elements;
}

@Override
public Namespace namespace() {
return namespace;
}

public void setElements( final List<ModelElement> elements ) {
this.elements = elements;
}

public void setNamespace( final Namespace namespace ) {
this.namespace = namespace;
}

@Override
public boolean equals( final Object obj ) {
if ( obj == this ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
package org.eclipse.esmf.metamodel.impl;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.eclipse.esmf.aspectmodel.AspectModelFile;
Expand All @@ -37,13 +36,10 @@ public DefaultAspectModel( final List<AspectModelFile> files, final Model merged

@Override
public List<Namespace> namespaces() {
return elements().stream()
.filter( element -> !Namespace.ANONYMOUS.equals( element.urn().getUrnPrefix() ) )
.collect( Collectors.groupingBy( element -> element.urn().getUrnPrefix() ) )
.entrySet()
.stream()
.<Namespace> map( entry -> new DefaultNamespace( entry.getKey(), entry.getValue(), Optional.empty() ) )
.toList();
return files().stream()
.map( AspectModelFile::namespace )
.collect( Collectors.toSet() )
.stream().toList();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,40 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import org.eclipse.esmf.aspectmodel.AspectModelFile;
import org.eclipse.esmf.aspectmodel.VersionNumber;
import org.eclipse.esmf.aspectmodel.loader.MetaModelBaseAttributes;
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
import org.eclipse.esmf.metamodel.ModelElement;
import org.eclipse.esmf.metamodel.Namespace;
import org.eclipse.esmf.metamodel.datatype.LangString;

public class DefaultNamespace implements Namespace {
private final Optional<MetaModelBaseAttributes> baseAttributes;
private final String packagePart;
private final VersionNumber versionNumber;
private final List<ModelElement> elements;
private final Optional<AspectModelFile> source;

public DefaultNamespace( final AspectModelUrn aspectModelUrn, final List<ModelElement> elements,
final Optional<AspectModelFile> source ) {
this( aspectModelUrn.getNamespace(), VersionNumber.parse( aspectModelUrn.getVersion() ), elements, source );
this( aspectModelUrn, elements, source, Optional.empty() );
}

public DefaultNamespace( final AspectModelUrn aspectModelUrn, final List<ModelElement> elements,
final Optional<AspectModelFile> source, final Optional<MetaModelBaseAttributes> baseAttributes ) {
this( aspectModelUrn.getNamespaceMainPart(), VersionNumber.parse( aspectModelUrn.getVersion() ), elements, source, baseAttributes );
}

public DefaultNamespace( final String packagePart, final VersionNumber versionNumber, final List<ModelElement> elements,
final Optional<AspectModelFile> source ) {
final Optional<AspectModelFile> source, final Optional<MetaModelBaseAttributes> baseAttributes ) {
this.packagePart = packagePart;
this.versionNumber = versionNumber;
this.source = source;
this.elements = elements;
this.baseAttributes = baseAttributes;
}

/**
Expand All @@ -49,8 +59,9 @@ public DefaultNamespace( final String packagePart, final VersionNumber versionNu
* @param uri the namespace uri
* @param elements the list of elements in the namspace
*/
public DefaultNamespace( final String uri, final List<ModelElement> elements, final Optional<AspectModelFile> source ) {
this( uri.split( ":" )[2], VersionNumber.parse( uri.split( ":" )[3].replace( "#", "" ) ), elements, source );
public DefaultNamespace( final String uri, final List<ModelElement> elements, final Optional<AspectModelFile> source,
final Optional<MetaModelBaseAttributes> baseAttributes ) {
this( uri.split( ":" )[2], VersionNumber.parse( uri.split( ":" )[3].replace( "#", "" ) ), elements, source, baseAttributes );
}

@Override
Expand Down Expand Up @@ -78,6 +89,21 @@ public String getName() {
return "urn:samm:%s:%s".formatted( packagePart, versionNumber );
}

@Override
public List<String> getSee() {
return baseAttributes.map( MetaModelBaseAttributes::getSee ).orElseGet( Namespace.super::getSee );
}

@Override
public Set<LangString> getPreferredNames() {
return baseAttributes.map( MetaModelBaseAttributes::getPreferredNames ).orElseGet( Namespace.super::getPreferredNames );
}

@Override
public Set<LangString> getDescriptions() {
return baseAttributes.map( MetaModelBaseAttributes::getDescriptions ).orElseGet( Namespace.super::getDescriptions );
}

@Override
public boolean equals( final Object o ) {
if ( this == o ) {
Expand Down
Loading

0 comments on commit 825d425

Please sign in to comment.