SAMM CLI

The SAMM CLI is a command line tool for the validation of Aspect Models and the generation of artifacts, such as documentation or code, from Aspect Models.

The SAMM CLI is available as a native executable for multiple platforms and as an executable jar:

Downloading samm-cli

Running the SAMM CLI

For the executable jar, call java -jar samm-cli-2.7.0.jar followed by one of the following subcommands (e.g., java -jar samm-cli-2.7.0.jar help). In the following sections, samm will be used as the command name.

To make samm-cli easier to call, you can add an alias to the configuration of the shell of your choice. For example, for Bash, you could add the following line to .bashrc:

alias samm='java -jar /location/to/samm-cli-2.7.0.jar'
  1. For the Windows native executable:

    • Download: Download via above link or visit the repository of the Java SDK which contains the SAMM CLI at the Github releases page and download executable file for Windows.

    • Extract: extract it to a location of your choice.

    • Open samm.exe: This will open a command prompt in this directory, where you can enter further samm commands.

    • Input: Make sure to read the below documentation and provide model files in the correct directory structure.

  2. For the Linux native executable:

    • Download: Download via above link or visit the repository of the Java SDK which contains the SAMM CLI at the Github releases page and download executable file for Linux.

    • Extract: Unpack the archive to your preferred directory.

    • Open Terminal: Open the Terminal and navigate to the directory with the application.

    • Input: Make sure to read the below documentation and provide model files in the correct directory structure.

    • Execute: Run the application using the command ./samm.

Successful execution of a command is signaled by returning 0. In case of a logical or other internal error the error code 1 is being returned. Missing or wrong command parameters result in error code 2 being returned.

To get help for a certain subcommand, add 'help' before the subcommand name or add --help to the end, e.g., samm help aspect or samm aspect --help. Each subcommand can have its own set of options which allow the user to further fine-tune the execution of the command. The available options and their meaning can also be seen in the help text of the individual subcommands.

Command Description/Options Examples

help

Get overview of all commands

samm help

help <subcommand>

Get help for a specific subcommand

samm help aspect

aspect help <aspect subcommand>

Get help for aspect subcommands

samm aspect help validate

aspect <model> validate

Validate Aspect Model

samm aspect AspectModel.ttl validate

--custom-resolver : use an external resolver for the resolution of the model elements

samm aspect AspectModel.ttl validate --custom-resolver myresolver.sh

aspect <model> prettyprint

Pretty-print Aspect Model

samm aspect AspectModel.ttl prettyprint

--output, -o : the output will be saved to the given file

samm aspect AspectModel.ttl prettyprint -o c:\Results\PrettyPrinted.ttl

aspect <model> migrate

Migrate Aspect Model to the latest SAMM version

samm aspect AspectModel.ttl migrate AspectModel.ttl

--output, -o : the output will be saved to the given file

samm aspect AspectModel.ttl migrate AspectModel.ttl -o c:\Results\MigratedModel.ttl

aspect <model> to html

Generate HTML documentation for an Aspect Model

samm aspect AspectModel.ttl to html

--output, -o : the output will be saved to the given file

samm aspect AspectModel.ttl to html -o c:\Model.html

--css, -c : CSS file with custom styles to be included in the generated HTML documentation

samm aspect AspectModel.ttl to html -c c:\styles.css

--language, -l : The language from the model for which the HTML should be generated (default: en)

samm aspect AspectModel.ttl to html -l de

--custom-resolver : use an external resolver for the resolution of the model elements

samm aspect AspectModel.ttl to html --custom-resolver myresolver.bat

aspect <model> to png

Generate PNG diagram for Aspect Model

samm aspect AspectModel.ttl to png

--output, -o : output file path (default: stdout); as PNG is a binary format, it is strongly recommended to output the result to a file by using the -o option or the console redirection operator '>')

--language, -l : the language from the model for which the diagram should be generated (default: en)

--custom-resolver : use an external resolver for the resolution of the model elements

samm aspect AspectModel.ttl to png --custom-resolver resolver.jar

aspect <model> to svg

Generate SVG diagram for Aspect Model

samm aspect AspectModel.ttl to svg

--output, -o : the output will be saved to the given file

--language, -l : the language from the model for which the diagram should be generated (default: en)

--custom-resolver : use an external resolver for the resolution of the model elements

samm aspect AspectModel.ttl to svg --custom-resolver "java -jar resolver.jar"

