-
Key: QVT-26
-
Legacy Issue Number: 10978
-
Status: closed
-
Source: France Telecom R&D ( Mariano Belaunde)
-
Summary:
Some of the examples provided in the spec have either syntax errors either or missing
elements -
Reported: QVT 1.0b1 — Mon, 30 Apr 2007 04:00 GMT
-
Disposition: Resolved — QVT 1.0
-
Disposition Summary:
(1) Replace the contents of A2.1: Operational Mapping Examples by the following:
metamodel BOOK {
{title: String; composes chapters: Chapter [*];}
class Bookclass Chapter
{title : String; nbPages : Integer;}}
metamodel PUB {
{title : String; nbPages : Integer;}
class Publication}
transformation Book2Publication(in bookModel:BOOK,out pubModel:PUB);
main()
{ bookModel->objectsOfType(Book)->map book_to_publication(); }mapping Class::book_to_publication () : Publication
{ title := self.title; nbPages := self.chapters->nbPages->sum(); }(3) Replace the contents of 12.2 by
– This QVT definition performs an in place transformation on
– a UML class-diagram model by privatizing the attributes and
– creating accessor methodsmodeltype UML uses "omg.org.uml14";
transformation Encapsulation(inout classModel:UML);
// Indicating that UML1.4 Name type is to be treated as a String
tag "TypeEquivalence" UML::Name = "String";– entry point: selects the packages and applies the transformation
– on each packagemain()
{ classModel.objectsOfType(Package) ->map encapsulateAttributesInPackageClasses(); }– Applies the transformation to each class of the package
mapping inout Package::encapsulateAttributesInPackageClasses () {
{self.ownedElement->map encapsulateAttributesInClass();}
init}
– Performs the encapsulation for each attribute of the class
– The initialization section is used to retrieve the list of attributes
– The population section is used to add the two accessor operations
– The end section is used to privatize each attributemapping inout Class::encapsulateAttributesInClass ()
{ var attrs := self.feature[Attribute];}
{
initoperation := { – assignment with additive semantics
{ name := "get_" + self.name.upperFirst(); visibility := "public"; type := a.type; }
attrs->object(a) Operation;
{ name := 'a_'+ self.name.upperFirst(); kind := "in"; type := a.type;}
attrs->object(a) Operation {
name := "set_" + self.name.upperFirst();
visibility := "public";
parameter := object Parameter;
{ attrs->map privatizeAttribute();}
};
};
end}
– in place privatization of the attribute
mapping inout Attribute::privatizeAttribute ()
{ visibility := "private"; }(4) Replaces the content of A2.3 by the following
The metamodels used here are the same metamodels used for the relational version given in Appendix A.1.1. We provide below their definition using the concrete syntax for metamodels. Note we are assuming that all multi-valued associations are ordered.
metamodel SimpleUml {
abstract class UMLModelElement
{ kind : String; name : String; }class Package extends UMLModelElement
{ composes elements : PackageElement [*] ordered opposites namespace [1]; }abstract class PackageElement extends UMLModelElement {
}class Classifier extends PackageElement {
}class Attribute extends UMLModelElement
{ references type : Classifier [1]; }class Class extends Classifier
{ composes attribute : Attribute [*] ordered opposites owner [1]; references general : Classifier [*] ordered; }class Association extends PackageElement
{ source : Class [1] opposites reverse [*]; destination : Class [1] opposites forward [*]; }class PrimitiveDataType extends Classifier {
}}
metamodel SimpleRdbms {
abstract class RModelElement
{ kind : String; name : String; }class Schema extends RModelElement
{ composes tables : Table [*] ordered opposites schema [1]; }class Table extends RModelElement
{ composes column : Column [*] ordered opposites owner[1]; composes _key : Key [*] ordered opposites owner[1]; // '_key' is an automatic alias for 'key' composes foreignKey : ForeignKey [*] ordered opposites owner[1]; }class Column extends RModelElement
{ type : String; }class Key extends RModelElement
{ references column : Column [*] ordered opposites _key [*]; }class ForeignKey extends RModelElement
{ references refersTo : Key [1]; references column : Column [*] ordered opposites foreignKey [*]; }}
Below the transformation definition.
transformation Uml2Rdb(in srcModel:UML,out dest:RDBMS);
– Aliases to avoid name conflicts with keywords
{ name:String; kind:String; attr:UML::Attribute; }
tag "alias" RDBMS::Table::key_ = "key";
– defining intermediate data to reference leaf attributes that may
– appear when struct data types are used
intermediate class LeafAttribute;
intermediate property UML::Class::leafAttributes : Sequence(LeafAttribute);– defining specific helpers
query UML::Association::isPersistent() : Boolean
{ result = (self.source.kind='persistent' and self.destination.kind='persistent'); }– defining the default entry point for the module
– first the tables are created from classes, then the tables are
– updated with the foreign keys implied by the associationsmain()
{ srcModel.objects()[Class]->map class2table(); -- first pass srcModel.objects()[Association]->map asso2table(); -- second pass }– maps a class to a table, with a column per flattened leaf attribute
mapping Class::class2table () : Table
{self.kind='persistent';}
when{
{ -- performs any needed intialization self.leafAttributes := self.attribute ->map attr2LeafAttrs("",""); // ->flatten(); }
init– population section for the table
{ -- nested population section for a 'Key' name := 'k_'+ self.name; column := result.column[kind='primary']; }
name := 't_' + self.name;
column := self.leafAttributes->map leafAttr2OrdinaryColumn("");
key_ := object Key;
}– Mapping that creates the intermediate leaf attributes data.
mapping Attribute::attr2LeafAttrs (in prefix:String,in pkind:String)
{attr:=self;name:=prefix+self.name;kind:=k;}
: Sequence(LeafAttribute) {
init {
var k := if pkind="" then self.kind else pkind endif;
result :=
if self.type.isKindOf(PrimitiveDataType)
then – creates a sequence with a LeafAttribute instance
Sequence {
object LeafAttribute}
else self.type.asType(Class).attribute
>map attr2LeafAttrs(self.name+"_",k)>asSequence()
endif;
}
}– Mapping that creates an ordinary column from a leaf attribute
mapping LeafAttribute::leafAttr2OrdinaryColumn (in prefix:String): Column
{ name := prefix+self.name; kind := self.kind; type := if self.attr.type.name='int' then 'NUMBER' else 'VARCHAR' endif; }– mapping to update a Table with new columns of foreign keys
mapping Association::asso2table() : Table
{self.isPersistent();}
when{
{result := self.destination.resolveone(Table);}
initforeignKey := self.map asso2ForeignKey();
column := result.foreignKey->column ;
}– mapping to build the foreign keys
mapping Association::asso2ForeignKey() : ForeignKey
{ name := 'f_' + self.name; refersTo := self.source.resolveone(Table).key_; column := self.source.leafAttributes[kind='primary'] ->map leafAttr2ForeignColumn(self.source.name+'_'); }– Mapping to create a Foreign key from a leaf attributes
– Inheriting of leafAttr2OrdinaryColumn has the effect to call the
– inherited rule before entering the property population sectionmapping LeafAttribute::leafAttr2ForeignColumn (in prefix:String) : Column
{ kind := "foreign"; }
inherits leafAttr2OrdinaryColumn(5) Replaces the content of A2.4 by the following
modeltype UML uses "omg.org.spem_umlprofile";
modeltype SPEM uses "omg.org.spem_metamodel";
transformation SpemProfile2Metamodel(in umlmodel:UML,out spemmodel:SPEM);query UML::isStereotypedBy(stereotypeName:String) : Boolean;
query UML::Classifier::getOppositeAends() : Set(UML::AssociationEnd);main ()
{ -- first pass: create all the SPEM elements from UML elements umlmodel.rootobjects()[UML::Model]->map createDefaultPackage(); -- second pass: add the dependencies beyween SPEM elements umlmodel.objects[UML::UseCase]->map addDependenciesInWorkDefinition(); }mapping UML::Package::createDefaultPackage () : SPEM::Package
{ name := self.name; ownedElement := self.ownedElement->map createModelElement(); }mapping UML::Package::createProcessComponent () : SPEM::ProcessComponent
{self.isStereotypedBy("ProcessComponent");}
inherits createDefaultPackage
when{}
mapping UML::Package::createDiscipline () : SPEM::Discipline
{self.isStereotypedBy("Discipline");}
inherits createDefaultPackage
when
{}mapping UML::ModelElement::createModelElement () : SPEM::ModelElement
disjuncts
createProcessRole, createWorkDefinition,
createProcessComponent, createDiscipline
{}mapping UML::UseCase::createWorkDefinition () : SPEM::WorkDefinition
disjuncts
createLifeCycle, createPhase, createIteration,
createActivity, createCompositeWorkDefinition
{}mapping UML::Actor::createProcessRole () : SPEM::ProcessRole
{self.isStereotypedBy("ProcessRole");}
when{}
– rule to create the default process performer singleton
{ result := resolveoneByRule(createOrRetrieveDefaultPerformer); if result then return endif; }
mapping createOrRetrieveDefaultPerformer () : SPEM::ProcessPerformer {
initname := "ProcessPerformer";
}mapping abstract UML::UseCase::createCommonWorkDefinition ()
{ self.constraint[isStereotypedBy("precondition")] ->map createPrecondition(); self.constraint[isStereotypedBy("goal")]->map createGoal(); }
: SPEM::WorkDefinition
{
name := self.name;
constraint :=;
}mapping UML::UseCase::createActivity () : SPEM::WorkDefinition
{self.isStereotypedBy("Activity");}
inherits createCommonWorkDefinition
when{}
mapping UML::UseCase::createPhase () : SPEM::Phase
{self.isStereotypedBy("Phase");}
inherits createCommonWorkDefinition
when{}
mapping UML::UseCase::createIteration () : SPEM::Iteration
{self.isStereotypedBy("Iteration");}
inherits createCommonWorkDefinition
when{}
mapping UML::UseCase::createLifeCycle () : SPEM::LifeCycle
{self.isStereotypedBy("LifeCycle");}
inherits createCommonWorkDefinition
when{}
mapping UML::UseCase::createCompositeWorkDefinition () : SPEM::WorkDefinition
{self.isStereotypedBy("WorkDefinition");}
inherits createCommonWorkDefinition
when{}
mapping UML::Constraint::createPrecondition () : SPEM::Precondition
{ body := self.body; }mapping UML::Constraint::createGoal () : SPEM::Goal
{ body := self.body; }mapping UML::UseCase::addDependenciesInWorkDefinition ()
{ result := self.resolveone(WorkDefinition); var performers := self.getOppositeAends()[i|i.association [isStereotypedBy("perform")]->notEmpty()]; assert (not performers->size()>1) with log("A unique performer is allowed",self); }
: SPEM::WorkDefinition
merging addDependenciesInActivity
{
initsubWork := self.clientDependency[*includes].supplier
->resolveone(WorkDefinition);
performer := if performers then performers->first()
else createOrRetrieveDefaultPerformer() endif;
}mapping UseCase::addDependenciesInActivity () : WorkDefinition
{self.stereotypedBy("Activity");} { assistant := self.getOppositeAends()[i|i.association [a|a.isStereotypedBy("assist")]->notEmpty()]->resolve(); }
when -
Updated: Fri, 6 Mar 2015 20:54 GMT
QVT — QVTOperational examples have some errors and need to be inline with grammar
- Key: QVT-26
- OMG Task Force: MOF QVT FTF