Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
ATL FAQ
< To: ATL
This is the ATL wiki FAQ. The entries of the old ATL FAQ (archived version) have not been copied here yet.
Contents
- 1 Metamodels declared in the header (after the create keyword) of transformation models have to be named. What name should be used?
- 2 How close is ATL navigation language from the OCL 2.0 standard?
- 3 How can I refer to metamodel classes located in subpackages, and avoid name collision?
- 4 I can use KM3 to create metamodels, but what about models?
- 5 How to create a terminal model?
- 6 What's this ATL feature called "superimposition"?
- 7 Using named references in ATL
- 8 How can I try ATL without installing Eclipse?
- 9 Is it possible to create abstract lazy rules?
- 10 What are the different kinds of rules, and how do they work?
- 11 How boolean expressions are evaluated?
Metamodels declared in the header (after the create
keyword) of transformation models have to be named. What name should be used?
Usually, the name given to a metamodel is used in several places: the name of the file containing its definition (e.g. in XMI or KM3), the name of the main package of the metamodel, and the name given in the header of ATL transformations. This is the simple scenario that should be followed when possible.
In practice, the EMF driver for ATL (emf4atl) does not care about the name given to the metamodel in the header. There is no strong notion of main package. Any name can thus be used.
The MDR driver (mdr4atl), however, does care about this name. A specific package has to be specified to create a model conforming to a metamodel. If the correct package is not selected, the created model usually does not behave as expected. The current version of mdr4atl selects the package having the name specified in the transformation header or any package if there is no match.
When designing ATL, we started from the most recent OCL specification at the time. It is the OMG Final Adopted Specification ptc/03-10-14.
We elaborated from this document to solve the following issues:
- ATL works with MOF, not UML. The specification only gave some hints on how to do this.
- We decided to use model element references so that the metamodel is not defined as an extension of the metametamodel. Note that the specification defined it as an extension of UML.
- We had to resolve some of the ambiguities of the specification. The latest version of OCL 2.0 specification probably solves most of these but ATL predates it.
- We simplified the metamodel and syntax so that it works with TCS (or more precisely the version of TCS at that time).
The last step (simplification of metamodel and syntax) was necessary but did not impact the result too much in
our opinion.
It mostly resulted in forbiding some of OCL syntactical shortcuts.
For instance, iterators and self
must be specified explicitely in ATL whereas this is optional in OCL.
We are confident that ATL is really close to OCL 2.0. Moreover, it is certainly interoperable with any OCL tool having an explicit metamodel. This interoperability can indeed be achieved via model transformation.
How can I refer to metamodel classes located in subpackages, and avoid name collision?
In ATL, classes are always referred to with respect to their metamodel. They are two possibilities to refer to a specific class from a given metamodel: simple name, and full name.
Simple name reference to metamodel classes
Metamodel classes can be referred to by their name, even if they are defined in subpackages:
<MetamodelName>!<ClassName>
Let us, for instance, consider the following metamodel defined in file MM.km3:
package P1 { class C1 {} package P2 { class C2 {} } } package P3 { class C3 {} }
ATL code can refer to these classes simply by prefixing their name by the metamodel name (declared in the transformation header), and an exclamation mark (!):
MM!C1 MM!C2 MM!C3
Full name reference to metamodel classes
It is also possible to include the full path using the following scheme:
<Package1Name>::<Package2Name>::<ClassifierName>
Actually the ATL Parser doesn't deal well with "::" so we need to surround the path using ".
For instance, using the metamodel excerpt given above, we could write:
MM!"P1::C1" MM!"P1::P2::C2" MM!"P3::C3"
In some cases, full name reference is required to avoid ambiguity due to name collision. Let us consider the following metamodel:
-- Note: the following KM3 excerpt is not valid because KM3 does -- not allow several classes with the same name, even in different -- packages. However, the structure described here can be found -- in some pre-existing Ecore or MOF 1.4 metamodels. package P1 { class C1 {} package P2 { class C1 {} } } package P3 { class C1 {} }
Using MM!C1 is incorrect because it cannot reliably me mapped to a specific class. If you try to do this, a warning will be reported in the ATL console. In this case, it is mandatory to write:
MM!"P1::C1" MM!"P1::P2::C1" MM!"P3::C1"
I can use KM3 to create metamodels, but what about models?
Please see the answer to How to create a terminal model?
How to create a terminal model?
Definition A terminal model is a model such that its reference model is a metamodel, i.e. it conforms to its reference metamodel. It is a representation of a "real world" system. |
If you design your own DSL from scratch, you should first define the abstract syntaxt of this DSL i.e. the metamodel. To create your metamodel, you can use KM3.
Definition A metamodel is a model that defines the concepts and relationships that may be created in a model. A model always conforms to a metamodel. This relation is called conformance. The conformance relation has a different nature than the representation relation between a model and its system. A metamodel does not represent a model (that could be considered a system), but only the concepts and relationships that may be created. A metamodel conforms to a metametamodel. |
With your metamodel, you are now ready to create your terminal model.
NB: If you are a UML user, your favorite UML modeler may already provides you a XMI-serialization for your UML diagrams. You can use these XMI files directly in a model transformation.
There are several possibilities to create terminal models conform to your metamodel:
- Using EMF "Sample Reflective Ecore Model Editor".
- Creating a graphical editor by using Eclipse/GMF project. This is very convenient for languages with visual syntaxes.
- Creating a textual editor by using Eclipse/TCS. This is very convenient for languages with textual syntaxes.
- Using a XML-to-model tool that can parse XML documents into a model.
- Transforming a source model into a target model by combining one previously quoted solution and a model tranformation.
Using EMF Generated Editor
If you want to create terminal models, an easy way would be to use the EMF generated editors. From your Ecore metamodel, you can create an EMF model (New > Other... Eclipse Modeling Framework> EMF Model). A genmodel file is generated, and when you open it you see a tree editor (almost the same as with your ecore metamodel). On the context menu, you should be able to generate model file, edit and editor. Click on each of them and you will have a set of plugins that will add a specific editor (on .author files as default). This editor is a tree like editor, as in ecore. It is a very simple editor, but it should be enough to run some tests with ATL.
By this way you create terminal models that conform to your metamodel. If you feel like customizing a little your editor, check the properties of the genmodel items. You can set some interesting options, although you don't need to change most of them.
This solution is adapted for a simple test but in most of the case the creation of an advanced editor could be cost-effective.
Creating a Graphical Editor for a visual syntax
If your DSL already has a visual syntax or if you want to have one, there are some powerful editor generators to do it. With a project like GMF, you can generate a graphical editor from your metamodel. GMF (Graphical Modeling Framework) provides a generative component and runtime infrastructure for developing graphical editors based on EMF and GEF. A tutorial is available at: http://wiki.eclipse.org/index.php/GMF_Tutorial.
Creating a Textual Editor for a textual syntax
If your DSL already has a textual syntax or if you want to have one, with TCS you can generate a textual editor from your metamodel. TCS (Textual Concrete Syntax) enables the specification of textual concrete syntaxes for Domain-Specific Languages (DSLs) by attaching syntactic information to metamodels. With TCS, it is possible to parse (text-to-model) and pretty-print (model-to-text) DSL sentences. Moreover, TCS provides an Eclipse editor, which features: syntax highlighting, an outline, hyperlinks, and hovers for every DSL which syntax is represented in TCS. TCS examples are available at: http://wiki.eclipse.org/TCS/Zoo.
Starting with XML documents
If you start from XML documents, you can use the AM3 XML tool to create terminal models. This tool transforms your xml file into a model conforms to the XML metamodel. Then you can create a model transformation from the XML metamodel to your metamodel. This transformation generates terminal models conform to your metamodel. You can find an example using this mechanism in the RSS to ATOM use case (see XML2RSS.atl or XML2ATOM.atl transformations available from the ATL Transformation Zoo).
Transforming a source model into a target model
The idea is to reuse a tool that creates terminal models and then a transformation can be created to your metamodel. For instance, to get a model conforming to a SimpleClassDiagram metamodel one can write a UML to SimpleClassDiagram transformation. Then, a standard UML tool can be used to create SimpleClassDiagram metamodels.
Advanced concepts
An injection is a transformation from another Technical Space (e.g., XML, Grammarware) to the Model Engineering Technical Space.
An injector is a tool implementing an injection.
An extraction is a transformation to another Technical Space (e.g., XML, Grammarware) from the Model Engineering Technical Space.
An extractor is a tool implementing an extraction.
Injectors and extractors may be used when respectively loading and saving models using the AM3 ant tasks. To be usable from the AM3 Ant Tasks an injector (resp. extractor) must implement the Injector (resp. extractor interface. Some injectors and extractors are already available: XMLInjector, XMLExtractor, TCSInjector, and TCSExtractor.
What's this ATL feature called "superimposition"?
Superimposition allows you to load an ATL transformation module on top of another in your "Run..." configuration. It allows for the superimposing module to import and override matched rules from the module it is superimposed upon. See also the ATL Superimposition wiki page, the corrresponding bug report and some example transformations.
Q: I read in the corresponding bug report that it is now possible to use a feature called superimposition. Is a superimposed module aware of the module it is superimposing? Or more concretely, is it possible to access rules of the root module from a superimposed module? How can this be done? - Markus Herrmannsdoerfer
A: Modules are not at all aware of any superimposition going on. Superimposition is done at load-time. Access includes invocation of called rules and helper methods, as well as helper attributes.
You can actually access any module in the same run, whether it is superimposing or superimposed upon. It is of course bad practice to introduce references from the root module to any of the superimposed modules, so you'll probably want to reference downward only.
The safest (and original) use of superimposition is to mask matched rules from the root module. Any matched rule in a superimposed module with the same _name_ as a matched rule in the root module will replace it (it masks the old rule).
Q: Do I have to use the "uses" statement in order to be able to access a rule from another module? - Markus Herrmannsdoerfer
A: No, this is not strictly necessary. It is recommendable in case of explicit references to another rule, however. It adds more clarity and may even become a future requirement.
If you only mask a rule from a lower transformation module, no explicit reference to the masked rule is made. Hence, no explicit "uses" statement should be used for this case.
Q: Assume I have the following rules in the root module:
rule A { ... } rule B extends A { ... }
1. Is it possible to mask B in another module and still extending A from the root module? - Markus Herrmannsdoerfer
A: No, this is not possible. The "extends" statement is a compile-time construction. At compile-time (i.e. .atl to .asm), only single modules are considered. Superimposition is a load-time costruction, that links the .asm files just before running them.
Q: 2. If I mask A in another module, will B in the root module then extend the new A? - Markus Herrmannsdoerfer
A: No, the "extends" statement is compiled in such a way that rule "A" is simply in-lined in rule "B". No relationship between "A" and "B" exists in the .asm file.
If "A" were a called rule, it would be masked by any newly defined called rule "A". Rule "B" then indeed invokes the new rule "A".
Using named references in ATL
When you inject your KM3 model into an Ecore metamodel, an Ecore file corresponding to your KM3 file gets created. By default EMF creates references by location, i.e. something like ref=//@structuralElements.2/@ae.0
You can also instruct EMF to use named references, i.e. ref=n. Here, n is the value of an attribute of the referenced Ecore class which has the EMF option ID set to true. So you get something like (n=14):
<structuralElements xsi:type="meta:Package" id="13" name="" ingoing="14"/> <structuralElements xsi:type="meta:StructuralDependency" id="14" src="10" dst="13"/>
The closest km3 definition would be:
... reference ... ingoing ... : StructuralDependency ... ... --@ID attribute id : String; ...
The @ID comment instructs the KM3 compiler to set the EMF option ID to true. It is not yet implemented (EMF 2.3.0.v20070626, ATL 2.0.0rc2), for now you'll have to edit the generated Ecore file to set the option manually.
Now you can use ATL with models using named references.
How can I try ATL without installing Eclipse?
Several ATL transformations have been deployed as web services:
Moreover, it is possible to try OCL queries with ATL using the OCL Web Tester web service.
Is it possible to create abstract lazy rules?
Yes, it is possible. Let us, for instance, consider the following example to explain how to use this mechanism:
lazy abstract rule A { ... } lazy rule B extends A { ... } lazy rule C extends A { ... }
In your transformation, you can call lazy rules B or C with the following syntax thisModule.A(element)
. They will be called depending on which one matches.
RM: The syntax thisModule.B(element)
is invalid.
What are the different kinds of rules, and how do they work?
There are three types of declarative rules:
- Standard rules are applied once for each match. A given set of elements may only be matched by one standard rule,
- Lazy rules are applied as many times for each match as it is referred to from other rules (possibly never for some matches).
- Unique lazy rules are applied at most once for each match, and only if it is referred to from other rules.
The following table summarizes their differences with respect to the number of time they are applied.
Kind of rule | Number of references to source pattern | Number of times the target pattern gets created | Kind of traceability link created |
---|---|---|---|
standard | 0 | 1 | default or not (using keyword nodefault) |
1 | 1 | ||
n > 1 | 1 | ||
lazy | 0 | 0 | Not default |
1 | 1 | ||
n > 1 | n | ||
unique lazy | 0 | 0 | Not default |
1 | 1 | ||
n > 1 | 1 |
In addition, imperative rules may also be used.
Here are a few guidelines about which rules and constructs to use. They may be summarized as: "Make your transformation as complex as necessary but as simple as possible".
- Prefer declarative over imperative: only use imperative constructs for the part of a transformation that needs it if it even does.
- Prefer simpler constructs over more complex ones:
- Use standard rules when possible, otherwise use unique lazy rules, and use lazy rules only if necessary.
- Only use resolveTemp if necessary.
- Prefer iterators (e.g., select, collect) over iterate.
How boolean expressions are evaluated?
In this case:
if (exp1 and exp2) then ... else ... endif
exp2 will always be evaluated, regardless of the result of the first expression. ATL evaluates it like this:
if (exp1.and(exp2)) then ... else ... endif
So remember that in this case:
if (self.attributes->size() > 0 and self.attributes->first().attr)
Even though the first member is false, there may be a call of the "attr" property on an undefined element, which will cause an error.