diff --git a/documentation/developer-guide/antora.yml b/documentation/developer-guide/antora.yml index 716f1d1f7..c6c54538c 100644 --- a/documentation/developer-guide/antora.yml +++ b/documentation/developer-guide/antora.yml @@ -1,7 +1,7 @@ name: esmf-developer-guide -title: ESMF SDK Developer Guide +title: Java SDK and SAMM CLI version: 'master' start_page: ROOT:index.adoc nav: - modules/tooling-guide/nav.adoc - - modules/static-metaclasses/nav.adoc + - modules/static-metaclasses/nav.adoc \ No newline at end of file diff --git a/documentation/developer-guide/modules/ROOT/pages/index.adoc b/documentation/developer-guide/modules/ROOT/pages/index.adoc index 2e2003f1f..50c15de85 100644 --- a/documentation/developer-guide/modules/ROOT/pages/index.adoc +++ b/documentation/developer-guide/modules/ROOT/pages/index.adoc @@ -1,6 +1,6 @@ -= ESMF SDK Developer Guide += Java SDK -The ESMF SDK Developer Guide helps you to get up-and-running with the ESMF SDK developed within the +The Java SDK Developer Guide helps you to get up-and-running with the ESMF SDK developed within the Eclipse Semantic Modeling Framework (ESMF). It covers all possible scenarios, no matter whether you are planning to build a solution with the SDK, model your Aspect data, implement your own customized -Aspect or want to integrate existing assets and systems. +Aspect or want to integrate existing assets and systems. \ No newline at end of file diff --git a/documentation/developer-guide/modules/tooling-guide/nav.adoc b/documentation/developer-guide/modules/tooling-guide/nav.adoc index 5f5de4fb2..97cbea0e6 100644 --- a/documentation/developer-guide/modules/tooling-guide/nav.adoc +++ b/documentation/developer-guide/modules/tooling-guide/nav.adoc @@ -1,6 +1,12 @@ * xref:samm-cli.adoc[SAMM CLI] -* xref:java-aspect-tooling.adoc[Java APIs for Aspect Models] * xref:maven-plugin.adoc[Maven Plugin] +* Java APIs for Aspect Models +** xref:java-aspect-tooling.adoc[Getting Started and Loading] +** xref:java-model-creation.adoc[Creating and Modifying Models] +** xref:java-validation.adoc[Validation] +** xref:java-code-generation.adoc[Code Generation] +** xref:java-documentation-generation.adoc[Documentation Generation] +* xref:java-aas-mapping.adoc[AAS Integration] * xref:error-codes.adoc[Error Codes and Validation Results] * xref:best-practices.adoc[Best Practices] -* xref:bamm-migration.adoc[Migration from BAMM] +* xref:bamm-migration.adoc[Migration from BAMM] \ No newline at end of file diff --git a/documentation/developer-guide/modules/tooling-guide/pages/java-aas-mapping.adoc b/documentation/developer-guide/modules/tooling-guide/pages/java-aas-mapping.adoc new file mode 100644 index 000000000..ddd8f4c5c --- /dev/null +++ b/documentation/developer-guide/modules/tooling-guide/pages/java-aas-mapping.adoc @@ -0,0 +1,137 @@ +:page-partial: + +[[mapping-aas]] += Mapping Aspect Models to Asset Administration Shell (AAS) Submodel Templates + +The Asset Administration Shell (AAS) and its +https://www.plattform-i40.de/IP/Redaktion/EN/Standardartikel/specification-administrationshell.html[information +model] is a widely recognized standard developed by the https://industrialdigitaltwin.org[Industrial +Digital Twin Association (IDTA)] to express and handle Digital Twins. Central element of the AAS is +the concept of Submodels, which describe certain aspects of a Digital Twin. + +The SAMM Aspect Meta Model allows to specify aspects of a digital twin and its semantics. The AAS +Generator module provides mapping implementations to derive AAS Submodels from SAMM Aspect Models. +On the one hand, this allows to integrate SAMM models in AAS environments and on the other hand it +allows AAS submodels to be described with rich semantics, as it is possible with SAMM. + +[[details-mapping-aas]] +== Details of the Mapping Concept + +In the following section, the mapping rules applied by the generator are explained. The rules apply +to xref:2.0.0@samm-specification:ROOT:index.adoc[SAMM v2.0.0] and +https://industrialdigitaltwin.io/aas-specifications/IDTA-01001/v3.0/index.html[AAS Specification Part 1 V3.0]. + +[cols="1,1,2"] +|=== +| SAMM | AAS | Comment + +| **samm:Aspect** | aas:Submodel with kind=Template | Empty Asset and AssetAdministrationShell entries are added to the output file + +| samm:name | aas:Submodel.idShort | + +| samm:preferredName | aas:Submodel.displayName | + +| samm:description | aas:Submodel.description | + +| samm:property | see **samm:Property** | + +| samm:operation | see **samm:Operation** | + +| samm:Aspect.urn | aas:Submodel.semanticId | + +| **samm:Property** | aas:Property, aas:SubmodelElementCollection | The AAS type is derived from the type of the SAMM Characteristic specifying the SAMM property. Depending on the type it is decided what the resulting AAS element will be. In case of an Entity it will result in a SubmodelElementCollection. It will also be a SubmodelElementCollection if the SAMM Characteristic is of a Collection type (see the https://eclipse-esmf.github.io/samm-specification/2.0.0/characteristics.html[Characteristics taxonomy]). In all other cases an aas:Property will be generated + +| samm:Property.name | aas:Property.idShort | + +| samm:Property.urn | aas:ConceptDescription.identification.id, aas:Property.semanticId| + +| samm:Property.preferredName | aas:Property.displayName | + +| samm:Property.description | aas:Property.description | Note: Also mapped to aas:DataSpecificationIEC61360.definition of the aas:ConceptDescription of this property + +| samm:Property.exampleValue |aas:Property.value | + +| samm:Characteristic.dataType | aas:Property.valueType | + +| **samm:Operation** | Operation | in/out parameters are not used in SAMM so the mapping only generates input variables and output variables in AAS + +| xref:samm-specification:ROOT:characteristics.adoc#characteristic-characteristic[**samm-c:Characteristic**] | aas:SubmodelElement, aas:ConceptDescription | Characteristics in SAMM define the semantics of a property, which includes there types as well as links to further definitions (standards, dictionaries, etc), a natural language description and name in different languages. Type and description are separated in AAS, which is why there is not a one-to-one mapping of a Characteristic to one element in AAS but rather Characteristics are used in the mapping of Properties, first, to guide the generation process and, second, to capture semantics in ConceptDescriptions of properties with data specification "DataSpecificationIEC61360" of the AAS. + +| xref:samm-specification:ROOT:characteristics.adoc#collection-characteristic[**samm-c:Collection**] | aas:SubmodelElementList, aas:ConceptDescription | The general remarks to Characteristics apply also to Collection type Characteristics. However, properties referencing Collections are mapped to SubmodelElementLists. Specific properties of collections are mapped. samm:Set is unique, samm:SortedSet is unique and sorted, samm:List is sorted. + +| xref:samm-specification:ROOT:characteristics.adoc#quantifiable-characteristic[**samm-c:Quantifiable**] | aas:SubmodelElement, aas:ConceptDescription | The general remarks to Characteristics apply also to Quantifiable type Characteristics. Quantifiables (also Duration and Measurement) reference a unit, which is added to the ConceptDescription corresponding the mapped Characteristic. + +| xref:samm-specification:ROOT:characteristics.adoc#either-characteristic[**samm-c:Either**] | aas:SubmodelElement, aas:ConceptDescription | The general remarks to Characteristics apply also to Either. However, the Either characteristic has two distinct entries of which one is to be selected. This concept is not present in AAS. Thus, both entries will be written to a Submodel template, where one has to be ignored. + +| xref:samm-specification:ROOT:characteristics.adoc#trait-characteristic[**samm-c:Trait**] | aas:SubmodelElement, aas:ConceptDescription | The general remarks to Characteristics apply also to Trait. However, the constraint of a trait will be ignored and only the base type will be evaluated, which will act as the characteristic of a property. + +| xref:samm-specification:ROOT:characteristics.adoc#code-characteristic[**samm-c:Code**] | aas:SubmodelElement, aas:ConceptDescription | Similar to plain Characteristic. + +| xref:samm-specification:ROOT:characteristics.adoc#structured-value-characteristic[**samm-c:StructuredValue**] | aas:SubmodelElement, aas:ConceptDescription | The general remarks to Characteristics apply also to StructuredValue. However, AAS has no concpet like deconstruction rule. Thus, the deconstruction rule and the sub properties of the deconstruction entity will be ignored and only the Characteristic is mapped. + +| xref:samm-specification:ROOT:characteristics.adoc#enumeration-characteristic[**samm-c:Enumeration**] | aas:SubmodelElement, aas:ConceptDescription | The general remarks to Characteristics apply also to Enumerations. Additionally, the values of an Enumeration are mapped to a valueList of a DataSpecificationIEC61360. + +| xref:samm-specification:ROOT:characteristics.adoc#state-characteristic[**samm-c:State**] | aas:SubmodelElement, aas:ConceptDescription | Same as Enumeration. + +| xref:samm-specification:ROOT:characteristics.adoc#MultiLanguageText[samm-c:MultiLanguageText] | aas:MultiLanguageProperty | if a MultiLanguageText is used in SAMM it is mapped to the MultiLanguageProperty in AAS. +|=== + +== Known Limitations +The AAS Generator implements a base set of features, which are mapped from SAMM to AAS. +However, there are still limitations: + +* Predefined entity mapping (FileResource would be mapped to aas:File) +* samm-c:Either is mapped to aas:SubmodelElementCollection with two entries for left and right side +* Recursive optional properties of SAMM model are not included in output but dropped straight away + +== Translate Aspect Model to AAS + +The following code demonstrates how the API to translate an Aspect Model into one of the valid AAS +formats (JSON, XML, AASX) is used: + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateAas.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateAas.java[tags=generate] +---- + +To include the translator artifact, use the following dependencies: + +include::esmf-developer-guide:ROOT:partial$esmf-aspect-model-aas-generator-artifact.adoc[] + +[[translate-aas-to-aspect-model]] +== Translate AAS to Aspect Model + +It is also possible to translate AAS Submodel Templates to Aspect Models using a best-effort. The +following example shows how the API to translate an AAS environment containing one or more Submodel +Templates to Aspect Models: + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateAspectFromAas.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateAspectFromAas.java[tags=generate] +---- + +To include the translator artifact, use the same same dependencies as shown above in section <>. \ No newline at end of file diff --git a/documentation/developer-guide/modules/tooling-guide/pages/java-aspect-tooling.adoc b/documentation/developer-guide/modules/tooling-guide/pages/java-aspect-tooling.adoc index 67e207878..b26763c0c 100644 --- a/documentation/developer-guide/modules/tooling-guide/pages/java-aspect-tooling.adoc +++ b/documentation/developer-guide/modules/tooling-guide/pages/java-aspect-tooling.adoc @@ -1,7 +1,7 @@ :page-partial: [[aspect-model-java-tooling]] -= Java Tooling for Working with Aspect Models += Getting Started with Java APIs for Aspect Models [[general-considerations]] == General Considerations @@ -232,638 +232,6 @@ therefore contains all transitively referenced model element definitions. Altern the `sourceModel()` of each Aspect Model file given by `files()`, which will return only the RDF graph of this file. -[[serializing-an-aspect-model]] -=== 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 -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$SerializeAspectModel.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$SerializeAspectModel.java[tags=serialize] ----- - -Alternatively, you can also serialize a complete `AspectModelFile`: - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$SerializeAspectModel.java[tags=serializeFile] ----- - -To include the serializer, use the following dependency: - -include::esmf-developer-guide:ROOT:partial$esmf-aspect-meta-model-java-artifact.adoc[] - -[[creating-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`. - -[source,java,indent=0] ----- -include::example$SammBuilderDemo.java[tags=imports] ----- - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$SammBuilderDemo.java[tags=sammBuilder] ----- - -[TIP] -===== - -When you use https://assertj.github.io/doc/[AssertJ] for testing, you can add a dependency to the -tests jar provided by the `esmf-aspect-meta-model-java` module: - -include::esmf-developer-guide:ROOT:partial$esmf-aspect-meta-model-java-tests.adoc[] - -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: - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$AssertJ.java[tags=assertj] ----- -===== - -Overloaded `assertThat()` methods are provided for all Aspect Model Elements, e.g., `Aspect`, -`Property`, `Characteristic`, `Trait`, etc., as well as for `AspectModel` and `AspectModel`. - -[[validating-aspect-models]] -== Validating Aspect Models - -Aspect Models are validated using the `AspectModelValidator`. Validation returns a list of -`Violation`​s. A violation has a human-readable message and a unique error code and provides access -to the `EvaluationContext` which contains references to the model element that caused the -violation and the SHACL shape that triggered the violation. - -Each possible type of violation is a subtype of the `Violation` interface and provides additional -context information specific to this type, for example, the `MinLengthViolation` provides `int min` -(the allowed length) and `int actual` (the length that was encountered in the model). - -Consider the following example: - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$ValidateAspectModel.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$ValidateAspectModel.java[tags=validate] ----- - -<1> To format the validation result into an human-readable form, use the `ViolationFormatter` or the -`DetailedViolationFormatter`. Note that those are only intended for text-based interfaces such as -CLIs. -<2> Every application dealing with validation results that needs to transform the results into some -different structure can implement the `Violation.Visitor` Interface with a suitable target -type `(String` used as an example here) and use the visitor to handle the different types of -Violations in a type-safe way. - -The `AspectModelValidator` also provides the `loadModel(Supplier)` method that can be used in -conjunction with `() -> new AspectModeLoader().load(...)` to have exceptions that might be created during the -Aspect Model loading process, for example due to model resolution failures or syntax errors in the input -files, be turned into a `List` that can be passed to the aforementioned violation formatters. This -allows for custom structured handling of problems that occur during model loading. - -To include the model validator, use the following dependencies: - -include::esmf-developer-guide:ROOT:partial$esmf-aspect-model-validator-artifact.adoc[] - -=== Custom Error Formatting - -In order to access validation violations in a type-safe way, implement the interface -`org.eclipse.esmf.aspectmodel.shacl.violation.Violation.Visitor`. This allows you to handle each -violation type specifically and format error messages according to your application's requirements. - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$CustomViolationFormatter.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$CustomViolationFormatter.java[tags=custom-formatter] ----- - -=== Programmatic Access - -When using the Java API, errors are available through the `Violation` interface: - -[source,java] -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$ValidateAspectModel.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$ValidateAspectModel.java[tags=violations] ----- - - -=== Error Aggregation - -For applications that need to process multiple violations efficiently, you can group errors by type -for batch processing: - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$CustomViolationFormatter.java[tags=error-aggregation] ----- - - -[[generating-documentation]] -== Generating Documentation for Aspect Models - -Different types of artifacts can be generated from an Aspect model. All corresponding generators are included in the -following dependency: - -include::esmf-developer-guide:ROOT:partial$esmf-aspect-model-document-generators-artifact.adoc[] - -The documentation generation APIs provide methods that take as an argument a `Function`. -This is a mapping function that takes a file name as an input (which is determined by the respective generator) and -returns a corresponding `OutputStream`, for example (but not necessarily) a `FileOutputStream`. By providing this -function when calling the generator method, you can control where the output is written to, even when the generator -creates multiple files. For the code examples in the following subsections, we assume that the following method is -defined for calling the generators: - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$AbstractGenerator.java[tags=outputStream] ----- - -[[generating-diagrams]] -=== Generating SVG or PNG Diagrams - -Using the `AspectModelDiagramGenerator`, automatically layouted diagrams can be created for Aspect models in -the formats PNG and SVG. - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateDiagrams.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateDiagrams.java[tags=generate] ----- - -<1> The diagram generator is initialized with the loaded model and the -generation configuration. -<2> The generation takes the output stream for the output file name as input and -writes the generated diagram to the output stream. - -[[generating-html-documentation]] -=== Generating HTML Documentation - -A HTML reference documentation for an Aspect model can be generated as shown in the following code sample. The -documentation contains an overview diagram and describes the model elements as specified in the Aspect model. Preferred -names and descriptions in the respective language from the Aspect model are shown in the resulting document as part of -each model element. - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateHtml.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateHtml.java[tags=generate] ----- - -<1> HTML generation can be controlled via options. -<2> The HTML generator is initialized with the context consisting of the loaded RDF model and the -selected Aspect. - -[[generating-sample-json-payload]] -=== Generating Sample JSON Payload - -The sample JSON payload generator is used to create a valid JSON payload for an Aspect model as it could be returned by -an Aspect that implements that Aspect model. This follows the -xref:samm-specification:ROOT:payloads.adoc#mapping-to-json[mapping rules] as defined in the Meta Model specification. -The generator uses `samm:exampleValue`​s of Properties if present, otherwise random values corresponding to the -respective data types are generated. - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateJsonPayload.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateJsonPayload.java[tags=generate] ----- - -=== Generating JSON Schema - -The JSON schema generator creates a https://json-schema.org/[JSON Schema] that describes the payload for an Aspect model -as it could be returned by an Aspect that implements that Aspect model. - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateJsonSchema.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateJsonSchema.java[tags=generate] ----- - -=== Generating OpenAPI Specification - -The OpenAPI specification generator creates either a https://json-schema.org/[JSON Schema] or a https://yaml.org/[Yaml Spec] -that specifies an Aspect regarding to the https://github.com/OAI/OpenAPI-Specification/[OpenApi specification]. -The currently used versions corresponds https://json-schema.org/specification-links.html#draft-4[Draft 4] of the JSON Schema specification, -and https://github.com/OAI/OpenAPI-Specification/blob/3.0.1/versions/3.0.1.md[3.0.1]. - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateOpenApi.java[tags=imports] ----- -++++ -
-++++ - -.Generate OpenAPI YAML -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateOpenApi.java[tags=generateYaml] ----- - -.Generate OpenAPI JSON -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateOpenApi.java[tags=generateJson] ----- - -NOTE: For Enumerations with complex data types, the values are modelled as instances of the Entity defined as the -Enumeration's data type (see xref:samm-specification:ROOT:modeling-guidelines.adoc#declaring-enumerations[Declaring -Enumerations] for more information). In case the Entity instances contain Properties with a sorted collection as their -data type, the order of the values of said collection in the Entity instances is not preserved in the generated OpenAPI -specification. Preserving this order in OpenAPI is not possible at this point. - -=== Generating AsyncAPI Specification - -The AsyncAPI specification generator creates either a https://json-schema.org/[JSON Schema] or a https://yaml.org/[Yaml Spec] -that specifies an Aspect regarding to the https://www.asyncapi.com/en[AsyncApi specification]. -The currently used versions correspond to https://json-schema.org/specification-links.html#draft-4[Draft 4] of the JSON Schema specification, -and https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md[3.0.0] of the AsyncAPI specification. - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateAsyncApi.java[tags=imports] ----- -++++ -
-++++ - -.Generate AsyncAPI YAML -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateAsyncApi.java[tags=generateYaml] ----- - -.Generate AsyncAPI JSON -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateAsyncApi.java[tags=generateJson] ----- - -[[generating-sql]] -=== Generating SQL for Aspect Models - -Using the Aspect Model SQL generator, an SQL script can be generated that sets up a table for data -corresponding to the Aspect. The current implementation provides support for the -https://docs.databricks.com/en/sql/language-manual/index.html[Databricks SQL] dialect and a mapping -strategy that uses a denormalized table, i.e., the table contains one column for each Property used -in the Aspect Model (or any of its transitively referenced Entities). - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateSql.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateSql.java[tags=generate] ----- - -[[databricks-type-mapping]] -==== Databricks Type Mapping - -xref:samm-specification:ROOT:datatypes.adoc#data-types[Data types] in the Aspect Model are mapped to Databricks types using the following correspondences: - -[width="100%", options="header", cols="33,33,33"] -|=== -| Aspect model type | Databricks SQL type | Note -| `xsd:string` | `STRING` | -| `xsd:boolean` | `BOOLEAN` | -| `xsd:decimal` | `DECIMAL` | While xsd:decimal is by definition unbounded, DECIMAL's default - precision is 10 digits and can be up to 38. if we assume values larger than that can appear -in the data, the Aspect Models using xsd:decimal should also use a xref:samm-specification:ROOT:characteristics.adoc#fixed-point-constraint[samm-c:FixedPointConstraint] accordingly. -| `xsd:integer` | `DECIMAL` | As opposed to xsd:int, xsd:integer has arbitrary precision, i.e. DECIMAL is needed. -| `xsd:double` | `DOUBLE` | -| `xsd:float` | `FLOAT` | -| `xsd:date` | `STRING` | `DATE` can not be used, because it does not retain timezone information. -| `xsd:time` | `STRING` | -| `xsd:dateTime` | `STRING` | -| `xsd:dateTimeStamp` | `TIMESTAMP` | -| `xsd:gYear` | `STRING` | -| `xsd:gMonth` | `STRING` | -| `xsd:gDay` | `STRING` | -| `xsd:gYearMonth` | `STRING` | -| `xsd:gMonthDay` | `STRING` | -| `xsd:duration` | `STRING` | -| `xsd:yearMonthDuration` | `STRING` | -| `xsd:dayTimeDuration` | `STRING` | -| `xsd:byte` | `TINYINT` | -| `xsd:short` | `SMALLINT` | -| `xsd:int` | `INT` | -| `xsd:long` | `BIGINT` | -| `xsd:unsignedByte` | `SMALLINT` | -| `xsd:unsignedShort` | `INT` | -| `xsd:unsignedInt` | `BIGINT` | -| `xsd:unsignedLong` | `DECIMAL` | -| `xsd:positiveInteger` | `DECIMAL` | -| `xsd:nonNegativeInteger` | `DECIMAL` | -| `xsd:negativeInteger` | `DECIMAL` | -| `xsd:nonPositiveInteger` | `DECIMAL` | -| `xsd:hexBinary` | `BINARY` | -| `xsd:base64Binary` | `BINARY` | -| `xsd:anyURI` | `STRING` | -| `samm:curie` | `STRING` | -|=== - -[[generating-java-code]] -== Generating Java Code for Aspect Models - -Java code can be generated from an Aspect model in two ways: - -. The generated code represents the Aspect payload. Aspects and Entities become Java classes; their Properties become -fields in the classes. Characteristics are not first-class elements, but are implicitly represented by the usage of -corresponding data types (e.g. using `java.util.Set` as the type for the `Set` Characteristic of a Property) or -`javax.validation` annotations. The generated classes can be used in a straightforward fashion, but they do not contain -information about the underlying Aspect model such as its version number. Parts of the Aspect model that have no -representation in its corresponding JSON payload are not part of those classes either, in particular descriptions and -preferred names. These classes are called POJOs (Plain Old Java Objects), as they do not contain logic but serve mainly as data containers. - -. The generated code represents the Aspect model itself: It is a type-safe variant of the model and includes every -information that is also present in the model such as Characteristics, descriptions including language tags and original -XSD data types. It is however not intended to store payload corresponding to an Aspect. Theses classes are called static -meta classes, because they are created at compile time (_static_) and talk about the structure of the information, not -the information itself (_meta_). - -Depending on the use case, you would either use one or both of the types simultaneously. - -To include the Java generator, use the following dependencies: - -include::esmf-developer-guide:ROOT:partial$esmf-aspect-model-java-generator-artifact.adoc[] - -[[type-mapping]] -=== Type Mapping - -In the Java code generated from an Aspect model, the scalar Aspect model -xref:samm-specification:ROOT:datatypes.adoc#data-types[data types] are mapped to native Java types. The following table -lists the correspondences. - -[width="100%", options="header", cols="50,50"] -|=== -| Aspect model type | Java native type -| `xsd:string` | `java.lang.String` -| `xsd:boolean` | `java.lang.Boolean` -| `xsd:decimal` | `java.math.BigDecimal` -| `xsd:integer` | `java.math.BigDecimal` -| `xsd:double` | `java.lang.Double` -| `xsd:float` | `java.lang.Float` -| `xsd:date` | `javax.xml.datatype.XMLGregorianCalendar` -| `xsd:time` | `javax.xml.datatype.XMLGregorianCalendar` -| `xsd:dateTime` | `javax.xml.datatype.XMLGregorianCalendar` -| `xsd:dateTimeStamp` | `javax.xml.datatype.XMLGregorianCalendar` -| `xsd:gYear` | `javax.xml.datatype.XMLGregorianCalendar` -| `xsd:gMonth` | `javax.xml.datatype.XMLGregorianCalendar` -| `xsd:gDay` | `javax.xml.datatype.XMLGregorianCalendar` -| `xsd:gYearMonth` | `javax.xml.datatype.XMLGregorianCalendar` -| `xsd:gMonthDay` | `javax.xml.datatype.XMLGregorianCalendar` -| `xsd:duration` | `javax.xml.datatype.Duration` -| `xsd:yearMonthDuration` | `javax.xml.datatype.Duration` -| `xsd:dayTimeDuration` | `javax.xml.datatype.Duration` -| `xsd:byte` | `java.lang.Byte` -| `xsd:short` | `java.lang.Short` -| `xsd:int` | `java.lang.Integer` -| `xsd:long` | `java.lang.Long` -| `xsd:unsignedByte` | `java.lang.Short` -| `xsd:unsignedShort` | `java.lang.Integer` -| `xsd:unsignedInt` | `java.lang.Long` -| `xsd:unsignedLong` | `java.math.BigInteger` -| `xsd:positiveInteger` | `java.math.BigInteger` -| `xsd:nonNegativeInteger` | `java.math.BigInteger` -| `xsd:negativeInteger` | `java.math.BigInteger` -| `xsd:nonPositiveInteger` | `java.math.BigInteger` -| `xsd:hexBinary` | `byte[]` -| `xsd:base64Binary` | `byte[]` -| `xsd:anyURI` | `java.net.URI` -| `samm:curie` | `org.eclipse.esmf.metamodel.datatypes.Curie` -|=== - -[[generating-pojos]] -=== Generating POJOs - -POJO generation is straightforward; there are two minor differences to the generation of documentation artifacts. -Firstly, when instantiating the generator, you pass a flag indicating whether -https://en.wikipedia.org/wiki/Jackson_(API)[Jackson] annotations should be generated in the class. Secondly, the name -mapping function passed to the generation method takes a `QualifiedName` instead of a String, so that you can decide how -to handle the package structure of the class. - -By default, POJO classes are generated without setters. If setters are desired, use `enableSetters( true )` on the -generator config. Three setter styles are supported: - -[width="100%", options="header", cols="33,67"] -|=== -| Setter style | Example output -| `STANDARD` (the default, if not explicitly set) | `void setTheProperty( final String theProperty )` -| `FLUENT` | `TheClass setTheProperty( final String theProperty )` -| `FLUENT_COMPACT` | `TheClass theProperty( final String theProperty )` -|=== - -The `FLUENT_*` styles allow for method chaining, so that POJO instances can be written in a more compact way. - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateJavaPojo.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateJavaPojo.java[tags=generate] ----- - -[[generating-static-meta-classes]] -=== Generating Static Meta Classes - -For the generation of static meta classes, consider the following example: - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateJavaStaticClass.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateJavaStaticClass.java[tags=generate] ----- - -To use the generated static meta classes, you need the following additional dependency: - -include::esmf-developer-guide:ROOT:partial$esmf-aspect-static-meta-model-java-artifact.adoc[] - -[[providing-custom-macros-for-code-generation]] -==== Providing Custom Macros for Code Generation - -It is possible to change predefined sections of the generated classes by providing custom https://velocity.apache.org/[Velocity] templates; see the https://velocity.apache.org/engine/2.3/user-guide.html[Velocity User Guide] for more information. -The custom macros must be defined in a single template file. -The path to the template file as well as its name may be passed as arguments to the code generation, e.g. using the xref:samm-cli.adoc#samm-cli[SAMM-CLI]. - -Custom macros may be provided for the following sections: - -[width="100%",options="header"] -|=== -| Section | Macro Name | Default Macro Provided -| Copyright Licence Header | fileHeader | {nok} -|=== - -NOTE: When using custom macros, macros for all sections above must be provided. - -Example: - -[source,indent=0] ----- -include::example$sample-file-header.vm[] ----- - -[[modifying-and-creating-aspect-models]] -== Modifying and creating 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 -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$EditAspectModel.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$EditAspectModel.java[tags=editModel] ----- - [[accessing-samm-programmatically]] == Accessing the SAMM programmatically @@ -921,139 +289,12 @@ include::example$LoadMetaModelRdf.java[tags=imports] include::example$LoadMetaModelRdf.java[tags=loadMetaModelRdf] ---- -[[mapping-aas]] -== Mapping Aspect Models to Asset Administration Shell (AAS) Submodel Templates - -The Asset Administration Shell (AAS) and its -https://www.plattform-i40.de/IP/Redaktion/EN/Standardartikel/specification-administrationshell.html[information -model] is a widely recognized standard developed by the https://industrialdigitaltwin.org[Industrial -Digital Twin Association (IDTA)] to express and handle Digital Twins. Central element of the AAS is -the concept of Submodels, which describe certain aspects of a Digital Twin. - -The SAMM Aspect Meta Model allows to specify aspects of a digital twin and its semantics. The AAS -Generator module provides mapping implementations to derive AAS Submodels from SAMM Aspect Models. -On the one hand, this allows to integrate SAMM models in AAS environments and on the other hand it -allows AAS submodels to be described with rich semantics, as it is possible with SAMM. - -[[details-mapping-aas]] -=== Details of the Mapping Concept - -In the following section, the mapping rules applied by the generator are explained. The rules apply -to https://eclipse-esmf.github.io/samm-specification/2.0.0/index.html[SAMM v2.0.0] and -https://www.plattform-i40.de/IP/Redaktion/EN/Downloads/Publikation/Details_of_the_Asset_Administration_Shell_Part1_V3.html[AAS -Specification Part 1 V3.0RC01]. - -[cols="1,1,2"] -|=== -| SAMM | AAS | Comment - -| **samm:Aspect** | aas:Submodel with kind=Template | Empty Asset and AssetAdministrationShell entries are added to the output file - -| samm:name | aas:Submodel.idShort | - -| samm:preferredName | aas:Submodel.displayName | - -| samm:description | aas:Submodel.description | - -| samm:property | see **samm:Property** | - -| samm:operation | see **samm:Operation** | - -| samm:Aspect.urn | aas:Submodel.semanticId | - -| **samm:Property** | aas:Property, aas:SubmodelElementCollection | The AAS type is derived from the type of the SAMM Characteristic specifying the SAMM property. Depending on the type it is decided what the resulting AAS element will be. In case of an Entity it will result in a SubmodelElementCollection. It will also be a SubmodelElementCollection if the SAMM Characteristic is of a Collection type (see the https://eclipse-esmf.github.io/samm-specification/2.0.0/characteristics.html[Characteristics taxonomy]). In all other cases an aas:Property will be generated - -| samm:Property.name | aas:Property.idShort | - -| samm:Property.urn | aas:ConceptDescription.identification.id, aas:Property.semanticId| - -| samm:Property.preferredName | aas:Property.displayName | - -| samm:Property.description | aas:Property.description | Note: Also mapped to aas:DataSpecificationIEC61360.definition of the aas:ConceptDescription of this property - -| samm:Property.exampleValue |aas:Property.value | +== Next Steps -| samm:Characteristic.dataType | aas:Property.valueType | - -| **samm:Operation** | Operation | in/out parameters are not used in SAMM so the mapping only generates input variables and output variables in AAS - -| xref:samm-specification:ROOT:characteristics.adoc#characteristic-characteristic[**samm-c:Characteristic**] | aas:SubmodelElement, aas:ConceptDescription | Characteristics in SAMM define the semantics of a property, which includes there types as well as links to further definitions (standards, dictionaries, etc), a natural language description and name in different languages. Type and description are separated in AAS, which is why there is not a one-to-one mapping of a Characteristic to one element in AAS but rather Characteristics are used in the mapping of Properties, first, to guide the generation process and, second, to capture semantics in ConceptDescriptions of properties with data specification "DataSpecificationIEC61360" of the AAS. - -| xref:samm-specification:ROOT:characteristics.adoc#collection-characteristic[**samm-c:Collection**] | aas:SubmodelElementList, aas:ConceptDescription | The general remarks to Characteristics apply also to Collection type Characteristics. However, properties referencing Collections are mapped to SubmodelElementLists. Specific properties of collections are mapped. samm:Set is unique, samm:SortedSet is unique and sorted, samm:List is sorted. - -| xref:samm-specification:ROOT:characteristics.adoc#quantifiable-characteristic[**samm-c:Quantifiable**] | aas:SubmodelElement, aas:ConceptDescription | The general remarks to Characteristics apply also to Quantifiable type Characteristics. Quantifiables (also Duration and Measurement) reference a unit, which is added to the ConceptDescription corresponding the mapped Characteristic. - -| xref:samm-specification:ROOT:characteristics.adoc#either-characteristic[**samm-c:Either**] | aas:SubmodelElement, aas:ConceptDescription | The general remarks to Characteristics apply also to Either. However, the Either characteristic has two distinct entries of which one is to be selected. This concept is not present in AAS. Thus, both entries will be written to a Submodel template, where one has to be ignored. - -| xref:samm-specification:ROOT:characteristics.adoc#trait-characteristic[**samm-c:Trait**] | aas:SubmodelElement, aas:ConceptDescription | The general remarks to Characteristics apply also to Trait. However, the constraint of a trait will be ignored and only the base type will be evaluated, which will act as the characteristic of a property. - -| xref:samm-specification:ROOT:characteristics.adoc#code-characteristic[**samm-c:Code**] | aas:SubmodelElement, aas:ConceptDescription | Similar to plain Characteristic. - -| xref:samm-specification:ROOT:characteristics.adoc#structured-value-characteristic[**samm-c:StructuredValue**] | aas:SubmodelElement, aas:ConceptDescription | The general remarks to Characteristics apply also to StructuredValue. However, AAS has no concpet like deconstruction rule. Thus, the deconstruction rule and the sub properties of the deconstruction entity will be ignored and only the Characteristic is mapped. - -| xref:samm-specification:ROOT:characteristics.adoc#enumeration-characteristic[**samm-c:Enumeration**] | aas:SubmodelElement, aas:ConceptDescription | The general remarks to Characteristics apply also to Enumerations. Additionally, the values of an Enumeration are mapped to a valueList of a DataSpecificationIEC61360. - -| xref:samm-specification:ROOT:characteristics.adoc#state-characteristic[**samm-c:State**] | aas:SubmodelElement, aas:ConceptDescription | Same as Enumeration. - -| xref:samm-specification:ROOT:characteristics.adoc#MultiLanguageText[samm-c:MultiLanguageText] | aas:MultiLanguageProperty | if a MultiLanguageText is used in SAMM it is mapped to the MultiLanguageProperty in AAS. -|=== - -=== Known Limitations -The AAS Generator implements a base set of features, which are mapped from SAMM to AAS. -However, there are still limitations: - -* Predefined entity mapping (FileResource would be mapped to aas:File) -* samm-c:Either is mapped to aas:SubmodelElementCollection with two entries for left and right side -* Recursive optional properties of SAMM model are not included in output but dropped straight away - -=== Translate Aspect Model to AAS - -The following code demonstrates how the API to translate an Aspect Model into one of the valid AAS -formats (JSON, XML, AASX) is used: - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateAas.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateAas.java[tags=generate] ----- - -To include the translator artifact, use the following dependencies: - -include::esmf-developer-guide:ROOT:partial$esmf-aspect-model-aas-generator-artifact.adoc[] - -[[translate-aas-to-aspect-model]] -=== Translate AAS to Aspect Model - -It is also possible to translate AAS Submodel Templates to Aspect Models using a best-effort. The -following example shows how the API to translate an AAS environment containing one or more Submodel -Templates to Aspect Models: - -++++ -
-Show used imports -++++ -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateAspectFromAas.java[tags=imports] ----- -++++ -
-++++ - -[source,java,indent=0,subs="+macros,+quotes"] ----- -include::example$GenerateAspectFromAas.java[tags=generate] ----- +For more advanced topics, see the dedicated pages: -To include the translator artifact, use the same same dependencies as shown above in section <>. +* xref:java-model-creation.adoc[Creating and Modifying Models] - Learn how to programmatically create and modify Aspect Models +* xref:java-validation.adoc[Validation] - Validate your Aspect Models and handle validation results +* xref:java-code-generation.adoc[Code Generation] - Generate Java POJOs, static classes, and SQL from your models +* xref:java-documentation-generation.adoc[Documentation Generation] - Create diagrams, HTML docs, JSON schemas, and API specifications +* xref:java-aas-mapping.adoc[AAS Integration] - Map between SAMM Aspect Models and Asset Administration Shell submodels diff --git a/documentation/developer-guide/modules/tooling-guide/pages/java-code-generation.adoc b/documentation/developer-guide/modules/tooling-guide/pages/java-code-generation.adoc new file mode 100644 index 000000000..7a9dc9805 --- /dev/null +++ b/documentation/developer-guide/modules/tooling-guide/pages/java-code-generation.adoc @@ -0,0 +1,233 @@ +:page-partial: + +[[generating-java-code]] += Generating Java Code for Aspect Models + +Java code can be generated from an Aspect model in two ways: + +. The generated code represents the Aspect payload. Aspects and Entities become Java classes; their Properties become +fields in the classes. Characteristics are not first-class elements, but are implicitly represented by the usage of +corresponding data types (e.g. using `java.util.Set` as the type for the `Set` Characteristic of a Property) or +`javax.validation` annotations. The generated classes can be used in a straightforward fashion, but they do not contain +information about the underlying Aspect model such as its version number. Parts of the Aspect model that have no +representation in its corresponding JSON payload are not part of those classes either, in particular descriptions and +preferred names. These classes are called POJOs (Plain Old Java Objects), as they do not contain logic but serve mainly as data containers. + +. The generated code represents the Aspect model itself: It is a type-safe variant of the model and includes every +information that is also present in the model such as Characteristics, descriptions including language tags and original +XSD data types. It is however not intended to store payload corresponding to an Aspect. Theses classes are called static +meta classes, because they are created at compile time (_static_) and talk about the structure of the information, not +the information itself (_meta_). + +Depending on the use case, you would either use one or both of the types simultaneously. + +To include the Java generator, use the following dependencies: + +include::esmf-developer-guide:ROOT:partial$esmf-aspect-model-java-generator-artifact.adoc[] + +[[type-mapping]] +== Type Mapping + +In the Java code generated from an Aspect model, the scalar Aspect model +xref:samm-specification:ROOT:datatypes.adoc#data-types[data types] are mapped to native Java types. The following table +lists the correspondences. + +[width="100%", options="header", cols="50,50"] +|=== +| Aspect model type | Java native type +| `xsd:string` | `java.lang.String` +| `xsd:boolean` | `java.lang.Boolean` +| `xsd:decimal` | `java.math.BigDecimal` +| `xsd:integer` | `java.math.BigDecimal` +| `xsd:double` | `java.lang.Double` +| `xsd:float` | `java.lang.Float` +| `xsd:date` | `javax.xml.datatype.XMLGregorianCalendar` +| `xsd:time` | `javax.xml.datatype.XMLGregorianCalendar` +| `xsd:dateTime` | `javax.xml.datatype.XMLGregorianCalendar` +| `xsd:dateTimeStamp` | `javax.xml.datatype.XMLGregorianCalendar` +| `xsd:gYear` | `javax.xml.datatype.XMLGregorianCalendar` +| `xsd:gMonth` | `javax.xml.datatype.XMLGregorianCalendar` +| `xsd:gDay` | `javax.xml.datatype.XMLGregorianCalendar` +| `xsd:gYearMonth` | `javax.xml.datatype.XMLGregorianCalendar` +| `xsd:gMonthDay` | `javax.xml.datatype.XMLGregorianCalendar` +| `xsd:duration` | `javax.xml.datatype.Duration` +| `xsd:yearMonthDuration` | `javax.xml.datatype.Duration` +| `xsd:dayTimeDuration` | `javax.xml.datatype.Duration` +| `xsd:byte` | `java.lang.Byte` +| `xsd:short` | `java.lang.Short` +| `xsd:int` | `java.lang.Integer` +| `xsd:long` | `java.lang.Long` +| `xsd:unsignedByte` | `java.lang.Short` +| `xsd:unsignedShort` | `java.lang.Integer` +| `xsd:unsignedInt` | `java.lang.Long` +| `xsd:unsignedLong` | `java.math.BigInteger` +| `xsd:positiveInteger` | `java.math.BigInteger` +| `xsd:nonNegativeInteger` | `java.math.BigInteger` +| `xsd:negativeInteger` | `java.math.BigInteger` +| `xsd:nonPositiveInteger` | `java.math.BigInteger` +| `xsd:hexBinary` | `byte[]` +| `xsd:base64Binary` | `byte[]` +| `xsd:anyURI` | `java.net.URI` +| `samm:curie` | `org.eclipse.esmf.metamodel.datatypes.Curie` +|=== + +[[generating-pojos]] +== Generating POJOs + +POJO generation is straightforward; there are two minor differences to the generation of documentation artifacts. +Firstly, when instantiating the generator, you pass a flag indicating whether +https://en.wikipedia.org/wiki/Jackson_(API)[Jackson] annotations should be generated in the class. Secondly, the name +mapping function passed to the generation method takes a `QualifiedName` instead of a String, so that you can decide how +to handle the package structure of the class. + +By default, POJO classes are generated without setters. If setters are desired, use `enableSetters( true )` on the +generator config. Three setter styles are supported: + +[width="100%", options="header", cols="33,67"] +|=== +| Setter style | Example output +| `STANDARD` (the default, if not explicitly set) | `void setTheProperty( final String theProperty )` +| `FLUENT` | `TheClass setTheProperty( final String theProperty )` +| `FLUENT_COMPACT` | `TheClass theProperty( final String theProperty )` +|=== + +The `FLUENT_*` styles allow for method chaining, so that POJO instances can be written in a more compact way. + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateJavaPojo.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateJavaPojo.java[tags=generate] +---- + +[[generating-static-meta-classes]] +== Generating Static Meta Classes + +For the generation of static meta classes, consider the following example: + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateJavaStaticClass.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateJavaStaticClass.java[tags=generate] +---- + +To use the generated static meta classes, you need the following additional dependency: + +include::esmf-developer-guide:ROOT:partial$esmf-aspect-static-meta-model-java-artifact.adoc[] + +[[providing-custom-macros-for-code-generation]] +=== Providing Custom Macros for Code Generation + +It is possible to change predefined sections of the generated classes by providing custom https://velocity.apache.org/[Velocity] templates; see the https://velocity.apache.org/engine/2.3/user-guide.html[Velocity User Guide] for more information. +The custom macros must be defined in a single template file. +The path to the template file as well as its name may be passed as arguments to the code generation, e.g. using the xref:samm-cli.adoc#samm-cli[SAMM-CLI]. + +Custom macros may be provided for the following sections: + +[width="100%",options="header"] +|=== +| Section | Macro Name | Default Macro Provided +| Copyright Licence Header | fileHeader | {nok} +|=== + +NOTE: When using custom macros, macros for all sections above must be provided. + +Example: + +[source,indent=0] +---- +include::example$sample-file-header.vm[] +---- + +[[generating-sql]] +== Generating SQL for Aspect Models + +Using the Aspect Model SQL generator, an SQL script can be generated that sets up a table for data +corresponding to the Aspect. The current implementation provides support for the +https://docs.databricks.com/en/sql/language-manual/index.html[Databricks SQL] dialect and a mapping +strategy that uses a denormalized table, i.e., the table contains one column for each Property used +in the Aspect Model (or any of its transitively referenced Entities). + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateSql.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateSql.java[tags=generate] +---- + +[[databricks-type-mapping]] +=== Databricks Type Mapping + +xref:samm-specification:ROOT:datatypes.adoc#data-types[Data types] in the Aspect Model are mapped to Databricks types using the following correspondences: + +[width="100%", options="header", cols="33,33,33"] +|=== +| Aspect model type | Databricks SQL type | Note +| `xsd:string` | `STRING` | +| `xsd:boolean` | `BOOLEAN` | +| `xsd:decimal` | `DECIMAL` | While xsd:decimal is by definition unbounded, DECIMAL's default + precision is 10 digits and can be up to 38. if we assume values larger than that can appear +in the data, the Aspect Models using xsd:decimal should also use a xref:samm-specification:ROOT:characteristics.adoc#fixed-point-constraint[samm-c:FixedPointConstraint] accordingly. +| `xsd:integer` | `DECIMAL` | As opposed to xsd:int, xsd:integer has arbitrary precision, i.e. DECIMAL is needed. +| `xsd:double` | `DOUBLE` | +| `xsd:float` | `FLOAT` | +| `xsd:date` | `STRING` | `DATE` can not be used, because it does not retain timezone information. +| `xsd:time` | `STRING` | +| `xsd:dateTime` | `STRING` | +| `xsd:dateTimeStamp` | `TIMESTAMP` | +| `xsd:gYear` | `STRING` | +| `xsd:gMonth` | `STRING` | +| `xsd:gDay` | `STRING` | +| `xsd:gYearMonth` | `STRING` | +| `xsd:gMonthDay` | `STRING` | +| `xsd:duration` | `STRING` | +| `xsd:yearMonthDuration` | `STRING` | +| `xsd:dayTimeDuration` | `STRING` | +| `xsd:byte` | `TINYINT` | +| `xsd:short` | `SMALLINT` | +| `xsd:int` | `INT` | +| `xsd:long` | `BIGINT` | +| `xsd:unsignedByte` | `SMALLINT` | +| `xsd:unsignedShort` | `INT` | +| `xsd:unsignedInt` | `BIGINT` | +| `xsd:unsignedLong` | `DECIMAL` | +| `xsd:positiveInteger` | `DECIMAL` | +| `xsd:nonNegativeInteger` | `DECIMAL` | +| `xsd:negativeInteger` | `DECIMAL` | +| `xsd:nonPositiveInteger` | `DECIMAL` | +| `xsd:hexBinary` | `BINARY` | +| `xsd:base64Binary` | `BINARY` | +| `xsd:anyURI` | `STRING` | +| `samm:curie` | `STRING` | +|=== \ No newline at end of file diff --git a/documentation/developer-guide/modules/tooling-guide/pages/java-documentation-generation.adoc b/documentation/developer-guide/modules/tooling-guide/pages/java-documentation-generation.adoc new file mode 100644 index 000000000..7a304f7ad --- /dev/null +++ b/documentation/developer-guide/modules/tooling-guide/pages/java-documentation-generation.adoc @@ -0,0 +1,194 @@ +:page-partial: + +[[generating-documentation]] += Generating Documentation for Aspect Models + +Different types of artifacts can be generated from an Aspect model. All corresponding generators are included in the +following dependency: + +include::esmf-developer-guide:ROOT:partial$esmf-aspect-model-document-generators-artifact.adoc[] + +The documentation generation APIs provide methods that take as an argument a `Function`. +This is a mapping function that takes a file name as an input (which is determined by the respective generator) and +returns a corresponding `OutputStream`, for example (but not necessarily) a `FileOutputStream`. By providing this +function when calling the generator method, you can control where the output is written to, even when the generator +creates multiple files. For the code examples in the following subsections, we assume that the following method is +defined for calling the generators: + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$AbstractGenerator.java[tags=outputStream] +---- + +[[generating-diagrams]] +== Generating SVG or PNG Diagrams + +Using the `AspectModelDiagramGenerator`, automatically layouted diagrams can be created for Aspect models in +the formats PNG and SVG. + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateDiagrams.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateDiagrams.java[tags=generate] +---- + +<1> The diagram generator is initialized with the loaded model and the +generation configuration. +<2> The generation takes the output stream for the output file name as input and +writes the generated diagram to the output stream. + +[[generating-html-documentation]] +== Generating HTML Documentation + +A HTML reference documentation for an Aspect model can be generated as shown in the following code sample. The +documentation contains an overview diagram and describes the model elements as specified in the Aspect model. Preferred +names and descriptions in the respective language from the Aspect model are shown in the resulting document as part of +each model element. + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateHtml.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateHtml.java[tags=generate] +---- + +<1> HTML generation can be controlled via options. +<2> The HTML generator is initialized with the context consisting of the loaded RDF model and the +selected Aspect. + +[[generating-sample-json-payload]] +== Generating Sample JSON Payload + +The sample JSON payload generator is used to create a valid JSON payload for an Aspect model as it could be returned by +an Aspect that implements that Aspect model. This follows the +xref:samm-specification:ROOT:payloads.adoc#mapping-to-json[mapping rules] as defined in the Meta Model specification. +The generator uses `samm:exampleValue`s of Properties if present, otherwise random values corresponding to the +respective data types are generated. + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateJsonPayload.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateJsonPayload.java[tags=generate] +---- + +== Generating JSON Schema + +The JSON schema generator creates a https://json-schema.org/[JSON Schema] that describes the payload for an Aspect model +as it could be returned by an Aspect that implements that Aspect model. + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateJsonSchema.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateJsonSchema.java[tags=generate] +---- + +== Generating OpenAPI Specification + +The OpenAPI specification generator creates either a https://json-schema.org/[JSON Schema] or a https://yaml.org/[Yaml Spec] +that specifies an Aspect regarding to the https://github.com/OAI/OpenAPI-Specification/[OpenApi specification]. +The currently used versions corresponds https://json-schema.org/specification-links.html#draft-4[Draft 4] of the JSON Schema specification, +and https://github.com/OAI/OpenAPI-Specification/blob/3.0.1/versions/3.0.1.md[3.0.1]. + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateOpenApi.java[tags=imports] +---- +++++ +
+++++ + +.Generate OpenAPI YAML +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateOpenApi.java[tags=generateYaml] +---- + +.Generate OpenAPI JSON +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateOpenApi.java[tags=generateJson] +---- + +NOTE: For Enumerations with complex data types, the values are modelled as instances of the Entity defined as the +Enumeration's data type (see xref:samm-specification:ROOT:modeling-guidelines.adoc#declaring-enumerations[Declaring +Enumerations] for more information). In case the Entity instances contain Properties with a sorted collection as their +data type, the order of the values of said collection in the Entity instances is not preserved in the generated OpenAPI +specification. Preserving this order in OpenAPI is not possible at this point. + +== Generating AsyncAPI Specification + +The AsyncAPI specification generator creates either a https://json-schema.org/[JSON Schema] or a https://yaml.org/[Yaml Spec] +that specifies an Aspect regarding to the https://www.asyncapi.com/en[AsyncApi specification]. +The currently used versions correspond to https://json-schema.org/specification-links.html#draft-4[Draft 4] of the JSON Schema specification, +and https://github.com/asyncapi/spec/blob/master/spec/asyncapi.md[3.0.0] of the AsyncAPI specification. + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateAsyncApi.java[tags=imports] +---- +++++ +
+++++ + +.Generate AsyncAPI YAML +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateAsyncApi.java[tags=generateYaml] +---- + +.Generate AsyncAPI JSON +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$GenerateAsyncApi.java[tags=generateJson] +---- \ No newline at end of file diff --git a/documentation/developer-guide/modules/tooling-guide/pages/java-model-creation.adoc b/documentation/developer-guide/modules/tooling-guide/pages/java-model-creation.adoc new file mode 100644 index 000000000..a19397c80 --- /dev/null +++ b/documentation/developer-guide/modules/tooling-guide/pages/java-model-creation.adoc @@ -0,0 +1,105 @@ +:page-partial: + +[[creating-and-modifying-aspect-models]] += Creating and Modifying Aspect Models + +[[creating-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`. + +[source,java,indent=0] +---- +include::example$SammBuilderDemo.java[tags=imports] +---- + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$SammBuilderDemo.java[tags=sammBuilder] +---- + +[TIP] +===== + +When you use https://assertj.github.io/doc/[AssertJ] for testing, you can add a dependency to the +tests jar provided by the `esmf-aspect-meta-model-java` module: + +include::esmf-developer-guide:ROOT:partial$esmf-aspect-meta-model-java-tests.adoc[] + +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: + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$AssertJ.java[tags=assertj] +---- +===== + +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-and-creating-aspect-models]] +== 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 +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$EditAspectModel.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$EditAspectModel.java[tags=editModel] +---- + +[[serializing-an-aspect-model]] +== 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 +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$SerializeAspectModel.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$SerializeAspectModel.java[tags=serialize] +---- + +Alternatively, you can also serialize a complete `AspectModelFile`: + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$SerializeAspectModel.java[tags=serializeFile] +---- + +To include the serializer, use the following dependency: + +include::esmf-developer-guide:ROOT:partial$esmf-aspect-meta-model-java-artifact.adoc[] \ No newline at end of file diff --git a/documentation/developer-guide/modules/tooling-guide/pages/java-validation.adoc b/documentation/developer-guide/modules/tooling-guide/pages/java-validation.adoc new file mode 100644 index 000000000..e2c89ed02 --- /dev/null +++ b/documentation/developer-guide/modules/tooling-guide/pages/java-validation.adoc @@ -0,0 +1,106 @@ +:page-partial: + +[[validating-aspect-models]] += Validating Aspect Models + +Aspect Models are validated using the `AspectModelValidator`. Validation returns a list of +`Violation`s. A violation has a human-readable message and a unique error code and provides access +to the `EvaluationContext` which contains references to the model element that caused the +violation and the SHACL shape that triggered the violation. + +Each possible type of violation is a subtype of the `Violation` interface and provides additional +context information specific to this type, for example, the `MinLengthViolation` provides `int min` +(the allowed length) and `int actual` (the length that was encountered in the model). + +Consider the following example: + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$ValidateAspectModel.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$ValidateAspectModel.java[tags=validate] +---- + +<1> To format the validation result into an human-readable form, use the `ViolationFormatter` or the +`DetailedViolationFormatter`. Note that those are only intended for text-based interfaces such as +CLIs. +<2> Every application dealing with validation results that needs to transform the results into some +different structure can implement the `Violation.Visitor` Interface with a suitable target +type `(String` used as an example here) and use the visitor to handle the different types of +Violations in a type-safe way. + +The `AspectModelValidator` also provides the `loadModel(Supplier)` method that can be used in +conjunction with `() -> new AspectModeLoader().load(...)` to have exceptions that might be created during the +Aspect Model loading process, for example due to model resolution failures or syntax errors in the input +files, be turned into a `List` that can be passed to the aforementioned violation formatters. This +allows for custom structured handling of problems that occur during model loading. + +To include the model validator, use the following dependencies: + +include::esmf-developer-guide:ROOT:partial$esmf-aspect-model-validator-artifact.adoc[] + +== Custom Error Formatting + +In order to access validation violations in a type-safe way, implement the interface +`org.eclipse.esmf.aspectmodel.shacl.violation.Violation.Visitor`. This allows you to handle each +violation type specifically and format error messages according to your application's requirements. + +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$CustomViolationFormatter.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$CustomViolationFormatter.java[tags=custom-formatter] +---- + +== Programmatic Access + +When using the Java API, errors are available through the `Violation` interface: + +[source,java] +++++ +
+Show used imports +++++ +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$ValidateAspectModel.java[tags=imports] +---- +++++ +
+++++ + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$ValidateAspectModel.java[tags=violations] +---- + + +== Error Aggregation + +For applications that need to process multiple violations efficiently, you can group errors by type +for batch processing: + +[source,java,indent=0,subs="+macros,+quotes"] +---- +include::example$CustomViolationFormatter.java[tags=error-aggregation] +---- \ No newline at end of file diff --git a/documentation/developer-guide/modules/tooling-guide/pages/samm-cli.adoc b/documentation/developer-guide/modules/tooling-guide/pages/samm-cli.adoc index ab4e31662..667111a1c 100644 --- a/documentation/developer-guide/modules/tooling-guide/pages/samm-cli.adoc +++ b/documentation/developer-guide/modules/tooling-guide/pages/samm-cli.adoc @@ -845,7 +845,7 @@ In this section, a detailed description of the mapping between individual Aspect 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 +==== Naming and Versioning Please consider the following model fragment, with the attention focused on the numbered elements: