QVT 1.0 NO IDEA Avatar
  1. OMG Issue

QVT — QVTOperational examples have some errors and need to be inline with grammar

  • 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 {
    class Book

    {title: String; composes chapters: Chapter [*];}

    class Chapter

    {title : String; nbPages : Integer;}

    }

    metamodel PUB {
    class Publication

    {title : String; nbPages : Integer;}

    }

    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 methods

    modeltype 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 package

    main()

    { classModel.objectsOfType(Package) ->map encapsulateAttributesInPackageClasses(); }

    – Applies the transformation to each class of the package

    mapping inout Package::encapsulateAttributesInPackageClasses () {
    init

    {self.ownedElement->map encapsulateAttributesInClass();}

    }

    – 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 attribute

    mapping inout Class::encapsulateAttributesInClass ()
    {
    init

    { var attrs := self.feature[Attribute];}

    operation := { – assignment with additive semantics
    attrs->object(a) Operation

    { name := "get_" + self.name.upperFirst(); visibility := "public"; type := a.type; }

    ;
    attrs->object(a) Operation {
    name := "set_" + self.name.upperFirst();
    visibility := "public";
    parameter := object Parameter

    { name := 'a_'+ self.name.upperFirst(); kind := "in"; type := a.type;}

    ;
    };
    };
    end

    { attrs->map privatizeAttribute();}

    }

    – 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
    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

    { name:String; kind:String; attr:UML::Attribute; }

    ;
    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 associations

    main()

    { 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
    when

    {self.kind='persistent';}

    {
    init

    { -- performs any needed intialization self.leafAttributes := self.attribute ->map attr2LeafAttrs("",""); // ->flatten(); }

    – population section for the table
    name := 't_' + self.name;
    column := self.leafAttributes->map leafAttr2OrdinaryColumn("");
    key_ := object Key

    { -- nested population section for a 'Key' name := 'k_'+ self.name; column := result.column[kind='primary']; }

    ;
    }

    – Mapping that creates the intermediate leaf attributes data.

    mapping Attribute::attr2LeafAttrs (in prefix:String,in pkind:String)
    : 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

    {attr:=self;name:=prefix+self.name;kind:=k;}

    }
    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
    when

    {self.isPersistent();}

    {
    init

    {result := self.destination.resolveone(Table);}

    foreignKey := 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 section

    mapping LeafAttribute::leafAttr2ForeignColumn (in prefix:String) : Column
    inherits leafAttr2OrdinaryColumn

    { kind := "foreign"; }

    (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
    inherits createDefaultPackage
    when

    {self.isStereotypedBy("ProcessComponent");}

    {}

    mapping UML::Package::createDiscipline () : SPEM::Discipline
    inherits createDefaultPackage
    when

    {self.isStereotypedBy("Discipline");}


    {}

    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
    when

    {self.isStereotypedBy("ProcessRole");}

    {}

    – rule to create the default process performer singleton
    mapping createOrRetrieveDefaultPerformer () : SPEM::ProcessPerformer {
    init

    { result := resolveoneByRule(createOrRetrieveDefaultPerformer); if result then return endif; }

    name := "ProcessPerformer";
    }

    mapping abstract UML::UseCase::createCommonWorkDefinition ()
    : SPEM::WorkDefinition
    {
    name := self.name;
    constraint :=

    { self.constraint[isStereotypedBy("precondition")] ->map createPrecondition(); self.constraint[isStereotypedBy("goal")]->map createGoal(); }

    ;
    }

    mapping UML::UseCase::createActivity () : SPEM::WorkDefinition
    inherits createCommonWorkDefinition
    when

    {self.isStereotypedBy("Activity");}

    {}

    mapping UML::UseCase::createPhase () : SPEM::Phase
    inherits createCommonWorkDefinition
    when

    {self.isStereotypedBy("Phase");}

    {}

    mapping UML::UseCase::createIteration () : SPEM::Iteration
    inherits createCommonWorkDefinition
    when

    {self.isStereotypedBy("Iteration");}

    {}

    mapping UML::UseCase::createLifeCycle () : SPEM::LifeCycle
    inherits createCommonWorkDefinition
    when

    {self.isStereotypedBy("LifeCycle");}

    {}

    mapping UML::UseCase::createCompositeWorkDefinition () : SPEM::WorkDefinition
    inherits createCommonWorkDefinition
    when

    {self.isStereotypedBy("WorkDefinition");}

    {}

    mapping UML::Constraint::createPrecondition () : SPEM::Precondition

    { body := self.body; }

    mapping UML::Constraint::createGoal () : SPEM::Goal

    { body := self.body; }

    mapping UML::UseCase::addDependenciesInWorkDefinition ()
    : SPEM::WorkDefinition
    merging addDependenciesInActivity
    {
    init

    { 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); }

    subWork := self.clientDependency[*includes].supplier
    ->resolveone(WorkDefinition);
    performer := if performers then performers->first()
    else createOrRetrieveDefaultPerformer() endif;
    }

    mapping UseCase::addDependenciesInActivity () : WorkDefinition
    when

    {self.stereotypedBy("Activity");} { assistant := self.getOppositeAends()[i|i.association [a|a.isStereotypedBy("assist")]->notEmpty()]->resolve(); }
  • Updated: Fri, 6 Mar 2015 20:54 GMT