It is possible to generate an skeleton AsyncAPI Specification from an annotated UML model. For this, we provide an Industry 4.0 (I4.0) UML profile. In this page you'll find:
- How did we create this model?
- What does this profile look like?
- Do you provide any example?
- What can be generated out of an annotated UML model?
- How can I test and play with this functionality?
- Can I regenerate my AsyncAPI specification (and the generated code) after modifying the initial UML model?
- Where can I find the model transformations in the source code?
If you want to learn more about our AsyncAPI Toolkit, check out our main README file.
UML is a powerful language that allows us to represent everything from the architecture to the behavioral aspects of software systems. However, when its expressiveness is too broad for a given context, it can be tailored for specific purposes by profiling. A UML profile provides a set of stereotypes and tagged values that are added to UML models to extend their semantics. To build a UML profile, the application domain must be analyzed to identify its particularities. Following best practices, this analysis can be captured in a domain model. In our case, we have defined a publish-subscribe model in Industry 4.0 for, subsequently and following the good practices of Lagarde et al. and Selic, get a UML profile.
This is the domain model we have defined for the Industry 4.0 field:
As can be seen, in an Industry 4.0 architecture we find at least one message Broker in addition to the architecture components (I4.0 Component). A broker has a name, a URL (url), accepts a protocol, and may have a description. The architecture components define and execute Operatiosn. When a given operation publishes to a Topic (which has a name, can have a description, and can be parameterized---see parameters), or is executed as a consequence of a subscription to a topic, becomes a Publisher or a Subscriber operation. A publisher operation sends a type of Message, just like a subscriber operation. Messages have a name, and can have a description, and a certain content (Payload). Said content is an object with a certain value and that conforms to a certain type.
Starting from the previous model, and following the good practices indicated above, we have derived the UML profile below:
Thus, a UML model (Model metaclass) can be annotated as an Industry 4.0 architecture using the I4.0 Architecture stereotype. Using this stereotype, we can add metadata such as the name of the architecture (name), the version of the specification, or a description. Likewise, UML components (metaclass Component) can be annotated as I4.0 Component (to indicate that they are components of our Industry 4.0 architecture), or as Broker (to indicate that they represent a broker). Brokers have the same properties as in the domain model (name, url, protocol, and description). Also, all components of Industry 4.0 must be associated with a broker.
The operations (Operation metaclass) of an Industry 4.0 component can be annotated as Publisher or Subscriber to indicate that they publish to a topic, or are run by a subscription to a topic, via the topic property. As in the domain model, a Topic is a UML Signal. In this case, a Signal annotated as a Topic has a name, an optional description, an optional identifier of the publish and subscribe operations (_ publishOpId_ and subscribeOpId, respectively), and a set of parameters, which in turn can be named, typed, and can contain optional descriptions. Note that the identifiers publishOpId and subscribeOpId do not necessarily have to coincide with the name of the operations of the components that publish or subscribe to a given topic, since a given topic is going to be associated with numerous publisher and subscriber operations. Next, we see that any UML StructuredClassifier can be annotated to represent a certain Message. Thus, a message has a name, and an optional description. It should be noted that, since in the domain model a message points to a single Payload whose type is a StructuredClassifier, the profile has avoided representing Payload explicitly: the type of the Payload is the StructuredClassifier itself annotated by the message, and its value, the object resulting from instantiating said StructuredClassifier. Finally, we find the RedefinableProperty stereotype, which allows us to annotate properties (metaclass Property). This is a helper stereotype that allows us to set a friendlier name, or title, to any property at the modeler's convenience.
Yes! Look at the model below!
From the above profiles model, it is possible to obtain the following AsyncAPI specification:
{
"asyncapi": "2.0.0",
"info": {
"title" : "Example Architecture",
"version" : "0.1.0"
},
"servers": {
"production" : {
"url" : "example.com:1883",
"protocol" : "mqtt"
}
},
"channels": {
"iotbox/{id}/monitor" : {
"parameters" : {
"id" : {
"schema" : {
"type" : "string"
}
}
},
"publish" : {
"operationId" : "sendStatus",
"message": {
"$ref" : "#/components/messages/MonitorMessage"
}
},
"subscribe" : {
"operationId" : "receiveStatus",
"message": {
"$ref" : "#/components/messages/MonitorMessage"
}
}
},
"iotbox/{id}/configure" : {
"parameters" : {
"id" : {
"schema" : {
"type" : "string"
}
}
},
"publish" : {
"operationId" : "sendServiceConfiguration",
"message": {
"$ref" : "#/components/messages/ConfigurationMessage"
}
},
"subscribe" : {
"operationId" : "receiveServiceConfiguration",
"message": {
"$ref" : "#/components/messages/ConfigurationMessage"
}
}
}
},
"components": {
"messages": {
"MonitorMessage" : {
"name" : "MonitorMessage",
"payload" : {
"$ref" : "#/components/schemas/PathInfo"
}
},
"ConfigurationMessage" : {
"name" : "ConfigurationMessage",
"payload" : {
"$ref" : "#/components/schemas/Configuration"
}
}
},
"schemas": {
"Configuration" : {
"type" : "object",
"properties" : {
"monitoringfrequency" : {
"$ref" : "#/components/schemas/MonitoringFrequency"
}
}
},
"MonitoringFrequency" : {
"type" : "object",
"properties" : {
"value" : {
"type" : "integer"
},
"unit" : {
"type" : "string",
"enum" : [
"seconds",
"minutes"
]
}
}
},
"PathInfo" : {
"type" : "object",
"properties" : {
"id" : {
"type" : "string"
},
"beltInfos" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/BeltInfo"
}
}
}
},
"BeltInfo" : {
"type" : "object",
"properties" : {
"id" : {
"type" : "string"
},
"ts" : {
"type" : "string",
"title" : "timestamp"
},
"speed" : {
"type" : "integer"
}
}
}
}
}
}
First, Download and install the AsyncAPI Toolkit.
To see the above model, and test the transformation and the code generation, run the Example AsyncAPI Project from I4.0 UML Model.
First, use the dedicated wizard in the New Project
dialog:
Second, AsyncAPI Project, set a project name, and continue.
Third, select the Example AsyncAPI Project from I4.0 UML Model template.
Finally, the wizard can be completed.
After that, a new Maven project with the following contents will appear in the workspace.
Pay special attention to the following files:
-
src/main/java/example/I40.di
is the main Papyrus UML file with the example Industry 4.0 architecture shown above. -
src/main/java/example/I40.asyncapi
is the AsynAPI specification which is automatically generate from the UML model above. Code and other resourcs in thegen
directory will be generated from the specification contained in this file. -
src/main/java/example/SubscribeExample.java
is an example program demonstrating how to use the generated code. In this case, this program subscribes to an example topic, and waits for messages until enter is pressed. -
src/main/java/example/PublishExample.java
is another example program. In this case, this program publishes messages in the example topic, one per each execution of the program. In can be executed at the same time than theSubscribeExample.java
program, and messages sent by this program will be received bySubscribeExample.java
.
The profile can be found in the /plugins/io.github.abelgomez.asyncapi.i40.profile/model/ directory. These are the main contents:
domain-model.di
: Main Papyrus file for the domain model.domain-model.notation
: Notation Papyrus file for the domain modeldomain-model.uml
: The actual UML2 file of the domain modeldomain-model.png
: The domain model as a PNG image file.i40.profile.di
: Main Papyrus file for the Industry 4.0 Profile.i40.profile.notation
: Notation Papyrus file for the Industry 4.0 Profile.i40.profile.uml
: The actual UML2 file of the Industry 4.0 Profile.i40.profile.png
: The Industry 4.0 Profile as a PNG image.i40.ecore
: Automatically generated Ecore file from the Industry 4.0 Profile. This Ecore file is used to generate code for the profile, so that it can be easily used in Java-based model transformations.i40.profile.genmodel
: Automatically generated GenModel file from the Industry 4.0 Profile. This file is used to customize the code generation from the above Ecore file.
Can I regenerate my AsyncAPI specification (and the generated code) after modifying the initial UML model?
Yes! But keep in mind that any manual modifications to the I40.asyncapi file will be overwritten!
Just use the AsyncAPI -> Generate AsyncAPI
context menu over the I40.uml
file:
The integration of the Industry 4.0 Profile within the AsyncAPI Toolkit relies on two model transformations:
-
From UML to AsyncAPI: This model-to-model transformation takes as its input a UML model annotation with the Industry 4.0 Profile, and generates an AsyncAPI specification based on its abstract syntax.
This transformations, implemented using Xtend, can be found at /plugins/io.github.abelgomez.asyncapi.i40/src/io/github/abelgomez/asyncapi/i40/m2m/Uml2AsyncApi.xtend
-
From AsyncAPI (model) to AsyncAPI (text): This model-to-text transformation takes as its input an AsyncAPI model and serializes it using its JSON-based concrete syntax.
This transformations, also implemented using Xtend, can be found at /plugins/io.github.abelgomez.asyncapi/src/io/github/abelgomez/asyncapi/generator/AsyncApi2Json.xtend