-
Notifications
You must be signed in to change notification settings - Fork 1
Architecture
The EMDW Model Compiler (MC) is an Eclipse based tool for generating source code for applications developed by UML modeling techniques. MC is developed on top of a technology stack that includes an extensible, state-of-the-art integrated development environment (Eclipse) and model-driven software development frameworks (including EMF, Xtext, EMF-IncQuery, VIATRA). The main functionality of MC is provided by a set of independent components that are executed in a workflow to deliver source code from the UML models. These components include (1) a live synchronization between xUML-RT UML models and the xUML-RT EMF model representation, (2) a model-to-model transformation from the intermediate model to a high-level source code model (e.g. C++ classes, includes and files) and (3) a model-to-text transformation to produce the source code from the source code model.
Eclipse is a platform that has been designed from the ground up for building integrated web and application development tooling. By design, the platform does not provide a great deal of end user functionality by itself. The value of the platform is what it encourages: rapid development of integrated features based on a plug-in model.
Eclipse provides a common user interface (UI) model for working with tools. It is designed to run on multiple operating systems while providing robust integration with each underlying OS. Plug-ins can program to the Eclipse portable APIs and run unchanged on any of the supported operating systems.
At the core of Eclipse is an architecture for dynamic discovery, loading, and running of plug-ins. The platform handles the logistics of finding and running the right code. The platform UI provides a standard user navigation model. Each plug-in can then focus on doing a small number of tasks well.
Eclipse Modeling Framework is a Java framework and code generation facility for building tools and other applications based on a structured model. EMF provides a meta-model (Ecore) for describing structured models. Using these structured models EMF provides tools and runtime support to produce a set of Java classes representing the model in Java Virtual Machine (JVM), a set of adapter classes that enable viewing and a basic editor.
Papyrus is aiming at providing an integrated and user-consumable environment for editing any kind of EMF model and particularly supporting UML and related modeling languages such as SysML and MARTE. Papyrus provides diagram editors for EMF-based modeling languages amongst them UML 2 and SysML and the glue required for integrating these editors (GMF-based or not) with other tools. Papyrus also offers a very advanced support of UML profiles that enables users to define editors for DSLs based on the UML 2 standard.
Xtext is a framework for development of programming languages and domain specific languages. It covers all aspects of a complete language infrastructure, from parsers, over linker, compiler or interpreter to fully-blown top-notch Eclipse IDE integration. It comes with built-in defaults for all these aspects which at the same time can be easily tailored to the individual needs of DSLs.
Xtend is a flexible and expressive dialect of Java, which compiles into readable Java 5 compatible source code. Any existing Java library can be used seamlessly. The compiled output is readable and pretty-printed, and tends to run as fast as the equivalent handwritten Java code.
EMF-IncQuery is a framework for defining declarative graph queries over EMF models, and executing them efficiently without manual coding in an imperative programming language such as Java.
The query language of EMF-IncQuery is highly expressive and supports query libraries, transitive closure, negative application conditions and check expressions. The language is defined in Xtext and has a textual editor with advanced editing features like syntax highlighting, content assist, validation and quick fixes.
The VIATRA framework supports the development of model transformations with specific focus on event-driven, reactive transformations. Building upon the incremental query support of the EMF-IncQuery project, VIATRA offers (1) a language to define and (2) a reactive engine to execute transformations upon changes in the underlying model.
XSemantics is a DSL (implemented in Xtext itself) for writing type systems, reduction rules, interpreters (and in general relation rules) for languages implemented in Xtext. It then generates Java code that can be used in your language implemented in Xtext for scoping and validation (it can also generate a validator in Java).
In order to support the envisaged model-driven EMDW framework to automatically generate source code and configuration to different implementation languages, we defined our modeling architecture based on the following concepts:
- Provide an editor (tool) independent input for the code generation process. As xUML-RT is a UML compatible language, where the user can define their models using any third-party UML tools the EMDW model compiler aims to define a separate EMF based input language (called xtumlrt) for the code generation process and provides an integration layer for EMF-UML. This allows to have easy out-of-the-box integration with any Eclipse based UML editor using EMF-UML. Additionally, integrating EMDW to any non-Eclipse based environment only requires the mapping from its UML representation to our input xUML-RT language.
- Support high-level instance model reusability in the generation process. The EMDW model compiler aims to support the reusability of the main models used within the generation process (e.g., xtumlrt, platform). This way the system architect can reuse already defined allocations for a single PIM xUML-RT model to multiple PSMs.
- Complex traceability support through the various models The EMDW modeling architecture is designed from the ground to support traceability between the complete development process as required by certain testing/certification guidelines.
OMG’s Unified Modeling language is one of the most widely used system and software modeling standard as of today that provides more than 15 different diagrams to capture all the different aspects of the system/module under design. Within EMDW a major goal it to provide an end-to-end code generation solution from high-level UML compliance PIM models to various implementation platforms.
Within EMDW we use EMF-UML to store and manipulate UML models as it is the de facto standard of the Eclipse platform for handling UML diagrams.
The high-level platform independent procedural action language to be define for the xUML-RT language. It follows the principles of any well-known (Java, C++) procedural programing languages for defining control structures (loops, ifs) and simple statement (variable declaration, arithmetic operations, etc) with language-level extensions to support (i) state machine event handling and processing, (ii) declarative query specification over xUML-RT Objects, (iii) port based communication and event handling and (iv) high-level handling and processing of Collections. The language is defined using Xtext and is currently under development.
(Please note that the naming convention for the new language called executable Unified Modeling Language for Real-Time changed during the EMDW project, thus many of the metamodels still hold the old abbreviation xtUMLRT and does not uses the accepted xUML-RT one. Both abbreviations mean the same language.)
The language has its root coming from both the original UML-RT and also xtUML (executable UML, https://xtuml.org/). It aims to provide a revisited version of UML based executable modeling integrating all the experience gained from its predecessors.
Within the xUML-RT MC projects, we use the instances of the xtumlrt metamodels as the input for the model compilation. Their main purpose is to capture all required PIM level information from the UML representation for the model compilation process. Due to its two predecessors languages the language was defined using a common part that captures those segments that are both present in xtUML and UML-RT while the specific extensions to these language area captures within their corresponding inherited metamodel.
Defines all the structural element for xUML-RT that is present both within xtUML and UML-RT. On this level we mainly focus on data level language integration and NOT semantics level integration. This means that some concept are stored in the same elements, which might have slightly different semantic meaning within their defining predecessor language.
This language is also commonly used by Papyrus-RT, which is responsible for the UML-RT part.
Defines all the extensions and constraints that altogether formulates the new xUML-RT language. As the semantics of the novel language is still under development the language itself is also changing rapidly based on the accepted and refined segments of the novel language’s semantics.
A simple traceability model that is able to contain the traceability links between the input EMF-UML model and its corresponding xtumlrt model.
In order to provide higher level reusability of MC components between the different realization languages (Java and C++) we defined a set of metamodels to capture the oopl language concepts that are used in the model compilation process. The driving idea behind this PSM metamodel is to capture all relevant segments of the generated source code on model level (maximum down to method level) and execute all the optimization and fine-tuning steps directly on the model representation rather than including this business logic into the template based code generation steps.
The common part contains those elements that are both present in the C++ and Java and defines important concepts within the generated source code such as: Classes, Data types (e.g., enumeration) and realization of associations on abstract collection level (e.g., set, list, etc).
The C++ metamodel extends the common part with all required C++ specific concepts down to method level that is used by the model compiler. This includes: element naming, header and source file handling, folder and package definition, import declaration, Type mapping and definition.
The Java model is not yet created.
The platform model will hold all execution platform specific information and will describe the provided services by the platform that can be used to fine-tune the behaviour of the generated source code.
The Platform model is not yet created.
The transformation configuration model will describe all necessary auxiliary information for the code and configuration generation that includes: integration with legacy modules, debugging/tracing, init and startup configurations, compiler and language versions.
The Transformation configuration model is not yet created..
The complete workflow of MC is built from several steps, some of these steps are working in an incremental mode while others are executed in batch processing phases. The incremental steps, such as the xUML-RT bridge are activated when the UML model is opened and react to events when they happen. The other steps are called explicitly when the user starts the code generation process.
- The xUML-RT bridge is an incremental step that performs the live synchronization between an opened xUML-RT UML model and the corresponding xUML-RT EMF model.
- The xUML-RT EMF model is processed by an incremental step to create the higher levels of a CPP model (global packages and components), while the internal details of UML components are transformed in a batch processing step.
- The CPP model is used to drive the source code generation in a batch processing step.
- The user prepares the action code in the xUML-RT UML models with the rALF editor that integrates into the UML modeling environment. While the rALF snippet compiler prepares the individual C++ source snippets that must be inserted into the structure code during the model-to-text transformation.
The following figure shows the main steps for transforming the xUML-RT models to source code. The three main elements that the transformation and the code generation deals with are state machines, classes, associations and components.
In each case the first step is to adorn the xUML-RT model with CPP model elements. These elements provide the implementation specific details used during code generation (e.g. header and body files, directory structure, filed types). In the case of associations, there is an additional step for assigning implementation types to multi valued association containers. This mapping provides additional template parts for the code generation for accessing and modifying these associations. Finally, in each case there are a set of templates that are used for generating the structure code related to the xUML-RT elements.
The following figure shows the main plugins related to the model compiler with dependencies between the plugins represented with arrows point to the plugin that the source plugin depends on:
The Common and rALF plugins can be found in the EMDW-Common repository, while the rest are separated to Core and User Interface plugins. Core plugins do not depend on the availability of any user interface and can be used for performing the model compiler process, while the UI plugins create a very thin layer for calling the model compiler from the Eclipse IDE.
The xUML-RT bridge performs the mapping from the UML representation to the input xUML-RT language. The mapping is done by live synchronization where a set of mapping rules define how specific constructs in the UML model are mapped to the xUML-RT EMF elements. In an initialization phase, when the bridge is established, each rule is executed in a prioritized order to create the xUML-RT EMF model completely. After that the bridge listens for elementary notifications on the UML model and identifies rules that must be executed again to synchronize the models. Once the transaction that represents a user interaction has been committed, the required rules are executed and the synchronization happens.
The bridge is implemented using the VIATRA event-driven transformation API and EMF-IncQuery for precondition queries. In addition, the initialization of the bridge is also integrated into the Papyrus editor and is executed whenever an UML model is opened. The live synchronization uses the external traceability model to keep track of the mapping between elements.
The integration with Papyrus is done by using both the model set snippet and service registration functionalities of the Papyrus framework. When the Papyrus editor is opened for a UML model, it initializes the Model Set (which is a specialized EMF Resource Set) through the service registry. During this initialization, the model set starts the model set snippets that can be plugged in through an OSGi extension. The xUML-RT Model Set Snippet creates a new resource set to contain the models related to the model compiler and adds these resources to the Model Set by wrapping them into a EMFResourcePapyrusModel. Such resources are created for the xUML-RT model and the traceability model. In addition, the xUML-RT model representing the UML primitive types is also loaded. The model set snippet uses the service registry of Papyrus to access the IncQueryEngineService that is used to ensure that a common IncQueryEngine is available to anyone working with a given Model Set. Next, the snippet prepares the set of xUML-RT transformation extensions that add specialized mapping rules to the basic transformation. In our case, the support of external entities representing existing C++ code is handled with a transformation extension. Finally, all this information is used to create and setup the xUML-RT bridge transformation that performs the live synchronization.
The xUML-RT bridge transformation creates an EventDrivenTransformation that is provided by VIATRA and uses a Rule Provider utility class for setting up the synchronization rules. Each rule is a subtype of an AbstractMapping that provides an interface to create, update and remove some xUML-RT elements. Each mapping rule has a precondition query written in EMF-IncQuery that is used by the transformation to trigger the rule when a match appears, updates or disappears.
The CPP model is generated from the platform independent xUML-RT model in two phases. The first is an event-driven transformation that deals with the higher levels of the xUML-RT model (such as packages and components). The second is a batch transformation executed on each xUML-RT component to transform its internal details. In addition, there is a change monitor that identifies components that have changed since the last execution.
Both transformations are built using the VIATRA transformation APIs while the change monitor also uses an abstract implementation available in VIATRA for aggregating changes.
The C++ code generation is invoked from the Papyrus Model Explorer that shows the contents of the UML model opened in the current Papyrus editor. The UMLHandler is called through the Eclipse command framework and the event passed to the handler can be used to access the selected UML model. The handler uses the IncQueryEngineService to retrieve the common IncQueryEngine for the UML model. Before starting the code generation process, a validation is performed on the xUML-RT model. The validation uses the ValidationEngine defined in EMF-IncQuery and checks a set of validation rules defined as annotated EMF-IncQuery patterns. If the validation is successful, it creates the CPP model if needed or retrieves it from the resource set if already available. Next, the xUML-RT to CPP transformation is initialized if it is not yet running. Finally, the code generator is invoked.
The xUML-RT to CPP transformation is similar to the xUML-RT bridge, but it uses mapping rules in an EventDrivenTransformation to create, update and delete CPP model elements based on queries on the xUML-RT model. The IncQueryEngine used by the transformation is the same that is used in the xUML-RT bridge, thus reducing memory consumption by reusing the indexes.
The CPP code generator is itself a complex workflow that involves several steps. It uses the common IncQueryEngine and loads the CPP model representation of the supported C++ basic types (corresponding to the xUML-RT primitive types) and the container implementations. An xUML-RT change monitor is created if it does not exist to identify dirty xUML-RT Components by reusing the ChangeMonitor implementation from VIATRA. The change monitor is initialized with a set of queries and any changes in the match sets of these queries are translated into a list of affected components. The code generator can access the components that were changed since the last code generation.
Next, the xUML-RT component to CPP transformation is executed for each dirty component (all components when first invoked). After the CPP model is completely prepared, the source code of the xUML-RT runtime is mapped from its stored location to the CPP files in the CPP model representing the runtime. The CPP code generation is executed on the same components to derive the source code for the CPP files. The contents of the main Makefile and any Makefile rules are prepared by a Makefile Generation step. Finally, a separate File Synchronization step accesses the file system to create or update all files related to the code generation.
The component level transformation of xUML-RT is performed using the BatchTransformation API of VIATRA. The transformation uses the common IncQueryEngine and is made up of BatchTransformationRules that are executed using the BatchTransformationStatements utility. Each rule maps xUML-RT model elements to corresponding CPP model elements and is executed in the context of the matches for the precondition queries. Instead of event-driven execution, top level rules are invoked explicitly and they in turn may execute other rules to traverse the model. Finally, action code fragments defined in rALF are compiled using the rALF snippet compiler and the resulting C++ snippets are stored in the CPPModel as well.
The source code is generated by first deriving the content of each source file that is affected and then synchronizing the file system with the directory structure in the CPP model and updating the content of each file that has changed. This two step approach ensures that files with unchanged content are not touched as long as the code generation is deterministic.
The first phase of the code generation uses VIATRA batch transformation rules that use Xtend template expressions to create the structure code from the CPP model. The transformation generates only the content of the source files for that are also represented in the CPP model.
The structure code depends on a small C++ runtime library that is also described in a simplified CPP model. The content of the runtime library is also loaded into the same file-content map that the structure code uses.
The second phase takes the directory structure in the CPP model and the file-content map and uses VIATRA batch transformation rules to synchronize the file system with the model.
The xUML-RT C++ runtime is represented by a reduced CPP Model that only specifies the set of classes, the files related to them and the directory structure. The source code of the runtime is stored in a directory inside the code generation plugin. The runtime mapping receives the CPP model (more specifically the CPPDirectory EMF object), an IFileManager that is able to read from inside an OSGi bundle (BundleFileManager) and the path to the location of the source code inside the bundle as input. The mapper traverses the CPPDirectory structure and retrieves the content of files as described by the CPPFile objects. The results are simply stored in a map with the CPPFiles as keys and the file content as values.
The main code generation is also implemented using a BatchTransformation API of VIATRA. The code generation rules read the CPP model and use precondition queries to traverse the CPP model structure and prepare the contents of each CPPFile corresponding to the CPP model elements. The contents are generetad using a set of code templates that use Xtend template expressions for constructing complex source code fragments and EMF-IncQuery patterns for reading from the CPP model. The templates for a given file often invoke other templates for processing the subelements of the given CPP element (e.g. operations of a class). The results are stored in a CPPFile to file content map similarly to the runtime mapping.
The contents of the main Makefile and the Makefile rules are generated in a separate step. The Makefile generation templates read the CPP model to identify the directories that contain makefiles and prepare the contents of the required files into a map keyed with CPPFiles similarly to the runtime mapping and code generation.
The file synchronization step runs after all file contents (runtime, structure and makefiles) were generated by the previous steps. It uses an IFileManager that can read and write the Eclipse File System (EclipseFileManager) to update the contents of a target directory in a prepared Eclipse project. The synchronization itself is also implemented as a VIATRA BatchTransformation where the file synchronization rules read the CPP model to identify the files to be created, updated or deleted and use the map that contains the CPPFile contents. It is important that a given file is only written if its contents are different from the content prepared by the code generation.
The specification of the action code part of the UML model (such as operation bodies, transition effects etc.) are supported by the rALF editor that plugs into the Papyrus editor and is available where UML allows an OpaqueBehavior with a given language and code to be edited. The editor is based on Xtext and can access the UML model to provide correct scope and context for the action code (for example access attributes of the current class, read parameters of the operation, send signals with possible types).
The rALF snippet compiler is responsible for processing the action code in the UML model and generating C++ source code snippets that can be inserted at their corresponding location into the complete generated structure code. The compiler accesses the CPP model in order to find out the implementation types and names for xUML-RT elements (such as attributes) and may also modify the CPP model to insert additional includes or reference storage elements. The code snippets are generated by traversing the AST model built from the action code by Xtext and transforming each node as needed.