aspect <model> to java

Generate Java classes from an Aspect Model

samm aspect AspectModel.ttl to java

--output-directory, -d : output directory to write files to (default: current directory)

--package-name, -pn : package to use for generated Java classes

samm aspect AspectModel.ttl to java -pn org.company.product

--no-jackson, -nj : disable Jackson annotation generation in generated Java classes

--template-library-file, -tlf : the path and name of the Velocity template file containing the macro library

--execute-library-macros, -elm : Execute the macros provided in the Velocity macro library

--static, -s : generate Java domain classes for a Static Meta Model

--custom-resolver : use an external resolver for the resolution of the model elements

aspect <model> to openapi

Generate OpenAPI specification for an Aspect Model

samm aspect AspectModel.ttl to openapi -j

--output, -o : output file path (default: stdout)

--api-base-url, -b : the base url for the Aspect API used in the OpenAPI specification

samm aspect AspectModel.ttl to openapi -j -b http://mysite.de

--json, -j : generate a JSON specification for an Aspect Model (default format is YAML)

--comment, -c : only in combination with --json; generates $comment OpenAPI 3.1 keyword for all samm:see attributes

--parameter-file, -p : the path to a file including the parameter for the Aspect API endpoints

For detailed description, see the section bellow

--semantic-version, -sv : use the full semantic version from the Aspect Model as the version for the Aspect API

--resource-path, -r : the resource path for the Aspect API endpoints

For detailed description, see the section bellow

--include-query-api, -q : include the path for the Query Aspect API Endpoint in the OpenAPI specification

--paging-none, -pn : exclude paging information for the Aspect API Endpoint in the OpenAPI specification

--paging-cursor-based, -pc : in case there is more than one paging possibility, it must be cursor based paging

--paging-offset-based, -po : in case there is more than one paging possibility, it must be offset based paging

--paging-time-based, -pt : in case there is more than one paging possibility, it must be time based paging

--language, -l : The language from the model for which an OpenAPI specification should be generated (default: en)

samm aspect AspectModel.ttl to openapi -l de

--separate-files, -sf : Create separate files for each schema

--custom-resolver : use an external resolver for the resolution of the model elements

aspect <model> to asyncapi

Generate AsyncAPI specification for an Aspect Model

samm aspect AspectModel.ttl to asyncapi

--output, -o : output file path (default: stdout)

--channel-address, -ca : Sets the channel address (i.e., for MQTT, the topic’s name). OpenAPI specification

samm aspect AspectModel.ttl to asyncapi -ca 123-456/789-012/namespace/1.0.0/Aspect

--application-id, -ai : Sets the application id, e.g. an identifying URL.

--semantic-version, -sv : use the full semantic version from the Aspect Model as the version for the Aspect API

--language, -l : The language from the model for which an AsyncAPI specification should be generated (default: en)

samm aspect AspectModel.ttl to asyncapi -l de

--separate-files, -sf : Create separate files for each schema

--custom-resolver : use an external resolver for the resolution of the model elements

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

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 generated (default: en)

samm aspect AspectModel.ttl to schema -l de

--custom-resolver : use an external resolver for the resolution of the model elements

aspect <model> to aas

Generate an Asset Administration Shell (AAS) submodel template from an Aspect Model

samm aspect AspectModel.ttl to aas

--output, -o : output file path (default: stdout)

--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

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

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

To allow the users to provide their own custom implementations of a model resolver, --custom-resolver command-line switch can be used. The value of the switch can be any command which is directly executable by the underlying operating system (such as a batch script on Windows or a shell script on Linux/Unix). When a model element needs to be resolved, this command is executed with the URN of the element to resolve passed as the last parameter. The command can provide other parameters as well, the element URN will be added automatically as the last one by samm-cli. The resolved model definition is expected to be output to the stdout in Turtle format. From there, it is read by the samm-cli and passed on to the internal processing pipeline. In this way the extension can be flexibly done in any programming language/script language, including complex logic if necessary.

Using the CLI to create a JSON OpenAPI Specification

Every specification is based on one Aspect, which needs a separately defined server URL where the given aspect will be. The URL will be defined as string with the -b option, i.e.: https://www.example.org. The default URL, using the above defined --api-base-url, would result in https://www.example.org/api/v1/{tenantId}/<aspectName>;. By default, {tenantId} followed by the Aspect’s name is used as path, with the aspect name converted from CamelCase to kebab-case. The default path can be changed with the --resource-path switch. If the path is defined further, for example using --resource-path "/resources/{resourceId}", the resulting URL would be: https://www.example.org/resources/{resourceId}.

