KDMtoUML.atl
757 lines (687 with data), 25.3 kB
-- @atlcompiler atl2006
-- @nsURI uml=http://www.eclipse.org/uml2/2.1.0/UML
-- @nsURI kdm=http://www.eclipse.org/MoDisco/kdm
--authors: Gabriel Barbier, Mia-Software, gbarbier@mia-software.com
--Transform KDM Models to UML 2.1 models
module KDMtoUML;
create OUT : uml from IN : kdm;
-- specific case to attach all single elements to root model
entrypoint rule initExternalElementsContainer() {
-- to externalPackage :uml!Package(
-- name <- 'detached elements'
-- ,packagedElement <- externalClass
-- )
-- ,externalClass :uml!Class(
-- name <- 'detached elements'
-- )
-- do {
-- thisModule.externalPackage <- externalPackage;
-- thisModule.externalClass <- externalClass;
-- }
}
helper def : findExternalPackage() : kdm!CodeModel =
kdm!Segment.allInstances()->select(e | e.refImmediateComposite().oclIsUndefined())
->collect(e | e.model)->flatten()
->select(e | e.name = 'externals')
-->collect(e | e.codeElement)->flatten()
-->select(e | e.name = 'detached elements')
->first();
endpoint rule manageDetachedElements() {
do {
if (not thisModule->findExternalPackage().oclIsUndefined()) {
thisModule.externalPackage <- thisModule.resolveTemp(thisModule->findExternalPackage(), 'tgt');
for (detachedClass in thisModule->findExternalPackage().codeElement) {
if (detachedClass.name = 'detached elements') {
thisModule.externalClass <- thisModule.resolveTemp(detachedClass, 'tgt');
}
}
for (alone in uml!Element.allInstances()) {
if (not (alone.oclIsTypeOf(uml!Model))) {
if (alone.refImmediateComposite().oclIsUndefined()) {
if (alone.oclIsKindOf(uml!PackageableElement)) {
thisModule.externalPackage.packagedElement <- alone;
} else {
if (not thisModule.externalClass.oclIsUndefined()) {
if (alone.oclIsKindOf(uml!Generalization)) {
thisModule.externalClass.generalization <- alone;
}
if (alone.oclIsKindOf(uml!Operation)) {
thisModule.externalClass.ownedOperation <- alone;
}
if (alone.oclIsKindOf(uml!Property)) {
thisModule.externalClass.ownedAttribute <- alone;
}
}
}
}
}
}
}
}
}
helper def: externalPackage : uml!Package = OclUndefined;
helper def: externalClass : uml!Class = OclUndefined;
--------------------------Helpers--------------------------------------------------------------------------------------------------
helper context kdm!Element def : getVisibility() : uml!VisibilityKind =
if (self.oclIsTypeOf(kdm!MethodUnit)) then
self->getMethodVisibility()
else
if (self.oclIsTypeOf(kdm!Datatype)) then
self->getDatatypeVisibility()
else
#public
endif
endif;
helper context kdm!MethodUnit def : getMethodVisibility() : uml!VisibilityKind =
if (self.export = #private) then
#private
else
if (self.export = #protected) then
#protected
else
#public
endif
endif;
helper context kdm!Datatype def : getDatatypeVisibility() : uml!VisibilityKind =
let attribute : kdm!Attribute = self.attribute->select(e | e.tag = 'visibility')->first() in
if (attribute.oclIsUndefined()) then
#public
else
let value : String = attribute.value in
if (value = 'private') then
#private
else
if (value = 'protected') then
#protected
else
#public
endif
endif
endif;
helper context kdm!DataElement def : getLowerCardinality() : Integer =
let attribute : kdm!Attribute = self.attribute->select(e | e.tag = 'inheritance')->first() in
if (attribute.oclIsUndefined()) then
0
else
if (attribute.value = 'final') then
1
else
0
endif
endif;
-- depends on type of DataElement
helper context kdm!DataElement def : getUpperCardinality() : Integer =
if (not self.size.oclIsUndefined()) then
self.size
else
if (not self.type.oclIsUndefined()) then
if (self.type.oclIsKindOf(kdm!ArrayType)) then
-1
else
if (self.type.oclIsTypeOf(kdm!TemplateType)) then
if (self.type->isCollection() or self.type->isMap()) then
-1
else
1
endif
else
1
endif
endif
else
1
endif
endif;
helper context kdm!Datatype def : isCollection() : Boolean =
if (self.name.oclIsUndefined()) then
false
else
if (self.name->startsWith('Collection')) then
true
else
if (self.oclIsTypeOf(kdm!TemplateType)) then
self->getTemplateUnit()->isCollection()
else
if (self.oclIsTypeOf(kdm!TemplateUnit)) then
self->getRealType()->isCollection()
else
if (self->getInheritanceLinks()->isEmpty()) then
false
else
let parents : Sequence(kdm!AbstractCodeRelationship) = self->getInheritanceLinks() in
parents->exists(parent | parent.to->isCollection())
endif
endif
endif
endif
endif;
helper context kdm!Datatype def : isMap() : Boolean =
if (self.name.oclIsUndefined()) then
false
else
if (self.name->startsWith('Map')) then
true
else
if (self.oclIsTypeOf(kdm!TemplateType)) then
self->getTemplateUnit()->isMap()
else
if (self.oclIsTypeOf(kdm!TemplateUnit)) then
self->getRealType()->isMap()
else
if (self->getInheritanceLinks()->isEmpty()) then
false
else
let parents : Sequence(kdm!AbstractCodeRelationship) = self->getInheritanceLinks() in
parents->exists(parent | parent.to->isMap())
endif
endif
endif
endif
endif;
helper context kdm!Datatype def : getInheritanceLinks() : Sequence(kdm!AbstractCodeRelationship) =
if ((self.oclIsTypeOf(kdm!EnumeratedType)) or (self.oclIsTypeOf(kdm!ClassUnit))
or (self.oclIsTypeOf(kdm!InterfaceUnit)) or (self.oclIsTypeOf(kdm!TemplateUnit))) then
self.codeRelation->select(e | e.oclIsTypeOf(kdm!Extends) or e.oclIsTypeOf(kdm!Implements))
else
Sequence{}
endif;
helper context kdm!TemplateType def : getTemplateUnit() : kdm!Datatype =
let link : kdm!InstanceOf = self.codeRelation->select(e | e.oclIsTypeOf(kdm!InstanceOf))->first() in
if (link.oclIsUndefined()) then
OclUndefined
else
if (link.to.oclIsUndefined()) then
let otherLink : kdm!HasType = self.codeRelation->select(e | e.oclIsTypeOf(kdm!HasType))->first() in
if (otherLink.oclIsUndefined()) then
OclUndefined
else
otherLink.to
endif
else
link.to
endif
endif;
helper context kdm!TemplateUnit def : getRealType() : kdm!CodeItem =
self.codeElement->select(e | not e.oclIsTypeOf(kdm!TemplateParameter))->first();
helper context kdm!InterfaceUnit def : getRealType() : kdm!Datatype =
self;
helper context kdm!ClassUnit def : getRealType() : kdm!Datatype =
self;
helper context kdm!CodeItem def : getPackageContainer() : kdm!Package =
if (self.refImmediateComposite().oclIsTypeOf(kdm!Package)) then
self.refImmediateComposite()
else
if (self.refImmediateComposite().oclIsKindOf(kdm!CodeItem)) then
self.refImmediateComposite()->getPackageContainer()
else
thisModule->findExternalPackage()
endif
endif;
helper context kdm!DataElement def : getDataElementType() : kdm!Datatype =
if (self.type.oclIsTypeOf(kdm!TemplateType)) then
if (self.type->isCollection() or self.type->isMap()) then
self.type->getTemplateTypeBinding()
else
self.type
endif
else
if (self.type.oclIsTypeOf(kdm!ArrayType)) then
self.type.itemUnit.type
else
self.type
endif
endif;
helper context kdm!DataElement def : getDataElementQualifierType() : kdm!Datatype =
if (self.type.oclIsTypeOf(kdm!TemplateType)) then
if (self.type->isMap()) then
self.type.codeRelation->select(e | e.oclIsTypeOf(kdm!ParameterTo))->first().to
else
OclUndefined
endif
else
OclUndefined
endif;
helper context kdm!TemplateType def : getTemplateTypeBinding() : kdm!Datatype =
let parameter : kdm!ParameterTo = self.codeRelation->select(e | e.oclIsTypeOf(kdm!ParameterTo))->last() in
if (parameter.to.oclIsTypeOf(kdm!TemplateType)) then
if (parameter.to->isCollection() or parameter.to->isMap()) then
parameter.to->getTemplateTypeBinding()
else
parameter.to
endif
else
parameter.to
endif;
helper context kdm!Datatype def : isPrimitiveType() : Boolean =
if (self.oclIsUndefined() or (self.oclIsKindOf(kdm!PrimitiveType))) then
true
else
-- specific case for primitive objects
if ((self.name = 'String') or (self.name = 'Integer')
or (self.name = 'Long') or (self.name = 'Short')
or (self.name = 'Float') or (self.name = 'Double')
or (self.name = 'Boolean') or (self.name = 'Number')) then
true
else
false
endif
endif;
--------------------------End-Helpers-----------------------------------------------------------------------------------------------------------------------------------------
--------------------------Rules-----------------------------------------------------------------------------------------------------------------------------------------------
rule SegmentToRootModel {
from src :kdm!Segment
to tgt :uml!Model(
name<- if (src.name.oclIsUndefined()) then 'root model' else src.name endif
,packagedElement<-src.segment
,packagedElement<-src.model
,packagedElement<-src.extension
-- contains external elements
-- ,packagedElement<- if (src.refImmediateComposite().oclIsUndefined()) then
-- thisModule.externalPackage
-- else Sequence{} endif
)
}
rule ExtensionFamilyToProfile {
from src :kdm!ExtensionFamily
to tgt :uml!Profile (
name <- src.name
,packagedElement <- src.annotation
,packagedElement <- src.attribute
,packagedElement <- src.stereotype
)
}
rule KDMModelToModel {
from src :kdm!KDMModel
to tgt :uml!Model (
name <- src.name
,packagedElement <- src.extension
,packagedElement <- src.ownedElement
)
}
--------------------------------End-Rules------------------------------------
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- Specific rules for source package in KDM metamodel------------------------
rule InventoryModelToModel extends KDMModelToModel {
from src :kdm!InventoryModel
to tgt :uml!Model (
packagedElement <- src.inventoryElement
)
}
--rule SourceFileToArtifact extends KDMEntityToNamedElement {
-- from src :kdm!SourceFile
-- to tgt :uml!Artifact (
-- fileName <- src.path
-- )
--}
rule InventoryItemToArtifact extends KDMEntityToNamedElement {
from src :kdm!InventoryItem
to tgt :uml!Artifact (
fileName <- src.path
)
}
rule InventoryContainerToPackage extends KDMEntityToNamedElement {
from src :kdm!InventoryContainer
to tgt :uml!Package (
packagedElement <- src.inventoryElement
)
}
--------------------------------End-Rules------------------------------------
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
---Specific rules for code package in KDM metamodel--------------------------
rule CodeModelToModel extends KDMModelToModel {
from src :kdm!CodeModel
to tgt :uml!Model (
packagedElement <- src.codeElement
)
}
abstract rule KDMEntityToNamedElement {
from src :kdm!KDMEntity
to tgt :uml!NamedElement (
name <- src.name
,visibility <- src->getVisibility()
)
}
-- to manage LanguageUnit and Package
rule ModuleToPackage extends KDMEntityToNamedElement {
from src :kdm!Module
to tgt :uml!Package (
packagedElement <- src.codeElement
)
}
-- to manage all primitive types (Boolean, Integer, Void, ...)
rule PrimitiveTypeToPrimitiveType extends KDMEntityToNamedElement {
from src :kdm!PrimitiveType
to tgt :uml!PrimitiveType ()
}
-- we have to filter dummy class only needed in kdm to manage behaviour element in StorableUnit
rule ClassUnitToClass extends KDMEntityToNamedElement {
from src :kdm!ClassUnit (
not src.refImmediateComposite().oclIsTypeOf(kdm!TemplateUnit)
and not (src.refImmediateComposite().oclIsTypeOf(kdm!StorableUnit))
)
to tgt :uml!Class (
isAbstract <- src.isAbstract
-- specific case to manage templated methods (encapsulated in a TemplateUnit)
,nestedClassifier <- src.codeElement->select(e | e.oclIsKindOf(kdm!Datatype))
->select(e | if (e.oclIsTypeOf(kdm!TemplateUnit)) then not (e->getRealType().oclIsTypeOf(kdm!MethodUnit)) else true endif)
,generalization <- src.codeRelation->select(e | e.oclIsTypeOf(kdm!Extends))
,interfaceRealization <- src.codeRelation->select(e | e.oclIsTypeOf(kdm!Implements))
,ownedOperation <- src.codeElement->select(e | e.oclIsTypeOf(kdm!MethodUnit))
,ownedAttribute <- src.codeElement->select(e | e.oclIsKindOf(kdm!DataElement))
)
}
rule InterfaceUnitToInterface extends KDMEntityToNamedElement {
from src :kdm!InterfaceUnit (not src.refImmediateComposite().oclIsTypeOf(kdm!TemplateUnit))
to tgt :uml!Interface (
-- specific case to manage templated methods (encapsulated in a TemplateUnit)
nestedClassifier <- src.codeElement->select(e | e.oclIsKindOf(kdm!Datatype))
->select(e | if (e.oclIsTypeOf(kdm!TemplateUnit)) then not (e->getRealType().oclIsTypeOf(kdm!MethodUnit)) else true endif)
,generalization <- src.codeRelation->select(e | e.oclIsTypeOf(kdm!Extends))
,ownedOperation <- src.codeElement->select(e | e.oclIsTypeOf(kdm!MethodUnit))
,ownedAttribute <- src.codeElement->select(e | e.oclIsKindOf(kdm!DataElement))
)
}
rule EnumeratedTypeToEnumeration extends KDMEntityToNamedElement {
from src :kdm!EnumeratedType
to tgt :uml!Enumeration (
ownedLiteral <- src.value
)
}
abstract rule TemplateUnitToTemplateableElement {
from src :kdm!TemplateUnit
-- to tgt :uml!TemplateableElement (
-- ownedTemplateSignature <- signature
-- )
to signature :uml!RedefinableTemplateSignature (
name <- src.name
,ownedParameter <- src.codeElement->select(e | e.oclIsTypeOf(kdm!TemplateParameter))
->collect(parameter | thisModule->TemplateParameterToClassifierTemplateParameter(parameter))
)
}
lazy rule TemplateParameterToClassifierTemplateParameter {
from src :kdm!TemplateParameter
to tgt :uml!ClassifierTemplateParameter (
-- name is not managed in UML
ownedParameteredElement <- parameter
)
, parameter :uml!Class (
name <- src.name
)
}
rule TemplateUnitToClass extends TemplateUnitToTemplateableElement {
from src :kdm!TemplateUnit (
src->getRealType().oclIsTypeOf(kdm!ClassUnit)
)
using {
realType :kdm!Datatype = src->getRealType();
}
to tgt :uml!Class (
name <- realType.name
,isAbstract <- realType.isAbstract
-- specific case to manage templated methods (encapsulated in a TemplateUnit)
,nestedClassifier <- realType.codeElement->select(e | e.oclIsKindOf(kdm!Datatype))
->select(e | if (e.oclIsTypeOf(kdm!TemplateUnit)) then not (e->getRealType().oclIsTypeOf(kdm!MethodUnit)) else true endif)
,generalization <- realType.codeRelation->select(e | e.oclIsTypeOf(kdm!Extends))
,interfaceRealization <- realType.codeRelation->select(e | e.oclIsTypeOf(kdm!Implements))
,ownedOperation <- realType.codeElement->select(e | e.oclIsTypeOf(kdm!MethodUnit))
,ownedAttribute <- realType.codeElement->select(e | e.oclIsKindOf(kdm!DataElement))
)
}
rule TemplateUnitToInterface extends TemplateUnitToTemplateableElement {
from src :kdm!TemplateUnit (
src->getRealType().oclIsTypeOf(kdm!InterfaceUnit)
)
using {
realType :kdm!Datatype = src->getRealType();
}
to tgt :uml!Interface (
name <- realType.name
-- specific case to manage templated methods (encapsulated in a TemplateUnit)
,nestedClassifier <- realType.codeElement->select(e | e.oclIsKindOf(kdm!Datatype))
->select(e | if (e.oclIsTypeOf(kdm!TemplateUnit)) then not (e->getRealType().oclIsTypeOf(kdm!MethodUnit)) else true endif)
,generalization <- realType.codeRelation->select(e | e.oclIsTypeOf(kdm!Extends))
,ownedOperation <- realType.codeElement->select(e | e.oclIsTypeOf(kdm!MethodUnit))
,ownedAttribute <- realType.codeElement->select(e | e.oclIsKindOf(kdm!DataElement))
)
}
rule ExtendsToGeneralization {
from src :kdm!Extends
to tgt :uml!Generalization (
general <- src.to
)
}
rule ImplementsToInterfaceRealization {
from src :kdm!Implements
to tgt :uml!InterfaceRealization (
contract <- if (src.to.oclIsTypeOf(kdm!ClassUnit)) then OclUndefined else src.to endif
)
do {
if (src.to.oclIsTypeOf(kdm!ClassUnit)) {
src.from->debug('Invalid implements, from ');
src.to->debug('to ');
}
}
}
rule ImportsToDependency {
from src :kdm!Imports
to tgt :uml!Dependency (
client <- src.from
,supplier <- src.to
)
do {
-- store the created dependency in first parent package of client element
thisModule.resolveTemp(src.from->getPackageContainer(), 'tgt').packagedElement <- tgt;
}
}
rule TemplateTypeToInterface {
from src : kdm ! TemplateType (
if (src->getTemplateUnit() = OclUndefined) then
false
else
src->getTemplateUnit()->getRealType().oclIsTypeOf(kdm!InterfaceUnit)
endif
)
to tgt :uml!Interface(
name<-src.name
,templateBinding <- src.codeRelation->select(e | e.oclIsTypeOf(kdm!ParameterTo))
)
do {
thisModule.resolveTemp(src->getTemplateUnit()->getPackageContainer(), 'tgt').packagedElement <- tgt;
}
}
rule TemplateTypeToClass {
from src : kdm ! TemplateType (
if (src->getTemplateUnit() = OclUndefined) then
false
else
not src->getTemplateUnit()->getRealType().oclIsTypeOf(kdm!InterfaceUnit)
endif
)
to tgt :uml!Class(
name<-src.name
,templateBinding <- src.codeRelation->select(e | e.oclIsTypeOf(kdm!ParameterTo))
)
do {
thisModule.resolveTemp(src->getTemplateUnit()->getPackageContainer(), 'tgt').packagedElement <- tgt;
}
}
rule ParameterToToTemplateBinding {
from src :kdm!ParameterTo (src.from->getTemplateUnit().oclIsTypeOf(kdm!TemplateUnit))
to tgt :uml!TemplateBinding (
signature <- thisModule.resolveTemp(src.from->getTemplateUnit(), 'signature')
,parameterSubstitution <- substitution
)
, substitution :uml!TemplateParameterSubstitution (
-- actual <- src.to
--,formal <- src.from->getTemplateUnit().codeElement->at(src.from.codeRelation->indexOf(src))
)
do {
substitution.formal <- tgt.signature.ownedParameter->at(src.from.codeRelation->indexOf(src));
}
}
--------------------------------End-Rules------------------------------------
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
-- ##########################################################################
---Specific rules for code package in KDM metamodel, dedicated to members----
rule ValueToEnumerationLiteral {
from src :kdm!Value (src.refImmediateComposite().oclIsTypeOf(kdm!EnumeratedType))
to tgt :uml!EnumerationLiteral (
name <- src.name
)
}
-- we have to filter dummy operations (needed in KDM to store behaviour)
rule MethodUnitToOperation extends KDMEntityToNamedElement {
from src :kdm!MethodUnit (
not src.refImmediateComposite().oclIsTypeOf(kdm!TemplateUnit)
and not (src.type.oclIsUndefined())
and not (src.refImmediateComposite().oclIsTypeOf(kdm!CodeModel)) -- Unresolved items
)
to tgt :uml!Operation (
ownedParameter <- src.type.parameterUnit
)
}
rule TemplateUnitToOperation extends TemplateUnitToTemplateableElement {
from src :kdm!TemplateUnit (
src->getRealType().oclIsTypeOf(kdm!MethodUnit)
)
using {
realType :kdm!MethodUnit = src->getRealType();
}
to tgt :uml!Operation (
name <- realType.name
,visibility <- src->getVisibility()
,ownedParameter <- realType.type.parameterUnit
)
}
rule ParameterUnitToParameter extends KDMEntityToNamedElement {
from src :kdm!ParameterUnit
to tgt :uml!Parameter (
direction <- if (src.kind = #return) then #return else OclUndefined endif
-- ,type <- src->getDataElementType()
,lowerValue <- lower
,upperValue <- upper
)
, lower : uml!LiteralInteger (
value <- src.getLowerCardinality()
)
, upper : uml! LiteralUnlimitedNatural (
value <- src.getUpperCardinality()
)
}
rule MemberUnitToProperty extends KDMEntityToNamedElement {
from src :kdm!MemberUnit
to tgt :uml!Property (
type <- src->getDataElementType()
,lowerValue <- lower
,upperValue <- upper
)
, lower : uml!LiteralInteger (
value <- src.getLowerCardinality()
)
, upper : uml! LiteralUnlimitedNatural (
value <- src.getUpperCardinality()
)
do {
if (not (src->getDataElementType().oclIsUndefined())) {
if (not (src->getDataElementType()->isPrimitiveType())) {
thisModule->DataElementToAssociation(src);
}
if (not (src->getDataElementQualifierType().oclIsUndefined())) {
tgt.qualifier <- thisModule.DatatypeToProperty(src->getDataElementQualifierType());
}
}
}
}
rule StorableUnitToProperty extends KDMEntityToNamedElement {
from src :kdm!StorableUnit (not (src.kind = #local)
and not (src.refImmediateComposite().oclIsTypeOf(kdm!CodeModel))) -- Unresolved items
to tgt :uml!Property (
-- type <- src->getDataElementType(),
isStatic <- if (src.kind = #static) then true else false endif
,lowerValue <- lower
,upperValue <- upper
)
, lower : uml!LiteralInteger (
value <- src.getLowerCardinality()
)
, upper : uml! LiteralUnlimitedNatural (
value <- src.getUpperCardinality()
)
do {
if (not (src->getDataElementType().oclIsUndefined())) {
if (not (src->getDataElementType()->isPrimitiveType())) {
thisModule->DataElementToAssociation(src);
}
if (not (src->getDataElementQualifierType().oclIsUndefined())) {
tgt.qualifier <- thisModule.DatatypeToProperty(src->getDataElementQualifierType());
}
}
}
}
lazy rule DataElementToAssociation {
from src :kdm!DataElement
to tgt :uml!Association (
memberEnd<- src
,memberEnd <- targetProperty
,ownedEnd <- targetProperty
)
, targetProperty :uml!Property (
-- type <- src.refImmediateComposite()
)
do {
thisModule.resolveTemp(src->getPackageContainer(), 'tgt').packagedElement <- tgt;
}
}
-- to create qualifier for a parent property
lazy rule DatatypeToProperty {
from src :kdm!Datatype
to tgt :uml!Property (
name <- 'qualifier'
,type <- src
)
}
--------------------------------End-Rules------------------------------------