Skip to content

Commit 15b9e5b

Browse files
authored
Merge branch 'main' into 481-samm-cli-aas-generation-mapping-of-set-characteristics
2 parents bd55ea9 + 255fe98 commit 15b9e5b

File tree

12 files changed

+377
-3
lines changed

12 files changed

+377
-3
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
3+
*
4+
* See the AUTHORS file(s) distributed with this work for additional
5+
* information regarding authorship.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
10+
*
11+
* SPDX-License-Identifier: MPL-2.0
12+
*/
13+
14+
package org.eclipse.esmf.aspectmodel.generator.jsonld;
15+
16+
import java.io.IOException;
17+
import java.io.OutputStream;
18+
import java.io.StringWriter;
19+
import java.util.function.Function;
20+
21+
import org.eclipse.esmf.aspectmodel.generator.AbstractGenerator;
22+
import org.eclipse.esmf.metamodel.Aspect;
23+
24+
public class AspectModelToJsonLdGenerator extends AbstractGenerator {
25+
26+
private static final String JSON_LD_FORMAT = "JSON-LD";
27+
private final Aspect aspect;
28+
29+
public AspectModelToJsonLdGenerator( final Aspect aspect ) {
30+
this.aspect = aspect;
31+
}
32+
33+
/**
34+
* Generates a JSON-LD representation of the aspect's source model and writes it to an output stream.
35+
*
36+
* <p>This method takes a function (nameMapper) that maps the name of the aspect to an output stream,
37+
* then writes the aspect's source model in JSON-LD format to that stream. The function is expected
38+
* to accept the aspect's name as a parameter and return an appropriate OutputStream where the JSON-LD
39+
* will be written. The OutputStream is closed automatically when the operation is complete.</p>
40+
*
41+
* @param nameMapper a function that maps the aspect name to an OutputStream for writing the JSON-LD.
42+
* @throws IOException if an I/O error occurs while writing to the output stream.
43+
*/
44+
public void generateJsonLd( final Function<String, OutputStream> nameMapper ) throws IOException {
45+
try ( final OutputStream output = nameMapper.apply( aspect.getName() ) ) {
46+
aspect.getSourceFile().sourceModel().write( output, JSON_LD_FORMAT );
47+
}
48+
}
49+
50+
public String generateJsonLd() {
51+
StringWriter stringWriter = new StringWriter();
52+
aspect.getSourceFile().sourceModel().write( stringWriter, JSON_LD_FORMAT );
53+
return stringWriter.toString();
54+
}
55+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.eclipse.esmf.aspectmodel.generator.jsonld;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
6+
import org.eclipse.esmf.metamodel.Aspect;
7+
import org.eclipse.esmf.test.TestAspect;
8+
import org.eclipse.esmf.test.TestResources;
9+
10+
import org.junit.jupiter.api.Test;
11+
12+
class AspectModelJsonLdGeneratorTest {
13+
14+
@Test
15+
void generateTest() {
16+
final Aspect aspect = TestResources.load( TestAspect.ASPECT_WITH_ENTITY_LIST ).aspect();
17+
final AspectModelToJsonLdGenerator jsonGenerator = new AspectModelToJsonLdGenerator( aspect );
18+
final String generatedJsonLd = jsonGenerator.generateJsonLd();
19+
20+
assertJsonLdMeta( generatedJsonLd, aspect.urn() );
21+
}
22+
23+
private void assertJsonLdMeta( final String generatedJsonLd, final AspectModelUrn aspectModelUrn ) {
24+
final String context = """
25+
"@context": {
26+
"xsd": "http://www.w3.org/2001/XMLSchema#",
27+
"samm-c": "urn:samm:org.eclipse.esmf.samm:characteristic:2.1.0#",
28+
"samm": "urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#",
29+
"@vocab": "urn:samm:org.eclipse.esmf.test:1.0.0#"
30+
}
31+
""";
32+
33+
assertThat( generatedJsonLd ).contains( "\"@graph\": [" );
34+
assertThat( generatedJsonLd ).contains( context );
35+
assertThat( generatedJsonLd ).contains( "\"xsd\": \"http://www.w3.org/2001/XMLSchema#\"," );
36+
assertThat( generatedJsonLd ).contains( String.format( "\"@id\": \"%s\"", aspectModelUrn.toString() ) );
37+
}
38+
}

core/esmf-aspect-model-urn/src/main/java/org/eclipse/esmf/aspectmodel/urn/AspectModelUrn.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ private static String getName( final boolean isSammUrn, final List<String> urnPa
262262
return modelElementName;
263263
}
264264
if ( MODEL_ELEMENT_TYPES.contains( elementType ) ) {
265+
//Check root model element name before current element name
266+
checkElementName( urnParts.get( ASPECT_NAME_INDEX ), "model element" );
267+
265268
final String modelElementName = urnParts.get( MODEL_ELEMENT_NAME_INDEX );
266269
checkElementName( modelElementName, elementType.getValue() + " element" );
267270
return modelElementName;

core/esmf-aspect-model-urn/src/test/java/org/eclipse/esmf/aspectmodel/urn/AspectModelUrnTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,4 +342,17 @@ void validNamespaceTest() throws URISyntaxException {
342342
assertThat( elementUrnWithDash.getNamespaceMainPart() ).isNotEmpty();
343343
assertThat( elementUrnWithDash.getNamespaceMainPart() ).isEqualTo( "org.eclipse.esmf-test" );
344344
}
345+
346+
@Test
347+
void invalidModelElementNameTest() throws URISyntaxException {
348+
final URI invalidRootModelElementName = new URI( sammBaseUri + "aspect-model:Er?ors:1.1.0#TestAspect" );
349+
assertThatExceptionOfType( UrnSyntaxException.class )
350+
.isThrownBy( () -> AspectModelUrn.fromUrn( invalidRootModelElementName ) )
351+
.withMessage( "The model element name must match \\p{Alpha}\\p{Alnum}*: Er?ors" );
352+
353+
final URI invalidModelElementName = new URI( sammBaseUri + "aspect-model:Er?ors:1.1.0:dummy#TestAspect" );
354+
assertThatExceptionOfType( UrnSyntaxException.class )
355+
.isThrownBy( () -> AspectModelUrn.fromUrn( invalidModelElementName ) )
356+
.withMessage( "The model element name must match \\p{Alpha}\\p{Alnum}*: Er?ors" );
357+
}
345358
}

documentation/developer-guide/modules/tooling-guide/pages/maven-plugin.adoc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,50 @@ Configuration Properties:
523523
| `outputDirectory` | The path to the directory where the generated JSON payload will be written to. | `String` | none | {ok}
524524
|===
525525

526+
=== Generating JSON-LD representation of an Aspect Model
527+
528+
The `generateJsonLd` goal generates a JSON-LD represention of a given Aspect Model. The default life cycle phase for the goal is `generate-resources`.
529+
530+
Usage:
531+
532+
[source,xml,subs=attributes+]
533+
----
534+
<build>
535+
<plugins>
536+
<plugin>
537+
<artifactId>esmf-aspect-model-maven-plugin</artifactId>
538+
<executions>
539+
<execution>
540+
<id>generate-jsonld</id>
541+
<goals>
542+
<goal>generateJsonLd</goal>
543+
</goals>
544+
</execution>
545+
</executions>
546+
<configuration>
547+
<modelsRootDirectory>$\{path-to-models-root}</modelsRootDirectory>
548+
<includes>
549+
<include>$\{urn-of-aspect-model-to-be-included}</include>
550+
</includes>
551+
<outputDirectory>$\{directory-for-generated-source-files}</outputDirectory>
552+
</configuration>
553+
</plugin>
554+
</plugins>
555+
</build>
556+
----
557+
558+
Configuration Properties:
559+
560+
[width="100%", options="header", cols="20,50,10,10,10"]
561+
|===
562+
| Property | Description | Type | Default Value | Required
563+
| `detailedValidationMessages` | Detailed validation messages if the model can not be loaded | `Boolean` | `false` | {nok}
564+
| `modelsRootDirectory` | The path to the root directory containing the Aspect Model file(s). | `String` | `$\{basedir}/src/main/resources/aspects` | {nok}
565+
| `includes` | A list of Aspect Model URNs identifying the Aspect Models to be included in the plugin execution. | `String` | none | {ok}
566+
| `outputDirectory` | The path to the directory where the generated JSON-LD will be written to. | `String` | none | {ok}
567+
|===
568+
569+
526570
== Pretty Print
527571

528572
The `prettyPrint` goal formats the given Aspect Model. The formatted file is written to the location

documentation/developer-guide/modules/tooling-guide/pages/samm-cli.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ The available options and their meaning can also be seen in the help text of the
146146
.3+| [[aspect-to-json]] aspect <model> to json | Generate example JSON payload data for an Aspect Model | `samm aspect AspectModel.ttl to json`
147147
| _--output, -o_ : output file path (default: stdout) |
148148
| _--custom-resolver_ : use an external resolver for the resolution of the model elements |
149+
.3+| [[aspect-to-jsonld]] aspect <model> to jsonld | Generate JSON-LD representation of an Aspect Model | `samm aspect AspectModel.ttl to jsonld`
150+
| _--output, -o_ : output file path (default: stdout) |
151+
| _--custom-resolver_ : use an external resolver for the resolution of the model elements |
149152
.4+| [[aspect-to-schema]] aspect <model> to schema | Generate JSON schema for an Aspect Model | `samm aspect AspectModel.ttl to schema`
150153
| _--output, -o_ : output file path (default: stdout) |
151154
| _--language, -l_ : The language from the model for which a JSON schema should be
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
3+
*
4+
* See the AUTHORS file(s) distributed with this work for additional
5+
* information regarding authorship.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
10+
*
11+
* SPDX-License-Identifier: MPL-2.0
12+
*/
13+
14+
package org.eclipse.esmf.aspectmodel;
15+
16+
import java.io.IOException;
17+
import java.util.Set;
18+
19+
import org.eclipse.esmf.aspectmodel.generator.jsonld.AspectModelToJsonLdGenerator;
20+
import org.eclipse.esmf.metamodel.Aspect;
21+
22+
import org.apache.maven.plugin.MojoExecutionException;
23+
import org.apache.maven.plugin.MojoFailureException;
24+
import org.apache.maven.plugins.annotations.LifecyclePhase;
25+
import org.apache.maven.plugins.annotations.Mojo;
26+
import org.slf4j.Logger;
27+
import org.slf4j.LoggerFactory;
28+
29+
@Mojo( name = "generateJsonLd", defaultPhase = LifecyclePhase.GENERATE_RESOURCES )
30+
public class GenerateJsonLd extends AspectModelMojo {
31+
private static final Logger LOG = LoggerFactory.getLogger( GenerateJsonLd.class );
32+
33+
@Override
34+
public void executeGeneration() throws MojoExecutionException, MojoFailureException {
35+
validateParameters();
36+
37+
final Set<Aspect> aspects = loadAspects();
38+
try {
39+
for ( final Aspect context : aspects ) {
40+
final AspectModelToJsonLdGenerator generator = new AspectModelToJsonLdGenerator( context );
41+
generator.generateJsonLd( name -> getOutputStreamForFile( name + ".jsonld", outputDirectory ) );
42+
}
43+
} catch ( final IOException exception ) {
44+
throw new MojoExecutionException( "Could not generate JSON-LD.", exception );
45+
}
46+
LOG.info( "Successfully generated JSON-LD for Aspect Models." );
47+
}
48+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
3+
*
4+
* See the AUTHORS file(s) distributed with this work for additional
5+
* information regarding authorship.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
10+
*
11+
* SPDX-License-Identifier: MPL-2.0
12+
*/
13+
14+
package org.eclipse.esmf.aspectmodel;
15+
16+
import static org.assertj.core.api.Assertions.assertThat;
17+
import static org.assertj.core.api.Assertions.assertThatCode;
18+
19+
import java.io.File;
20+
21+
import org.apache.maven.plugin.Mojo;
22+
import org.junit.Test;
23+
24+
public class GenerateJsonLdTest extends AspectModelMojoTest {
25+
26+
@Test
27+
public void testGenerateJsonLdValidAspectModel() throws Exception {
28+
final File testPom = getTestFile( "src/test/resources/generate-jsonld-spec-json-pom-to-file.xml" );
29+
final Mojo generateJsonLd = lookupMojo( "generateJsonLd", testPom );
30+
assertThatCode( generateJsonLd::execute ).doesNotThrowAnyException();
31+
assertThat( generatedFilePath( "AspectWithEvent.jsonld" ) ).exists();
32+
}
33+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright (c) 2024 Robert Bosch Manufacturing Solutions GmbH
4+
~
5+
~ See the AUTHORS file(s) distributed with this work for additional
6+
~ information regarding authorship.
7+
~
8+
~ This Source Code Form is subject to the terms of the Mozilla Public
9+
~ License, v. 2.0. If a copy of the MPL was not distributed with this
10+
~ file, You can obtain one at https://mozilla.org/MPL/2.0/.
11+
~
12+
~ SPDX-License-Identifier: MPL-2.0
13+
-->
14+
15+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
16+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
17+
<modelVersion>4.0.0</modelVersion>
18+
19+
<groupId>org.eclipse.esmf</groupId>
20+
<artifactId>test-generate-jsonld-spec-mojo</artifactId>
21+
<version>1.0</version>
22+
<packaging>jar</packaging>
23+
<name>Test Generate JSON-LD Spec Mojo</name>
24+
25+
<build>
26+
<plugins>
27+
<plugin>
28+
<artifactId>esmf-aspect-model-maven-plugin</artifactId>
29+
<configuration>
30+
<modelsRootDirectory>${basedir}/../../core/esmf-test-aspect-models/src/main/resources/valid</modelsRootDirectory>
31+
<includes>
32+
<include>urn:samm:org.eclipse.esmf.test:1.0.0#AspectWithEvent</include>
33+
</includes>
34+
<outputDirectory>${basedir}/target/test-artifacts</outputDirectory>
35+
</configuration>
36+
</plugin>
37+
</plugins>
38+
</build>
39+
</project>

tools/samm-cli/src/main/java/org/eclipse/esmf/aspect/AspectToCommand.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.eclipse.esmf.aspect.to.AspectToHtmlCommand;
2121
import org.eclipse.esmf.aspect.to.AspectToJavaCommand;
2222
import org.eclipse.esmf.aspect.to.AspectToJsonCommand;
23+
import org.eclipse.esmf.aspect.to.AspectToJsonLdCommand;
2324
import org.eclipse.esmf.aspect.to.AspectToJsonSchemaCommand;
2425
import org.eclipse.esmf.aspect.to.AspectToOpenapiCommand;
2526
import org.eclipse.esmf.aspect.to.AspectToPngCommand;
@@ -36,6 +37,7 @@
3637
AspectToHtmlCommand.class,
3738
AspectToJavaCommand.class,
3839
AspectToJsonCommand.class,
40+
AspectToJsonLdCommand.class,
3941
AspectToOpenapiCommand.class,
4042
AspectToAsyncapiCommand.class,
4143
AspectToPngCommand.class,

0 commit comments

Comments
 (0)