It will be required to specify the parameter, in case there is an additional parameter defined. This has to be done in JSON or in YAML, depending on the kind of specification chosen. For example: With the option --resource-path "/resources/{resourceId}" the generator constructs the URL https://www.example.org/resources/{resourceId} and then the --parameter-file defines the parameter resourceId in YAML:

resourceId:
  name: resourceId
  in: path
  description: An example resource Id.
  required: true
  schema:
    type: string

The full command for the native executable samm-cli would be:

samm aspect AspectModel.ttl to openapi -b "https://www.example.org" -r "/resources/{resourceId}" -p fileLocation

For the Java version of samm-cli, the full command would result in:

java -jar samm-cli-2.7.0.jar aspect AspectModel.ttl to openapi -b "https://www.example.org" -r "/resources/{resourceId}" -p fileLocation

Mapping between the Aspect Models and the OpenAPI Specification

In this section, a detailed description of the mapping between individual Aspect elements and the OpenAPI specification is given. To make it easier to follow, the mapping is explained based on a concrete example, divided into logically coherent blocks. Please bear in mind that these blocks are snippets or fragments of a larger whole; viewed in isolation they do not necessarily form a valid or meaningful Aspect Model or OpenAPI specification.

Naming and versioning

Please consider the following model fragment, with the attention focused on the numbered elements:

@prefix : <urn:samm:com.mycompany.myapplication:1.0.0#> . (1)
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .

:Test a samm:Aspect; (3)
    samm:preferredName "TestAspect"@en ; (2)
    samm:preferredName "TestAspekt"@de .
1 prefix used to build the full URN of :Test Aspect
2 the preferred name of the Aspect in language of user’s choice
3 the name of the Aspect

For the generated OpenAPI specification, the following mapping would apply:

{
  "openapi" : "3.0.3",
  "info" : {
    "title" : "TestAspect", (2) (3)
    "version" : "v2" (1)
  }
}
1 depending on parameters used when generating the specification, this is either the major version of the full Aspect URN (2.0.0), or it can be the full version (v2.0.0), if using -sv (semantic version) command line switch
2 if present, samm:preferredName is used as the value for the title element of the specification
3 as samm:preferredName is an optional element, in cases when it is missing the name of the Aspect is used instead

The version information as described above is also used in the URL definitions of the servers block of the specification:

{
 "servers" : [ {
    "url" : "http://mysite/api/v2", (1)
    "variables" : {
      "api-version" : {
        "default" : "v2" (1)
      }
    }
  } ]
}

The name of the Aspect is used to generate several important OpenAPI artifacts, like the path definitions for the API:

{
 "paths" : {
    "/{tenant-id}/test" : { (3)
      "get" : {
        "tags" : [ "Test" ], (3)
        "operationId" : "getTest" (3)
      }
    }
  }
}

and the definitions for request bodies and responses in the corresponding blocks (requestBodies and responses) of the OpenAPI specification (example omitted for simplicity).

Mapping of Aspect and its properties

For each Aspect in the model, an entry in the components/schemas part of the OpenAPI specification is generated. For an example Aspect from the following fragment:

:Test a samm:Aspect; (1)
    samm:properties (
        :prop1 (2)
        [ samm:property :prop2; samm:payloadName "givenName"; ] (3)
        [ samm:property :prop3; samm:optional true; ] ). (4)

:prop1 a samm:Property;
    samm:description "Description of Property1"@en; (5)
    samm:characteristic :Enum. (6)

an entry like the one given in the following JSON will be generated:

"Test" : { (1)
  "type" : "object",
    "properties" : {
      "prop1" : { (2)
        "description" : "Description of Property1", (5)
        "$ref" : "#/components/schemas/urn_samm_test_2.0.0_Enum" (6)
      },
      "givenName" : { (3)
        "$ref" : "#/components/schemas/urn_samm_test_2.0.0_EntityChar"
      },
      "prop3" : { (4)
        "$ref" : "#/components/schemas/urn_samm_test_2.0.0_StringCharacteristic"
      }
    },
    "required" : [ "prop1", "givenName" ] (2) (3)
}
1 the name of the Aspect is used to name the schema object for the aspect
2 with plain property references, the name of the property is used to name the property definition
3 in cases where a payload name is defined on a specific property, it is used in preference to the plain property name
4 if the property use is also defined as optional, the property will not be included in the list of the required properties
5 the values of samm:description elements in property definitions are included in the generated JSON
6 for each of the properties characteristics an entry in components/schemas is generated and referenced here; if the characteristic is of complex type, the whole procedure is applied recursively to the complex type’s properties

