Creating and Modifying Aspect Models

Programmatically Creating Aspect Models

In certain situations, particularly for test code, it is desirable to programmatically create an Aspect Model. For this, the SammBuilder class can be used. It provides static builder methods for all model element types, e.g., aspect(), property() and so on. Using the Elements. static import allows easy access to predefined model elements such as samm_c.Text. The DataTypes. static import allows access to all valid SAMM data types, such as xsd.integer, xsd.dateTime and samm.curie.

import static org.eclipse.esmf.metamodel.DataTypes.*;
import static org.eclipse.esmf.metamodel.Elements.*;
import static org.eclipse.esmf.metamodel.builder.SammBuilder.*;

import java.util.Locale;

import org.eclipse.esmf.aspectmodel.urn.AspectModelUrn;
import org.eclipse.esmf.metamodel.Aspect;
final AspectModelUrn namespace = AspectModelUrn.fromUrn( "urn:samm:org.example:1.0.0" );
final Aspect aspect = aspect( namespace.withName( "Aspect" ) )
      .preferredName( "My Aspect" )
      .property( property( namespace.withName( "property" ) )
            .preferredName( "My Property" )
            .description( "This is a test property" )
            .characteristic( samm_c.Text )
            .build() )
      .property( property( namespace.withName( "mySecondProperty" ) )
            .preferredName( "My second Property", Locale.ENGLISH )
            .description( "This is my second test property", Locale.ENGLISH )
            .characteristic( trait( namespace.withName( "MyTrait" ) )
                  .preferredName( "My Trait" )
                  .baseCharacteristic( characteristic()
                        .preferredName( "Custom characteristic" )
                        .dataType( xsd.integer )
                        .build() )
                  .constraint( regularExpressionConstraint()
                        .value( "a.*b" )
                        .build() )
                  .build() )
            .build() )
      .build();

When you use AssertJ for testing, you can add a dependency to the tests jar provided by the esmf-aspect-meta-model-java module:

Maven
<dependency>
    <groupId>org.eclipse.esmf</groupId>
    <artifactId>esmf-aspect-meta-model-java</artifactId>
    <version>2.12.0</version>
    <classifier>tests</classifier>
    <type>test-jar</type>
    <scope>test</scope>
</dependency>
Gradle Groovy DSL
implementation 'org.eclipse.esmf:esmf-aspect-meta-model-java:2.12.0:tests'
Gradle Kotlin DSL
implementation("org.eclipse.esmf:esmf-aspect-meta-model-java:2.12.0:tests")

Add a static import to org.eclipse.esmf.test.shared.AspectModelAsserts.assertThat to your test code, then you can use custom fluent assertions similar to the SammBuilder, for asserting properties of an Aspect Model:

assertThat( aspect )
      .hasPreferredName( "My Aspect", Locale.ENGLISH )
      .hasDescriptionMatching( description -> description.getValue().contains( "is my" ) )
      .hasSinglePropertyThat()
      .hasSameNamespaceAs( aspect )
      .hasName( "property" )
      .hasPreferredName( "Meine Property", Locale.GERMAN );

final Property property = aspect.getPropertyByName( "property" ).orElseThrow();
assertThat( property )
      .characteristic()
      .hasSameNamespaceAs( aspect )
      .hasName( "MySingleEntity" )
      .isSingleEntityThat()
      .dataType()
      .isEntityThat()
      .hasName( "MyEntity" );

Overloaded assertThat() methods are provided for all Aspect Model Elements, e.g., Aspect, Property, Characteristic, Trait, etc., as well as for AspectModel and AspectModel.

Modifying Aspect Models

You can use the AspectChangeManager to modify an Aspect Model. Each modifying operation performed on an Aspect Model is called a change. Instances of classes that implement the Change interface can be passed to the AspectChangeManager applyChange() method. Available `Change`s include renaming Aspect Model files or Model elements, adding and removing Aspect Model files and moving Aspect Model elements to other or new files in the same or another namespace.

