Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions aspect-model-editor-service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@
<groupId>org.eclipse.esmf</groupId>
<artifactId>esmf-native-support</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
</dependency>

<!-- ESMF dependencies -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -85,9 +86,8 @@ public AspectModelResult getModel( final AspectModelUrn aspectModelUrn, final @N
loadModelFromUrn( aspectModelUrn );
validateModel( aspectModel );

return aspectModel.files().stream().filter( a -> a.elements().stream().anyMatch(
e -> ( e instanceof DefaultScalarValue && ( (DefaultScalarValue) e ).getType()
.equals( new DefaultScalar( aspectModelUrn.toString() ) ) ) || e.urn().equals( aspectModelUrn ) ) ).findFirst()
return aspectModel.files().stream().filter( file -> containsElement( file, aspectModelUrn ) )
.filter( aspectModelFile -> aspectModelFile.sourceLocation().isPresent() ).filter( this::hasValidCasing ).findFirst()
.map( aspectModelFile -> new AspectModelResult( aspectModelFile.filename(),
AspectSerializer.INSTANCE.aspectModelFileToString( aspectModelFile ) ) )
.orElseThrow( () -> new FileNotFoundException( "Aspect Model not found" ) );
Expand All @@ -96,6 +96,29 @@ public AspectModelResult getModel( final AspectModelUrn aspectModelUrn, final @N
}
}

private boolean containsElement( final AspectModelFile file, final AspectModelUrn aspectModelUrn ) {
return file.elements().stream().anyMatch( e -> ( e instanceof DefaultScalarValue && ( (DefaultScalarValue) e ).getType()
.equals( new DefaultScalar( aspectModelUrn.toString() ) ) ) || e.urn().equals( aspectModelUrn ) );
}

private boolean hasValidCasing( final AspectModelFile aspectModelFile ) {
try {
final URI sourceLocation = aspectModelFile.sourceLocation().orElseThrow( () -> new IOException( "Source location not present" ) );
final Path file = Path.of( sourceLocation );

if ( !Files.exists( file ) ) {
return false;
}

final Path realPath = file.toRealPath();
final Path providedPath = file.toAbsolutePath().normalize();

return realPath.getFileName().toString().equals( providedPath.getFileName().toString() );
} catch ( final IOException e ) {
return false;
}
}