Mapping of Aspect’s operations

If the Aspect also has a non-empty list of operations defined, like the one in the following example:

:AspectWithOperation a samm:Aspect ;
   samm:properties ( ) ;
   samm:operations ( :testOperation ) .

:testOperation a samm:Operation ;
   samm:input ( :input ) ; (1)
   samm:output :output . (2)

:output a samm:Property ;
   samm:characteristic samm-c:Text . (3)

:input a samm:Property ;
   samm:characteristic samm-c:Text . (4)

then additional entries are added to the generated OpenAPI specification. First, there is an additional entry in the paths section of the specification: /{tenant-id}/aspect-with-operation/operations. The available operations are then added to the components/schemas part:

{
 "Operation" : {
    "allOf" : [ {
      "$ref" : "#/components/schemas/JsonRpc"
    }, {
      "properties" : {
        "params" : {
          "type" : "object",
          "required" : [ "input" ], (1)
          "properties" : {
            "input" : { (1)
              "$ref" : "#/components/schemas/urn_samm_org.eclipse.esmf.samm_characteristic_2.0.0_Text" (3)
            }
          }
        },
        "method" : {
          "type" : "string",
          "description" : "The method name",
          "example" : "testOperation"
        }
      }
    } ]
  },
 "OperationResponse" : {
    "allOf" : [ {
      "$ref" : "#/components/schemas/JsonRpc"
    }, {
      "properties" : {
        "result" : {
          "type" : "object",
          "required" : [ "output" ], (2)
          "properties" : {
            "output" : { (2)
              "$ref" : "#/components/schemas/urn_samm_org.eclipse.esmf.samm_characteristic_2.0.0_Text" (4)
            }
          }
        }
      }
    } ]
  }
}
1 the names of the input
2 and output parameters are reflected in the properties generated for the request/response objects
3 the characteristics are generated
4 and referenced as described in the point 6 of the section "Mapping of Aspect and its properties"

As usual, corresponding entries referencing the definitions above are added to the requestBodies and responses sections (examples omitted for simplicity). For technical reasons, there may be a slight variation in the generated JSON depending on whether the aspect has one or more operations defined.

Mapping of Collections

There are some additional JSON entries generated for complex types related to various types of collections to facilitate access to the individual elements of these collections via paging. As these entries are rather of static character without direct references to any aspect elements, it suffices here to give a short overview about which kind of paging is available for which type of collection:

  • a general Collection - cursor and/or offset based paging

  • TimeSeries - cursor, offset and/or time based paging

For all these paging mechanisms, an additional entry with the name PagingSchema is generated in the components/schemas part of the specification, which is then used as the main response schema for the Aspect. Basically, instead of a single Aspect, a collection of Aspects is returned, together with optional total number of Aspects available in the collection:

"PagingSchema" : {
  "type" : "object",
  "properties" : {
    "items" : {
      "type" : "array",
      "items" : {
        "$ref" : "#/components/schemas/Test"
      }
    },
    "totalItems" : {
      "type" : "number"
    }
  }
}

Depending on the concrete paging model selected, there can be additional properties in the PagingSchema object. For cursor based paging, the cursor object denotes the position of the returned Aspects in relation to some other uniquely identifiable Aspect (before or after it):

"cursor" : {
  "type" : "object",
  "properties" : {
    "before" : {
      "type" : "string",
      "format" : "uuid"
    },
    "after" : {
      "type" : "string",
      "format" : "uuid"
    }
  }
},

For offset and time based paging, the data is returned in batches of requested size ("pages"), described using the following properties (the meaning of which is self explanatory):

"totalPages" : {
  "type" : "number"
},
"pageSize" : {
  "type" : "number"
},
"currentPage" : {
  "type" : "number"
}

In addition to the PagingSchema object, also several new parameters are added to the request parameters section of the generated document, with the help of which the size and/or the relative position of the returned data can be controlled. All paging mechanisms have the following parameters in common, the meaning of which can be discerned from their descriptions:

