Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create Aspect Models from AAS submodel template #517

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
ea8be68
Create Aspect Models from AAS submodel template
Yauhenikapl Jan 29, 2024
b4b6d96
Extend static meta model generation with property accessors
andreas-schilling Jan 25, 2024
3c715f1
Fix import issues
andreas-schilling Jan 26, 2024
2489866
Adjust formatting, imports, usage of final
atextor Jan 29, 2024
56c336b
Move MODEL_WITH_CYCLES to invalid aspect models enum
atextor Jan 24, 2024
3bf6a99
Copy jar files so they are available for Temurin test
atextor Jan 24, 2024
39d2876
Explicitly mark AAS model and impl classes for reflection
atextor Jan 24, 2024
79f9697
Run AAS gen tests for all models in native exec integration test
atextor Jan 24, 2024
3335f7a
Mark reflection configuration feature as hosted only
atextor Jan 24, 2024
7d2a5ec
Silence chatty unhelpful logger
atextor Jan 25, 2024
31c3016
Refactor native-image.properties into features
atextor Jan 25, 2024
e0b371e
Merge branch 'main' into 468-create-aspect-models-from-AAS-submodel-t…
Yauhenikapl Jan 29, 2024
acf1eab
Create Aspect Models from AAS submodel template
Yauhenikapl Feb 5, 2024
9a111a6
Merge branch 'main' into 468-create-aspect-models-from-AAS-submodel-t…
Yauhenikapl Feb 5, 2024
733aba3
Create Aspect Models from AAS submodel template
Yauhenikapl Feb 5, 2024
422865a
Fix tests.
Yauhenikapl Feb 5, 2024
f9d837e
Update description
Yauhenikapl Feb 6, 2024
edc466d
Update docs
Yauhenikapl Feb 6, 2024
453b839
Refactoring
Yauhenikapl Feb 8, 2024
1112a71
Fix build
Yauhenikapl Feb 8, 2024
927fb35
Formatting
Yauhenikapl Feb 13, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.digitaltwin.aas4j.v3.model.Referable;
import org.eclipse.esmf.aspectmodel.VersionNumber;
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
import org.eclipse.esmf.aspectmodel.vocabulary.SAMMC;
Expand Down Expand Up @@ -165,6 +166,14 @@ public List<Aspect> generateAspects() {
.toList();
}

public List<String> getSubmodelNames() {
return aasEnvironment.getSubmodels()
.stream()
.filter( submodel -> submodel.getKind().equals( ModellingKind.TEMPLATE ) )
.map( Referable::getIdShort )
.collect( Collectors.toList());
}