Show used imports
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.eclipse.esmf.aspectmodel.edit.AspectChangeManager;
import org.eclipse.esmf.aspectmodel.edit.AspectChangeManagerConfig;
import org.eclipse.esmf.aspectmodel.edit.AspectChangeManagerConfigBuilder;
import org.eclipse.esmf.aspectmodel.edit.Change;
import org.eclipse.esmf.aspectmodel.edit.ChangeGroup;
import org.eclipse.esmf.aspectmodel.edit.ChangeReport;
import org.eclipse.esmf.aspectmodel.edit.ChangeReportFormatter;
import org.eclipse.esmf.aspectmodel.edit.change.MoveElementToNewFile;
import org.eclipse.esmf.aspectmodel.edit.change.RenameElement;
import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader;
import org.eclipse.esmf.metamodel.AspectModel;
final AspectModel aspectModel = new AspectModelLoader().load(
      // a File, InputStream or AspectModelUrn
);

// All changes to an Aspect Model are done using an AspectChangeManager.
// Optionally, you can pass a config object as first constructor argument:
final AspectChangeManagerConfig config = AspectChangeManagerConfigBuilder.builder()
      .detailedChangeReport( true )
      .defaultFileHeader( List.of( "Generated on "
            + new SimpleDateFormat( "dd-MM-yyyy" ).format( new Date() ) ) )
      .build();
final AspectChangeManager changeManager = new AspectChangeManager( config, aspectModel );

// You can create a single change, or you can combine multiple changes into a group.
// For all possible refactoring operations, see classes implementing the Change interface.
final Change refactorModel = new ChangeGroup( List.of(
      // Rename an element. This works with with samm:Aspect and all other model elements.
      new RenameElement( aspectModel.aspect(), "MyAspect" ),
      // Move an element to a new Aspect Model file in the same namespace.
      new MoveElementToNewFile(
            // The element to move.
            aspectModel.aspect().getProperties().get( 0 ),
            // If you intend to write the model to the file system, set the location
            // for the newly created file to some sensible location  here.
            URI.create( "file:///temp/out.ttl" ) )
) );

// Apply the changes and get a report that summerizes the changes.
final ChangeReport changeReport = changeManager.applyChange( refactorModel );

// If you want to display the change report, you can serialize it to a string:
ChangeReportFormatter.INSTANCE.apply( changeReport, config );

// Alternatively, you can also get views on collections containing modified/
// added/removed files for the last applied change.
changeManager.createdFiles().forEach( file -> System.out.println( "Created: " + file ) );
changeManager.modifiedFiles().forEach( file -> System.out.println( "Modified: " + file ) );
changeManager.removedFiles().forEach( file -> System.out.println( "Removed: " + file ) );

// At this point, you could use the AspectChangeManager's undo() method to revert
// the last change (refactorModel in this case); afterwards you can also redo().
// This functionality is mainly interesting when refactoring the Aspect Model
// interactively.

// If you want to write the model changes to the file system, use the AspectSerializer.
// Each AspectModelFile will be written to its respective source location.
// Alternatively, the AspectSerializer also provides a method to write an AspectModelFile
// into a String.
AspectSerializer.INSTANCE.write( aspectModel );

Serializing a Java Aspect Model into a RDF/Turtle Aspect Model

The serialize an Aspect into its corresponding RDF/Turtle representation, you can use the AspectSerializer, as demonstrated in the example below:

Show used imports
import java.io.File;

import org.eclipse.esmf.aspectmodel.AspectModelFile;
import org.eclipse.esmf.aspectmodel.serializer.AspectSerializer;
import org.eclipse.esmf.aspectmodel.loader.AspectModelLoader;
import org.eclipse.esmf.metamodel.AspectModel;
// AspectModel as returned by the AspectModelLoader
final AspectModel aspectModel = // ...

// A String that contains the pretty printed Aspect Model
final String aspectString =
      AspectSerializer.INSTANCE.aspectToString( aspectModel.aspect() );

Alternatively, you can also serialize a complete AspectModelFile:

AspectModelFile aspectModelFile = // ...
final String fileString = aspectModelFile.sourceRepresentation();

To include the serializer, use the following dependency:

Maven
<dependency>
    <groupId>org.eclipse.esmf</groupId>
    <artifactId>esmf-aspect-meta-model-java</artifactId>
    <version>2.12.0</version>
</dependency>
Gradle Groovy DSL
implementation 'org.eclipse.esmf:esmf-aspect-meta-model-java:2.12.0'
Gradle Kotlin DSL
implementation("org.eclipse.esmf:esmf-aspect-meta-model-java:2.12.0")