{
  "name" : "count",
  "in" : "query",
  "description" : "Number of items to return per call.",
  "required" : false,
  "schema" : {
    "type" : "number"
  }
},
{
  "name" : "totalItemCount",
  "in" : "query",
  "description" : "Flag that indicates that the total counts should be returned.",
  "required" : false,
  "schema" : {
    "type" : "boolean"
  }
}

Depending on the exact paging model selected, additional paging specific parameters are available. For offset based paging:

"name" : "start",
"in" : "query",
"description" : "Starting index which is starting by 0",
"required" : false,
"schema" : {
  "type" : "number"
}

For cursor based paging:

{
  "name" : "previous",
  "in" : "query",
  "description" : "URL to request the previous items. An empty value indicates there are no previous items.",
  "required" : false,
  "schema" : {
    "type" : "string",
    "format" : "uri"
  }
},{
  "name" : "next",
  "in" : "query",
  "description" : "URL to request the next items. An empty value indicates there are no other items.",
  "required" : false,
  "schema" : {
    "type" : "string",
    "format" : "uri"
    }
}, {
  "name" : "before",
  "in" : "query",
  "description" : "The cursor that points to the start of the page of items that has been returned.",
  "required" : false,
  "schema" : {
   "type" : "string",
    "format" : "uuid"
  }
}, {
  "name" : "after",
  "in" : "query",
  "description" : "The cursor that points to the end of items that has been returned.",
  "required" : false,
  "schema" : {
    "type" : "string",
    "format" : "uuid"
  }
}

And finally for the time based paging:

{
  "name" : "since",
  "in" : "query",
  "description" : "A timestamp that points to the start of the time-based data.",
  "required" : false,
  "schema" : {
    "type" : "string",
    "format" : "date-time"
  }
}, {
  "name" : "until",
  "in" : "query",
  "description" : "A timestamp that points to the end of the time-based data.",
  "required" : false,
  "schema" : {
    "type" : "string",
    "format" : "date-time"
  }
}, {
  "name" : "limit",
  "in" : "query",
  "description" : "Number of items to return per call.",
  "required" : false,
    "schema" : {
    "type" : "number"
  }
}

Using the CLI to create a JSON AsyncAPI Specification

As with OpenAPI, every AsyncAPI specification is based on one Aspect. Each Aspect is associated with one channel address. The channel address is set as string using with`--channel-address` or -ca option, e.g.: -ca 123-456/789-012/test/1.0.0/Aspect. The default channel address is derived from the Aspect’s URN and is constructed using the pattern {namespace}/{version}/{aspectName}.

The full command for the native executable samm-cli would be:

samm aspect AspectModel.ttl to asyncapi -ca "123-456/789-012/test/1.0.0/Aspect"

For the Java version of samm-cli, the corresponding full command is:

java -jar samm-cli-2.7.0.jar aspect AspectModel.ttl to asyncapi -ca "123-456/789-012/test/1.0.0/Aspect"

Mapping between the Aspect Models and the AsyncAPI Specification

In this section, a detailed description of the mapping between individual Aspect elements and the AsyncAPI specification is given. To make it easier to follow, the mapping is explained based on a concrete example, divided into logically coherent blocks. Please bear in mind that these blocks are snippets or fragments of a larger whole; viewed in isolation they do not necessarily form a valid or meaningful Aspect Model or AsyncAPI specification.

Naming and versioning

Please consider the following model fragment, with the attention focused on the numbered elements:

@prefix : <urn:samm:com.mycompany.myapplication:1.0.0#> . (1)
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .

:Movement a samm:Aspect ; (3)
   samm:name "Movement" ;
   samm:preferredName "My Movement Aspect"@en ; (2)
   samm:description "Aspect for movement information"@en . (4)
1 prefix used to build the full URN of :Movement Aspect
2 the preferred name of the Aspect in the language of the user’s choice
3 the name of the Aspect
4 the description of the Aspect

For the generated AsyncAPI specification, the following mapping would apply:

{
  "asyncapi" : "3.0.0",
  "info" : {
    "title" : "My Movement Aspect MQTT API", (2)
    "version" : "v2", (1)
    "description" : "Aspect for movement information" (3)
  }
}
1 depending on parameters used when generating the specification, this is either the major version of the full Aspect URN (2.0.0), or it can be the full version (v2.0.0), if using -sv (semantic version) command line switch
2 as samm:preferredName is used as the value for the title element of the specification (MQTT API defined automatically)
3 as samm:description is an optional element