protected String escapeUrnNamespacePart( final String namespacePart ) {
if ( namespacePart.matches( AspectModelUrn.NAMESPACE_REGEX ) ) {
return namespacePart;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,14 @@ The available options and their meaning can also be seen in the help text of the
| _--format, -f_ : output file format (xml, json, or aasx, default: xml) |
| _--custom-resolver_ : use an external resolver for the resolution of the model elements |
| _--aspect-data, -a_ : path to a JSON file containing aspect data corresponding to the Aspect Model |
.2+| aas <aas file> to aspect | Translate Asset Administration Shell (AAS) Submodel Templates to Aspect Models | `samm aas AssetAdminShell.aasx to aspect`
.3+| aas <aas file> to aspect | Translate Asset Administration Shell (AAS) Submodel Templates to Aspect Models | `samm aas AssetAdminShell.aasx to aspect`
| _--output-directory, -d_ : output directory to write files to (default:
current directory) |
| _--submodel-template, -s_ : selected submodel template for generating;
run `samm aas <aas file> list` to list them. | `samm aas AssetAdminShell.aasx to aspect -s 1 -s 2`
.1+| aas <aas file> list | Retrieve a list of submodel templates contained within the provided
Asset Administration Shell (AAS) file. | `samm aas AssetAdminShell.aasx list`

|===

=== Custom model resolver
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
subcommands = {
CommandLine.HelpCommand.class,
AasToCommand.class,
AasListSubmodelsCommand.class
},
headerHeading = "@|bold Usage|@:%n%n",
descriptionHeading = "%n@|bold Description|@:%n%n",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.eclipse.esmf.aas;

import java.io.File;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.io.FilenameUtils;
import org.eclipse.esmf.AbstractCommand;
import org.eclipse.esmf.LoggingMixin;
import org.eclipse.esmf.aspectmodel.aas.AasFileFormat;
import org.eclipse.esmf.aspectmodel.aas.AasToAspectModelGenerator;
import org.eclipse.esmf.exception.CommandException;

import picocli.CommandLine;

@CommandLine.Command( name = AasListSubmodelsCommand.COMMAND_NAME, description = "Get list of submodel templates of AAS input",
descriptionHeading = "%n@|bold Description|@:%n%n",
parameterListHeading = "%n@|bold Parameters|@:%n",
optionListHeading = "%n@|bold Options|@:%n",
mixinStandardHelpOptions = true
)
public class AasListSubmodelsCommand extends AbstractCommand {
public static final String COMMAND_NAME = "list";

@CommandLine.Mixin
private LoggingMixin loggingMixin;

@CommandLine.ParentCommand
private AasCommand parentCommand;

@Override
public void run() {
final String path = parentCommand.getInput();
final String extension = FilenameUtils.getExtension( path );

if ( Arrays.stream( AasFileFormat.values() ).noneMatch( format -> format.toString().equals( extension ) ) ) {
throw new CommandException( "Input file name must be one of " + AasFileFormat.allValues() );
}

final List<String> submodelNames = AasToAspectModelGenerator.fromFile( new File( path ) ).getSubmodelNames();

for ( final String submodelName : submodelNames ) {
final int index = submodelNames.indexOf( submodelName );
System.out.printf( "%2s: %s%n", index + 1, submodelName );
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

import org.apache.commons.io.FilenameUtils;
import org.eclipse.esmf.AbstractCommand;
import org.eclipse.esmf.LoggingMixin;
import org.eclipse.esmf.aas.AasToCommand;
import org.eclipse.esmf.aspectmodel.aas.AasToAspectModelGenerator;
import org.eclipse.esmf.aspectmodel.resolver.fs.StructuredModelsRoot;
import org.eclipse.esmf.aspectmodel.serializer.AspectSerializer;
import org.eclipse.esmf.exception.CommandException;
import org.eclipse.esmf.metamodel.Aspect;

import org.eclipse.esmf.aspectmodel.resolver.fs.StructuredModelsRoot;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import picocli.CommandLine;

@CommandLine.Command(
Expand All @@ -38,6 +41,10 @@ public class AasToAspectCommand extends AbstractCommand {
@CommandLine.Option( names = { "--output-directory", "-d" }, description = "Output directory to write files to" )
private String outputPath = ".";

@CommandLine.Option( names = { "--submodel-template",
"-s" }, description = "Select the submodel template(s) to include, as returned by the aas list command" )
private List<Integer> selectedOptions = new ArrayList<>();

@CommandLine.Mixin
private LoggingMixin loggingMixin;

Expand All @@ -53,7 +60,15 @@ public void run() {

private void generateAspects( final AasToAspectModelGenerator generator ) {
final StructuredModelsRoot modelsRoot = new StructuredModelsRoot( Path.of( outputPath ) );
for ( final Aspect aspect : generator.generateAspects() ) {
final List<Aspect> generatedAspects = generator.generateAspects();

final List<Aspect> filteredAspects = this.selectedOptions.isEmpty() ? generatedAspects :
IntStream.range( 0, generatedAspects.size() )
.filter( index -> selectedOptions.contains( index + 1 ) )
.mapToObj( generatedAspects::get )
.toList();

for ( final Aspect aspect : filteredAspects ) {
final String aspectString = AspectSerializer.INSTANCE.apply( aspect );
final File targetFile = modelsRoot.determineAspectModelFile( aspect.getAspectModelUrn().get() );
LOG.info( "Writing {}", targetFile.getAbsolutePath() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ public ExecutionResult apply( final String... arguments ) {
}

public ExecutionResult runAndExpectSuccess( final String... arguments ) {
final ExecutionResult result = apply(
new ExecutionContext( Arrays.asList( arguments ), Optional.empty(), new File( System.getProperty( "user.dir" ) ) ) );
final ExecutionResult result = apply( arguments );
if ( result.exitStatus() != 0 ) {
System.out.printf( "Execution failed (status %d):%n", result.exitStatus() );
System.out.println( "stdout:" );
Expand Down
49 changes: 44 additions & 5 deletions tools/samm-cli/src/test/java/org/eclipse/esmf/SammCliTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
import java.util.Optional;
import java.util.stream.Stream;

import org.apache.tika.config.TikaConfig;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MediaType;
import org.eclipse.esmf.ProcessLauncher.ExecutionResult;
import org.eclipse.esmf.aspect.AspectValidateCommand;
import org.eclipse.esmf.aspectmodel.shacl.violation.InvalidSyntaxViolation;
Expand All @@ -39,11 +43,6 @@
import org.eclipse.esmf.test.MetaModelVersions;
import org.eclipse.esmf.test.TestAspect;
import org.eclipse.esmf.test.TestModel;

import org.apache.tika.config.TikaConfig;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.mime.MediaType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -381,6 +380,46 @@ public void testAasToAspectModel() {
assertThat( sourceFile ).content().contains( ":" + testModel.getName() + " a samm:Aspect" );
}

@Test
public void testAasListSubmodels() {
final File aasXmlFile = outputFile( "output.xml" );
final ExecutionResult generateAasXmlResult = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "to", "aas",
"--format", "xml", "-o", aasXmlFile.getAbsolutePath() );
assertThat( generateAasXmlResult.stdout() ).isEmpty();
assertThat( generateAasXmlResult.stderr() ).isEmpty();

final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aas", aasXmlFile.getAbsolutePath(), "list" );
assertThat( result.stdout() ).isNotEmpty();
assertThat( result.stderr() ).isEmpty();
}

@Test
public void testAasToAspectModelWithSelectedSubmodels() {
// First create the AAS XML file we want to read
final File aasXmlFile = outputFile( "output.xml" );
final ExecutionResult generateAasXmlResult = sammCli.runAndExpectSuccess( "--disable-color", "aspect", defaultInputFile, "to", "aas",
"--format", "xml", "-o", aasXmlFile.getAbsolutePath() );
assertThat( generateAasXmlResult.stdout() ).isEmpty();
assertThat( generateAasXmlResult.stderr() ).isEmpty();

// Now the actual test, convert it to an Aspect Model
final File outputDir = outputDirectory.toFile();
final ExecutionResult result = sammCli.runAndExpectSuccess( "--disable-color", "aas", aasXmlFile.getAbsolutePath(), "to", "aspect",
"--output-directory", outputDir.getAbsolutePath(), "-s", "1" );
assertThat( result.stdout() ).isEmpty();
assertThat( result.stderr() ).isEmpty();

final File directory = outputDirectory.resolve( testModel.getUrn().getNamespace() )
.resolve( testModel.getUrn().getVersion() )
.toFile();
assertThat( directory ).exists();
final String expectedAspectModelFileName = testModel.getName() + ".ttl";
assertThat( directory ).isDirectoryContaining( file -> file.getName().equals( expectedAspectModelFileName ) );

final File sourceFile = directory.toPath().resolve( expectedAspectModelFileName ).toFile();
assertThat( sourceFile ).content().contains( ":" + testModel.getName() + " a samm:Aspect" );
}

@Test
public void testAspectToHtmlWithDefaultLanguageToFile() {
final File targetFile = outputFile( "output.html" );
Expand Down
Loading