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

Converting Aspect to JSON-LD #651

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* 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.generator.jsonld;

import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.function.Function;

import org.eclipse.esmf.aspectmodel.generator.AbstractGenerator;
import org.eclipse.esmf.metamodel.Aspect;

public class AspectModelToJsonLdGenerator extends AbstractGenerator {

private static final String JSON_LD_FORMAT = "JSON-LD";
private final Aspect aspect;

public AspectModelToJsonLdGenerator( final Aspect aspect ) {
this.aspect = aspect;
}

/**
* Generates a JSON-LD representation of the aspect's source model and writes it to an output stream.
*
* <p>This method takes a function (nameMapper) that maps the name of the aspect to an output stream,
* then writes the aspect's source model in JSON-LD format to that stream. The function is expected
* to accept the aspect's name as a parameter and return an appropriate OutputStream where the JSON-LD
* will be written. The OutputStream is closed automatically when the operation is complete.</p>
*
* @param nameMapper a function that maps the aspect name to an OutputStream for writing the JSON-LD.
* @throws IOException if an I/O error occurs while writing to the output stream.
*/
public void generateJsonLd( final Function<String, OutputStream> nameMapper ) throws IOException {
try ( final OutputStream output = nameMapper.apply( aspect.getName() ) ) {
aspect.getSourceFile().sourceModel().write( output, JSON_LD_FORMAT );
}
}

public String generateJsonLd() {
StringWriter stringWriter = new StringWriter();
aspect.getSourceFile().sourceModel().write( stringWriter, JSON_LD_FORMAT );
return stringWriter.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.eclipse.esmf.aspectmodel.generator.jsonld;

import static org.assertj.core.api.Assertions.assertThat;

import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
import org.eclipse.esmf.metamodel.Aspect;
import org.eclipse.esmf.test.TestAspect;
import org.eclipse.esmf.test.TestResources;

import org.junit.jupiter.api.Test;

class AspectModelJsonLdGeneratorTest {

@Test
void generateTest() {
final Aspect aspect = TestResources.load( TestAspect.ASPECT_WITH_ENTITY_LIST ).aspect();
final AspectModelToJsonLdGenerator jsonGenerator = new AspectModelToJsonLdGenerator( aspect );
final String generatedJsonLd = jsonGenerator.generateJsonLd();

assertJsonLdMeta( generatedJsonLd, aspect.urn() );
}

private void assertJsonLdMeta( final String generatedJsonLd, final AspectModelUrn aspectModelUrn ) {
final String context = """
"@context": {
"xsd": "http://www.w3.org/2001/XMLSchema#",
"samm-c": "urn:samm:org.eclipse.esmf.samm:characteristic:2.1.0#",
"samm": "urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#",
"@vocab": "urn:samm:org.eclipse.esmf.test:1.0.0#"
}
""";

assertThat( generatedJsonLd ).contains( "\"@graph\": [" );
assertThat( generatedJsonLd ).contains( context );
assertThat( generatedJsonLd ).contains( "\"xsd\": \"http://www.w3.org/2001/XMLSchema#\"," );
assertThat( generatedJsonLd ).contains( String.format( "\"@id\": \"%s\"", aspectModelUrn.toString() ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,50 @@ Configuration Properties:
| `outputDirectory` | The path to the directory where the generated JSON payload will be written to. | `String` | none | {ok}
|===

=== Generating JSON-LD representation of an Aspect Model

The `generateJsonLd` goal generates a JSON-LD represention of a given Aspect Model. The default life cycle phase for the goal is `generate-resources`.

Usage:

[source,xml,subs=attributes+]
----
<build>
<plugins>
<plugin>
<artifactId>esmf-aspect-model-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-jsonld</id>
<goals>
<goal>generateJsonLd</goal>
</goals>
</execution>
</executions>
<configuration>
<modelsRootDirectory>$\{path-to-models-root}</modelsRootDirectory>
<includes>
<include>$\{urn-of-aspect-model-to-be-included}</include>
</includes>
<outputDirectory>$\{directory-for-generated-source-files}</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
----

Configuration Properties:

[width="100%", options="header", cols="20,50,10,10,10"]
|===
| Property | Description | Type | Default Value | Required
| `detailedValidationMessages` | Detailed validation messages if the model can not be loaded | `Boolean` | `false` | {nok}
| `modelsRootDirectory` | The path to the root directory containing the Aspect Model file(s). | `String` | `$\{basedir}/src/main/resources/aspects` | {nok}
| `includes` | A list of Aspect Model URNs identifying the Aspect Models to be included in the plugin execution. | `String` | none | {ok}
| `outputDirectory` | The path to the directory where the generated JSON-LD will be written to. | `String` | none | {ok}
|===


== Pretty Print

The `prettyPrint` goal formats the given Aspect Model. The formatted file is written to the location
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ The available options and their meaning can also be seen in the help text of the
.3+| [[aspect-to-json]] aspect <model> to json | Generate example JSON payload data for an Aspect Model | `samm aspect AspectModel.ttl to json`
| _--output, -o_ : output file path (default: stdout) |
| _--custom-resolver_ : use an external resolver for the resolution of the model elements |
.3+| [[aspect-to-jsonld]] aspect <model> to jsonld | Generate JSON-LD representation of an Aspect Model | `samm aspect AspectModel.ttl to jsonld`
| _--output, -o_ : output file path (default: stdout) |
| _--custom-resolver_ : use an external resolver for the resolution of the model elements |
.4+| [[aspect-to-schema]] aspect <model> to schema | Generate JSON schema for an Aspect Model | `samm aspect AspectModel.ttl to schema`
| _--output, -o_ : output file path (default: stdout) |
| _--language, -l_ : The language from the model for which a JSON schema should be
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* 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;

import java.io.IOException;
import java.util.Set;

import org.eclipse.esmf.aspectmodel.generator.jsonld.AspectModelToJsonLdGenerator;
import org.eclipse.esmf.metamodel.Aspect;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Mojo( name = "generateJsonLd", defaultPhase = LifecyclePhase.GENERATE_RESOURCES )
public class GenerateJsonLd extends AspectModelMojo {
private static final Logger LOG = LoggerFactory.getLogger( GenerateJsonLd.class );

@Override
public void executeGeneration() throws MojoExecutionException, MojoFailureException {
validateParameters();

final Set<Aspect> aspects = loadAspects();
try {
for ( final Aspect context : aspects ) {
final AspectModelToJsonLdGenerator generator = new AspectModelToJsonLdGenerator( context );
generator.generateJsonLd( name -> getOutputStreamForFile( name + ".jsonld", outputDirectory ) );
}
} catch ( final IOException exception ) {
throw new MojoExecutionException( "Could not generate JSON-LD.", exception );
}
LOG.info( "Successfully generated JSON-LD for Aspect Models." );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;

import java.io.File;

import org.apache.maven.plugin.Mojo;
import org.junit.Test;

public class GenerateJsonLdTest extends AspectModelMojoTest {

@Test
public void testGenerateJsonLdValidAspectModel() throws Exception {
final File testPom = getTestFile( "src/test/resources/generate-jsonld-spec-json-pom-to-file.xml" );
final Mojo generateJsonLd = lookupMojo( "generateJsonLd", testPom );
assertThatCode( generateJsonLd::execute ).doesNotThrowAnyException();
assertThat( generatedFilePath( "AspectWithEvent.jsonld" ) ).exists();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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
-->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.eclipse.esmf</groupId>
<artifactId>test-generate-jsonld-spec-mojo</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<name>Test Generate JSON-LD Spec Mojo</name>

<build>
<plugins>
<plugin>
<artifactId>esmf-aspect-model-maven-plugin</artifactId>
<configuration>
<modelsRootDirectory>${basedir}/../../core/esmf-test-aspect-models/src/main/resources/valid</modelsRootDirectory>
<includes>
<include>urn:samm:org.eclipse.esmf.test:1.0.0#AspectWithEvent</include>
</includes>
<outputDirectory>${basedir}/target/test-artifacts</outputDirectory>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.eclipse.esmf.aspect.to.AspectToHtmlCommand;
import org.eclipse.esmf.aspect.to.AspectToJavaCommand;
import org.eclipse.esmf.aspect.to.AspectToJsonCommand;
import org.eclipse.esmf.aspect.to.AspectToJsonLdCommand;
import org.eclipse.esmf.aspect.to.AspectToJsonSchemaCommand;
import org.eclipse.esmf.aspect.to.AspectToOpenapiCommand;
import org.eclipse.esmf.aspect.to.AspectToPngCommand;
Expand All @@ -36,6 +37,7 @@
AspectToHtmlCommand.class,
AspectToJavaCommand.class,
AspectToJsonCommand.class,
AspectToJsonLdCommand.class,
AspectToOpenapiCommand.class,
AspectToAsyncapiCommand.class,
AspectToPngCommand.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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.aspect.to;

import java.io.IOException;

import org.eclipse.esmf.AbstractCommand;
import org.eclipse.esmf.LoggingMixin;
import org.eclipse.esmf.ResolverConfigurationMixin;
import org.eclipse.esmf.aspect.AspectToCommand;
import org.eclipse.esmf.aspectmodel.generator.jsonld.AspectModelToJsonLdGenerator;
import org.eclipse.esmf.exception.CommandException;

import picocli.CommandLine;

@CommandLine.Command( name = AspectToJsonLdCommand.COMMAND_NAME,
description = "Generate JSON-LD representation of an Aspect Model",
descriptionHeading = "%n@|bold Description|@:%n%n",
parameterListHeading = "%n@|bold Parameters|@:%n",
optionListHeading = "%n@|bold Options|@:%n"
)
public class AspectToJsonLdCommand extends AbstractCommand {
public static final String COMMAND_NAME = "jsonld";

@CommandLine.Option( names = { "--output", "-o" }, description = "Output file path" )
private String outputFilePath = "-";

@CommandLine.ParentCommand
private AspectToCommand parentCommand;

@CommandLine.Mixin
private LoggingMixin loggingMixin;

@CommandLine.Mixin
private ResolverConfigurationMixin resolverConfiguration;

@Override
public void run() {
final AspectModelToJsonLdGenerator generator = new AspectModelToJsonLdGenerator(
loadAspectOrFail( parentCommand.parentCommand.getInput(), resolverConfiguration ) );
try {
// we intentionally override the name of the generated artifact here to the name explicitly desired by the user (outputFilePath),
// as opposed to what the model thinks it should be called (name)
generator.generateJsonLd( name -> getStreamForFile( outputFilePath ) );
} catch ( final IOException e ) {
throw new CommandException( e );
}
}
}
Loading
Loading