The name of the Aspect is used to generate parts of the AsyncAPI specification, such as the channel definitions for the API:

{
 "channels" : {
    "Movement" : { (3)
      "address" : "movement/0.0.1/Movement", (3)
      "description" : "This channel for updating Movement Aspect.", (3)
      "parameters" : {
        "namespace" : "movement",
        "version" : "0.0.1",
        "aspect-name" : "Movement" (3)
      },
      "messages" : {}
    }
  }
}

Mapping of Aspect’s operations

The AsyncAPI specification is generated based on SAMM Operations and Events. his section describes how specification parts are generated for Operations. If the Aspect also has a non-empty list of Operations defined, such as the one in the following example:

:Movement a samm:Aspect ;
   samm:preferredName "movement"@en ;
   samm:description "Aspect for movement information"@en ;
   samm:properties ( ) ;
   samm:operations ( :getSpeed ) ;
   samm:events ( ) .

:getSpeed a samm:Operation ;
   samm:preferredName "Get speed"@en ;
   samm:description "Returns the current speed"@en ;
   samm:input ( :getSpeedInput ) ; (1)
   samm:output :getSpeedOutput . (2)

:getSpeedOutput a samm:Property ;
   samm:preferredName "getSpeed output"@en ;
   samm:description "Return value of the getSpeed operation"@en ;
   samm:characteristic :OutputCharacteristic .

:OutputCharacteristic a samm:Characteristic ;
   samm:preferredName "Output"@en ;
   samm:description "Describes the output of the getSpeed operation"@en ;
   samm:dataType :OutputEntity .

:OutputEntity a samm:Entity ;
   samm:preferredName "Output entity"@en ;
   samm:description "The structured response of getSpeed"@en ;
   samm:properties ( :outputEntityMessage ) .

:outputEntityMessage a samm:Property ;
   samm:characteristic samm-c:Text . (3)

:getSpeedInput a samm:Property ;
   samm:preferredName "getSpeed input"@en ;
   samm:description "The input to the getSpeed operation"@en ;
   samm:characteristic samm-c:Text . (4)

operations will be generated in some places of AsyncAPI specification: operations section, channel messages section and schemas section:

{
  "channels" : {
    "Movement" : {
      "address" : "movement/0.0.1/Movement",
      "description" : "This channel for updating Movement Aspect.",
      "parameters" : {
        "namespace" : "movement",
        "version" : "0.0.1",
        "aspect-name" : "Movement"
      },
      "messages" : {
        "getSpeedInput" : { (1)
          "$ref" : "#/components/messages/getSpeedInput" (1)
        },
        "getSpeedOutput" : { (2)
          "$ref" : "#/components/messages/getSpeedOutput" (2)
        }
      }
    }
  },
  "operations" : {
    "getSpeedInput" : {
      "action" : "receive", (5)
      "channel" : {
        "$ref" : "#/channels/Movement"
      },
      "messages" : [ {
        "$ref" : "#/channels/Movement/messages/getSpeedInput" (1)
      } ]
    },
    "getSpeedOutput" : { (2)
      "action" : "send", (5)
      "channel" : {
        "$ref" : "#/channels/Movement"
      },
      "messages" : [ {
        "$ref" : "#/channels/Movement/messages/getSpeedOutput" (2)
      } ]
    }
  },
  "components" : {
    "messages" : {
      "getSpeedInput" : { (1) (4)
        "name" : "getSpeedInput", (1)
        "title" : "getSpeed input",
        "summary" : "The input to the getSpeed operation",
        "content-type" : "application/json",
        "payload" : {
          "$ref" : "#/components/schemas/getSpeedInput" (1)
        }
      },
      "getSpeedOutput" : { (2) (4)
        "name" : "getSpeedOutput", (2)
        "title" : "getSpeed output",
        "summary" : "Return value of the getSpeed operation",
        "content-type" : "application/json",
        "payload" : {
          "$ref" : "#/components/schemas/getSpeedOutput" (2)
        }
      }
    },
    "schemas" : {
      "getSpeedInput" : { (1) (3)
        "type" : "string",
        "description" : "The input to the getSpeed operation"
      },
      "getSpeedOutput" : { (2) (3)
        "type" : "string",
        "description" : "Return value of the getSpeed operation"
      }
    }
  }
}
1 the names of the input
2 the names of the output
3 the characteristics are generated
4 the meta information of input/output
5 'send' (for output) action: map to a publish operation in AsyncAPI, 'receive' (for input) action: map to a subscribe operation

