This section shows the transformation rules for one simple example. The PIM and PSM languages are fixed. Note that it is easy to change the rules such that the PIM will map to any mainstream object oriented language. The transformation below can easily be adapted to transform to, for example, Python, Java, or C++. 9.3.1 Public and Private AttributesThe second transformation rule explained in section 9.1 specifies a transformation from public attribute to private attribute and getter and setter operations. The rule can be seen as a relationship class between the metaclasses of both PIM and PSM language, as shown in Figure 9-3. To distinguish between the metaclass Attribute of the PIM and the PSM language, the role names used in the associations are sourceAttribute and targetAttribute, respectively. Remember that actually the two Attribute classes shown in the figure are one and the same, because both the PIM and PSM languages are UML. Figure 9-3. The transformation rule, viewed as a class
The model specified by the diagram is, however, not yet precise enough to be a complete specification of the transformation rule. We have to augment it with parameters, conditions, and so on. The following specifies the transformation rule completely using the language defined in the previous section. In this case the <~> symbol represents equality, because both source and target language are the same. Transformation PublicToPrivateAttributes (UML, UML) { params setterprefix: String = 'set'; getterprefix: String = 'get'; source sourceAttribute : UML::Attribute; target targetAttribute : UML::Attribute; getter : UML::Operation; setter : UML::Operation; source condition sourceAttribute.visibility = VisibilityKind::public; target condition targetAttribute.visibility = VisibilityKind::private and setter.name = setterprefix.concat(targetAttribute.name) and setter.parameters->exists( p p.name = targetAttribute.name and p.type = targetAttribute.type) and setter.type = OclVoid and getter.name = getterprefix.concat(targetAttribute.name) and getter.parameters->isEmpty() and getter.type = targetAttribute.type and targetAttribute.class = setter.class and targetAttribute.class = getter.class; bidirectional ; mapping sourceAttribute.name <~> targetAttribute.name; sourceAttribute.type <~> targetAttribute.type; } When tools support this transformation rule, some tools could offer the user the possibility to set the getter and setter prefixes as transformation parameters. Other tools could offer the possibility to choose between using a prefix or a postfix string, or let the user enter the getter and setter operation names to be used in the generation. Not only can the transformation thus be tailored to the specific needs of the user, tool vendors will still compete in the area of user support, even when transformation rules are standardized. The complete transformation definition for mapping a model with public attributes to a model with only private attributes consists of more than just the transformation rule PublicToPrivateAttributes . To transform a complete UML model, a large number of rules are needed. In this case, all these rules would simply take an element (other than a public attribute) in the source model and produce exactly the same element in the target model and they are therefore not formalized . 9.3.2 AssociationsThe transformation definition for the second example from Chapter 2 transforms associations to attributes. The association ends become private attributes with get and set operations. This transformation rule illustrates the fact that different strategies can be used when we define transformation rules. To define the second example from Chapter 2, we can either build one transformation definition that specifies the full transformation, or we can build a transformation definition that transforms association ends into public attributes, and then apply the public to private attributes transformation definition from the previous section to this intermediate model. This approach makes use of an intermediate model and the ability to combine transformation definitions. Because we have already defined the PublicToPrivateAttributes rule, the latter option is the easiest , and we choose to specify the simple transformation from association ends to public attributes. The first step is always to determine the metamodels of the source and target language. For this example, in which both source and target language are UML, we use the metamodel depicted in Figure 9-4. Note that this metamodel is not the exact metamodel from the UML standard; a simplified version is used for this example. Figure 9-4. The UML metamodel used in the association transformation
The metamodel specifies that a UML model consists of classes that hold features, which can be either associations ends, attributes, or operations. All features have a type that is a class. For operations, if present, this type represents the return type. Association ends have a multiplicity that is the combination of an upper and a lower bound. A single association is the combination of two association ends. Attributes have a visibility, which has one of the values of the enumeration type VisibilityKind , that is, public , private , or protected . Furthermore, included from the OCL metamodel, there is a Set that has a class for its elementType. Instances of Set are sets of objects. Although it is not clear from the diagram, we assume that the type of an attribute may be either a Class or a Set. Because we may not define mapping rules conditionally, as explained in section 9.2.2, we have to write two different transformation rules. The first applies when the multiplicity of the association end is at most many; the second applies when the multiplicity is at most one. Transformation ManyAssociationToAttribute (UML, UML) { params -- none source ae : UML::AssociationEnd; target att : UML::Attribute; source condition ae.upper >= 1; target condition att.visibility = VisibilityKind::public and att.type.isTypeOf(Set); unidirectional ; mapping ae.name <~> att.name; ae.type <~> att.type.elementType; } In this transformation rule, the class that is the type of the association end must map onto the element type of the set that is the type of the generated attribute. In the second transformation rule, the class that is the type of the association end must map onto the type of the generated attribute. Note that type conformance is preserved. Both the type of the association end, and the type of the attribute in the second rule is the metaclass Class , as is the type of the element type of the set in the first rule. This is the specification of the second rule. Transformation SimpleAssociationToAttribute (UML, UML) { params -- none source ae : UML::AssociationEnd; target att : UML::Attribute; source condition ae.upper <= 1; target condition att.visibility = VisibilityKind::public and att.type.isTypeOf(Class); unidirectional ; mapping ae.name <~> att.name; ae.type <~> att.type; } 9.3.3 ClassesStill we have not defined the transformation completely. In Chapter 2 the transformation definitions also state which classes own the attributes and association ends. In the attribute transformation rule, it said:
In the association transformation rule, it said:
We have to state that the generated attribute is owned by the class that is generated for the owner of the association end. What we actually want to define is not a transformation of standalone associations to attributes, or from attributes to getter setter operations. We want to define a transformation of classes to classes, where the association ends and the attributes are mapped as described above, while all other attributes and operations are kept. Therefore, we need the following transformation rule to transform classes to classes. For convenience, we define three additional operations for Classifier, called associationEnds , attributes , and operations , which return the classifier's features of type AssociationEnd , Attribute , and Operation , respectively. Transformation ClassToClass (UML, UML) { params -- none source c1: UML::Class; target c2: UML::Class; source condition -- none target condition -- none unidirectional ; mapping c1.associationEnds() <~> c2.associationEnds(); c1.attributes() <~> c2.attributes(); c1.operations() <~> c2.operations(); } Here, the meaning of the mapping symbol (<~>) is that there is a mapping from left-hand side to right-hand side, that is, within this transformation definition rules can be found that define this mapping. In defining the transformation for classes, we do not need to explicitly choose the right (sub)rule for transforming association ends. Depending on the way the elements in the actual source model meet the conditions in the transformation definitions, the right transformation is chosen . Likewise, we do not have to bother with the situation where there are no association ends, or attributes, or operations. The mapping rules state that if there is an element that conforms to the conditions it is transformed; if there is no such element, no action is taken. The additional operations are defined in OCL as follows : context Class def : attributes() = feature->select( isTypeOf(Attribute) ); operations() = feature->select( isTypeOf(Operation) ); associationEnds() = feature->select( isTypeOf(AssociationEnd) ); 9.3.4 Finishing the Transformation DefinitionThe complete transformation definition for mapping associations to public attributes consists of the transformation rules ManyAssociationToAttribute , SimpleAssociationToAttribute , ClassToClass , and the rules that map existing attributes to attributes and operations to operations. These last two rules have not been formalized because they are straightforward. In order to specify the second example from Chapter 2 completely, we have to specify that this transformation is followed by the transformation defined in section 9.3.1, which transforms public to private attributes. The complete transformation definition can be defined as the sequence of the AssociationToPublicAttributeSpec transformation followed by the PublicToPrivateAttributesSpec transformation, using the names AssociationToPublicAttributeSpec and PublicToPrivateAttributesSpec to indicate the respective transformation definitions. |