private AspectModel loadModelFromUrn( final AspectModelUrn aspectModelUrn ) {
final Supplier<AspectModel> aspectModelSupplier = ModelUtils.getAspectModelSupplier( aspectModelUrn, aspectModelLoader );
return aspectModelSupplier.get();
Expand Down Expand Up @@ -254,8 +277,7 @@ public boolean checkElementExists( final AspectModelUrn aspectModelUrn, final St
try {

System.out.println( loadModelFromUrn( aspectModelUrn ).files() );
return loadModelFromUrn( aspectModelUrn ).files().stream()
.anyMatch( f -> !fileName.equals( f.filename().orElse( "" ) ) );
return loadModelFromUrn( aspectModelUrn ).files().stream().anyMatch( f -> !fileName.equals( f.filename().orElse( "" ) ) );
} catch ( final ModelResolutionException e ) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,24 @@

import java.io.File;
import java.net.URI;
import java.util.AbstractMap;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.jena.rdf.model.*;
import org.apache.jena.vocabulary.RDF;
import org.eclipse.esmf.ame.services.models.Model;
import org.eclipse.esmf.ame.services.models.Version;
import org.eclipse.esmf.aspectmodel.AspectModelFile;
import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader;
import org.eclipse.esmf.aspectmodel.resolver.AspectModelFileLoader;
import org.eclipse.esmf.aspectmodel.resolver.modelfile.RawAspectModelFile;
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
import org.eclipse.esmf.metamodel.AspectModel;
import org.eclipse.esmf.metamodel.ModelElement;
import org.eclipse.esmf.metamodel.vocabulary.SAMM;
import org.eclipse.esmf.metamodel.vocabulary.SAMMC;
import org.eclipse.esmf.metamodel.vocabulary.SAMME;
import org.eclipse.esmf.metamodel.vocabulary.SammNs;
import org.eclipse.esmf.samm.KnownVersion;

Expand All @@ -42,7 +43,7 @@
*
* @param aspectModelLoader the loader for aspect models
*/
public record ModelGroupingUtils( AspectModelLoader aspectModelLoader ) {
public record ModelGroupingUtils(AspectModelLoader aspectModelLoader) {
/**
* Constructs a ModelGrouper with the given base model path.
*/
Expand All @@ -52,7 +53,7 @@ public record ModelGroupingUtils( AspectModelLoader aspectModelLoader ) {
/**
* Groups model URIs by namespace and version, setting the existing field as specified.
*
* @param uriStream a stream of model URIs
* @param uriStream a stream of model URIs
* @param onlyAspectModels get only Aspect Models with Aspects as namespace list.
* @return a map where the keys are namespaces and the values are lists of maps containing versions and their associated models
*/
Expand All @@ -63,48 +64,155 @@ public Map<String, List<Version>> groupModelsByNamespaceAndVersion( final Stream
/**
* Groups model URIs by namespace and version, setting the existing field as specified.
*
* @param files a List of model Files
* @param files a List of model Files
* @param onlyAspectModels get only Aspect Models with Aspects as namespace list.
* @return a map where the keys are namespaces and the values are lists of maps containing versions and their associated models
*/
public Map<String, List<Version>> groupModelsByNamespaceAndVersion( final List<File> files, final boolean onlyAspectModels ) {
return files.stream().map( file -> {
final Optional<KnownVersion> metaModelVersionFromFile = Try.of(
() -> AspectModelFileLoader.load( file ).sourceModel().getNsPrefixMap().get( SammNs.SAMM.getShortForm() ) )
.flatMap( AspectModelUrn::from ).toJavaOptional().map( AspectModelUrn::getVersion )
.flatMap( KnownVersion::fromVersionString );
final AspectModel loadedModel = aspectModelLoader.load( file );
return new AbstractMap.SimpleEntry<>( loadedModel, metaModelVersionFromFile );
} ).flatMap(
entry -> entry.getKey().files().stream().flatMap( file -> extractModelElement( file, onlyAspectModels ) ).map( modelElement -> {
assert entry.getValue().orElse( null ) != null;
return createModel( modelElement, entry.getValue().orElse( null ) );
} ) ).collect( Collectors.groupingBy( model -> model.aspectModelUrn().getNamespaceMainPart() ) ).entrySet().stream()
.sorted( Map.Entry.comparingByKey() )
.collect( Collectors.toMap( Map.Entry::getKey, entry -> groupByVersion( entry.getValue() ), ( v1, v2 ) -> {
throw new RuntimeException( String.format( "Duplicate key for values %s and %s", v1, v2 ) );
}, LinkedHashMap::new ) );
final List<Model> allModels = loadAndExtractModels( files, onlyAspectModels );
final Map<String, List<Model>> modelsByNamespace = groupByNamespace( allModels );

return modelsByNamespace.entrySet().stream()
.sorted( Map.Entry.comparingByKey() )
.collect( Collectors.toMap(
Map.Entry::getKey,
entry -> groupByVersion( entry.getValue() ),
this::throwOnDuplicateKey,
LinkedHashMap::new ) );
}

private List<Model> loadAndExtractModels( final List<File> files, final boolean onlyAspectModels ) {
return files.stream()
.map( this::loadModelWithVersion )
.flatMap( entry -> extractModelsFromEntry( entry, onlyAspectModels ) )
.toList();
}

private Map.Entry<RawAspectModelFile, Optional<KnownVersion>> loadModelWithVersion( final File file ) {
final RawAspectModelFile rawFile = AspectModelFileLoader.load( file );
final Optional<KnownVersion> metaModelVersion = extractMetaModelVersion( rawFile );

return new AbstractMap.SimpleEntry<>( rawFile, metaModelVersion );
}

private Optional<KnownVersion> extractMetaModelVersion( final RawAspectModelFile rawFile ) {
return Try.of( () -> rawFile.sourceModel().getNsPrefixMap().get( SammNs.SAMM.getShortForm() ) )
.flatMap( AspectModelUrn::from )
.toJavaOptional()
.map( AspectModelUrn::getVersion )
.flatMap( KnownVersion::fromVersionString );
}

private Stream<Model> extractModelsFromEntry(final Map.Entry<RawAspectModelFile, Optional<KnownVersion>> entry, final boolean onlyAspectModels) {
final KnownVersion version = entry.getValue()
.orElseThrow(() -> new IllegalStateException("Meta model version is required"));
final RawAspectModelFile rawFile = entry.getKey();

final String filename = extractFilename(rawFile);
final List<Resource> resources = collectMetaModelResources(version);
final Resource firstNonBlankSubject = findFirstNonBlankSubject(rawFile.sourceModel(), resources, filename);

final Model model = new Model(filename, AspectModelUrn.fromUrn(firstNonBlankSubject.getURI()),
version.toVersionString(), true);

return Stream.of(model);
}

private String extractFilename(final RawAspectModelFile rawFile) {
return rawFile.sourceLocation()
.map(uri -> Path.of(uri).getFileName().toString())
.orElse("unnamed file");
}

private List<Resource> collectMetaModelResources(final KnownVersion version) {
final SAMM samm = new SAMM(version);
final SAMMC sammc = new SAMMC(version);
final SAMME samme = new SAMME(version, samm);

return Stream.of(
Stream.of(samm.Aspect(), samm.Property(), samm.Operation(), samm.Event(),
samm.Entity(), samm.Value(), samm.Characteristic(), samm.Constraint(),
samm.AbstractEntity(), samm.AbstractProperty()),
samme.allEntities(),
sammc.allCharacteristics(),
sammc.allConstraints(),
sammc.allCollections()
).flatMap(s -> s).toList();
}

private Resource findFirstNonBlankSubject(final org.apache.jena.rdf.model.Model sourceModel, final List<Resource> resources, final String filename) {
return resources.stream()
.flatMap(resource -> sourceModel.listStatements(null, RDF.type, resource).toList().stream())
.map(Statement::getSubject)
.filter(subject -> !subject.isAnon())
.findFirst()
.orElseThrow(() -> new IllegalStateException("No non-blank subject found in " + filename));
}

private Map<String, List<Model>> groupByNamespace( final List<Model> models ) {
return models.stream()
.collect( Collectors.groupingBy( model ->
model.aspectModelUrn().getNamespaceMainPart() ) );
}

private Stream<ModelElement> extractModelElement( final AspectModelFile file, final boolean onlyAspectModels ) {

final Optional<ModelElement> aspectElement = file.aspects().stream()
.map( ModelElement.class::cast )
.findFirst();

if ( onlyAspectModels ) {
return file.aspects().stream().map( ModelElement.class::cast ).findFirst().stream();
return aspectElement.stream();
}

return file.aspects().stream().map( ModelElement.class::cast ).findFirst()
.or( () -> file.elements().stream().filter( element -> !element.isAnonymous() ).findAny() ).stream();
return aspectElement
.or( () -> findFirstNonAnonymousElement( file ) )
.stream();
}

private Model createModel( final ModelElement element, final KnownVersion version ) {
final String filename = element.getSourceFile().filename().orElse( "unnamed file" );
return new Model( filename, element.urn(), version.toVersionString(), true );
private Optional<ModelElement> findFirstNonAnonymousElement( final AspectModelFile file ) {
return file.elements().stream()
.filter( element -> !element.isAnonymous() )
.findAny();
}

private List<Version> groupByVersion( final List<Model> models ) {
final Map<AspectModelUrn, Model> uniqueModels = removeDuplicateModels( models );
final Map<String, List<Model>> modelsByVersion = groupModelsByVersionString( uniqueModels );

return modelsByVersion.entrySet().stream()
.sorted( Map.Entry.comparingByKey() )
.map( this::createVersionEntry )
.toList();
}

private Map<AspectModelUrn, Model> removeDuplicateModels( final List<Model> models ) {
return models.stream()
.collect( Collectors.toMap( Model::aspectModelUrn, model -> model, ( existing, duplicate ) -> existing, LinkedHashMap::new ) )
.values().stream().collect( Collectors.groupingBy( model -> model.aspectModelUrn().getVersion() ) ).entrySet().stream()
.sorted( Map.Entry.comparingByKey() ).map( entry -> new Version( entry.getKey(),
entry.getValue().stream().sorted( Comparator.comparing( Model::model ) ).toList() ) ).toList();
.collect( Collectors.toMap(
Model::aspectModelUrn,
model -> model,
( existing, duplicate ) -> existing,
LinkedHashMap::new ) );
}

private Map<String, List<Model>> groupModelsByVersionString(
final Map<AspectModelUrn, Model> uniqueModels ) {

return uniqueModels.values().stream()
.collect( Collectors.groupingBy( model ->
model.aspectModelUrn().getVersion() ) );
}

private Version createVersionEntry( final Map.Entry<String, List<Model>> entry ) {
final List<Model> sortedModels = entry.getValue().stream()
.sorted( Comparator.comparing( Model::model ) )
.toList();
return new Version( entry.getKey(), sortedModels );
}

private <T> T throwOnDuplicateKey( final T v1, final T v2 ) {
throw new RuntimeException(
String.format( "Duplicate key for values %s and %s", v1, v2 ) );
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ public AspectModel get() {
* @return the loaded {@link AspectModel}
*/
public static AspectModel loadModelFromFile( final Path modelPath, final String filePath, final AspectModelLoader aspectModelLoader ) {
final Path path = Paths.get( filePath ).normalize();
final Path path = Paths.get( filePath.replace( ":", File.separator ) ).normalize();
final String[] pathParts = StreamSupport.stream( path.spliterator(), false ).map( Path::toString ).toArray( String[]::new );
final Path aspectModelPath = constructModelPath( modelPath, pathParts[0], pathParts[1], pathParts[2] );
return aspectModelLoader.load( aspectModelPath.toFile() );
Expand Down
4 changes: 0 additions & 4 deletions aspect-model-editor-web/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@
</dependency>

<!-- Third party dependencies -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-client</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,9 @@ private AspectModelUrn parseAspectModelUrn( final Optional<String> urn ) {
*/
@Get()
@Produces( MediaTypeExtension.TEXT_TURTLE_VALUE )
public HttpResponse<String> getModel( @Header( URN ) final Optional<String> urn,
@Header( "file-path" ) final Optional<String> filePath ) {
public HttpResponse<String> getModel( @Header( URN ) final Optional<String> urn ) {
final AspectModelUrn aspectModelUrn = parseAspectModelUrn( urn );
final String path = filePath.orElse( null );
return HttpResponse.ok( modelService.getModel( aspectModelUrn, path ).content() );
return HttpResponse.ok( modelService.getModel( aspectModelUrn, null ).content() );
}

/**
Expand All @@ -93,8 +91,7 @@ public HttpResponse<String> getModel( @Header( URN ) final Optional<String> urn,
* @return True if the element exists in a different file, false otherwise
*/
@Get( uri = "check-element", consumes = MediaType.APPLICATION_JSON )
public HttpResponse<Boolean> checkElementExists( @Header( URN ) final Optional<String> urn,
@QueryValue() final String fileName ) {
public HttpResponse<Boolean> checkElementExists( @Header( URN ) final Optional<String> urn, @QueryValue() final String fileName ) {
final AspectModelUrn aspectModelUrn = parseAspectModelUrn( urn );
return HttpResponse.ok( modelService.checkElementExists( aspectModelUrn, fileName ) );
}
Expand All @@ -111,7 +108,7 @@ public HttpResponse<List<FileInformation>> getModelsBatch( @Body final List<File
for ( final FileEntry entry : fileEntries ) {
try {
final AspectModelUrn urn = parseAspectModelUrn( Optional.of( entry.aspectModelUrn() ) );
final AspectModelResult aspectModelResult = modelService.getModel( urn, null );
final AspectModelResult aspectModelResult = modelService.getModel( urn, entry.absoluteName() );

final FileInformation fileInformation = new FileInformation( entry.absoluteName(), entry.aspectModelUrn(), entry.modelVersion(),
aspectModelResult.content(), aspectModelResult.filename().orElse( "" ) );
Expand Down
Loading