Mapping of Aspect’s events

This section describes the mapping between SAMM Events and the AsyncAPI specification. If the Aspect also has a non-empty list of events defined, like the one in the following example:

:Movement a samm:Aspect ;
   samm:preferredName "movement"@en ;
   samm:description "Aspect for movement information"@en ;
   samm:properties ( ) ;
   samm:operations ( ) ;
   samm:events ( :SpeedUpdateEvent ) .

:SpeedUpdateEvent a samm:Event ;
   samm:preferredName "Speed Update"@en ;
   samm:description "This is event for update speed property"@en ;
   samm:parameters ( :updatedSpeed :updateAcceleration ) .

:updatedSpeed a samm:Property ;
   samm:preferredName "updated speed"@en ;
   samm:description "the updated speed value"@en ;
   samm:characteristic samm-c:Text .

:updateAcceleration a samm:Property ;
   samm:preferredName "update acceleration"@en ;
   samm:description "the updated acceleration value"@en ;
   samm:characteristic samm-c:Text .

events will be generated in some places of AsyncAPI specification: operations section, channel messages section and schemas section:

{
"channels" : {
    "Movement" : {
      "address" : "movement/0.0.1/Movement",
      "description" : "This channel for updating Movement Aspect.",
      "parameters" : {
        "namespace" : "movement",
        "version" : "0.0.1",
        "aspect-name" : "Movement"
      },
      "massages" : {
        "SpeedUpdateEvent" : {
          "$ref" : "#/components/messages/SpeedUpdateEvent" (1)
        },
      }
    }
  },
  "operations" : {
    "SpeedUpdateEvent" : {
      "action" : "receive", (5)
      "channel" : {
        "$ref" : "#/channels/Movement"
      },
      "messages" : [ {
        "$ref" : "#/channels/Movement/messages/SpeedUpdateEvent" (1)
      } ]
    },
  },
  "components" : {
    "messages" : {
      "SpeedUpdateEvent" : { (1) (2)
        "name" : "SpeedUpdateEvent", (1)
        "title" : "Speed Update",
        "summary" : "This is event for update speed property",
        "content-type" : "application/json",
        "payload" : {
          "$ref" : "#/components/schemas/SpeedUpdateEvent" (1)
        }
      }
    },
    "schemas" : {
      "SpeedUpdateEvent" : { (1)
        "type" : "object",
        "properties" : {
          "updatedSpeed" : { (3) (4)
            "title" : "updated speed",
            "type" : "string",
            "description" : "the updated speed value"
          },
          "updateAcceleration" : { (3) (4)
            "title" : "updated acceleration",
            "type" : "string",
            "description" : "the updated acceleration value"
          }
        }
      }
    }
  }
}
1 the names of the event
2 the meta information of event
3 property of event
4 the characteristics are generated
5 for events available only 'receive' action: map to a subscribe operation

Understanding the models directory structure

An Aspect Model file can contain an Aspect definition as well as other model elements that are defined in the same versioned namespace, as described in the Namespaces section of the specification. Additionally, it is possible to split one versioned namespace across multiple files, for example to define a Characteristic that is usable in multiple Aspects into its own file. In order for SAMM CLI to be able to resolve references to such externally defined model elements, the model files must be organized in a directory structure as follows:

namespace/version/name.ttl

where namespace corresponds to the hierarchical namespace that is part of the model element’s URN, e.g. com.mycompany.myproduct and version corresponds to the version of the namespace. The resulting directory structure then looks like the following:

models root
└── com.mycompany.myproduct
    ├── 1.0.0
    │   ├── MyAspect.ttl
    │   ├── MyEntity.ttl
    │   └── myProperty.ttl
    └── 1.1.0
        └── MyAspect.ttl

The name of the directory shown as models root above can be chosen freely. The SAMM CLI will resolve the file path relative to the input file by following the folder structure described above. Each of the files in the 1.0.0 directory should therefore have an empty prefix declaration such as @prefix : <urn:samm:com.mycompany.myproduct:1.0.0#>.