blob: e9756c7848c5ad3a377c9d201fab7e49edf6d9b5 [file] [log] [blame]
-- @atlcompiler atl2006
-- author : Gabriel Barbier, Mia-Software, gbarbier@mia-software.com
-- recreates bidirectionnal associations from unidirectionnal associations
-- @nsURI uml=http://www.eclipse.org/uml2/2.1.0/UML
module BidirectionalAssociation; --superimpose UML2Copy
create umlOutput:uml from umlInput:uml;
helper def : bidirectionalAssociations : Set(uml!Association) = uml!Association.allInstancesFrom('umlInput')->select(
association | association->isBidirectional());
helper def : uselessProperties : Set(uml!Property) = thisModule.bidirectionalAssociations->collect(association | association.ownedEnd)->flatten();
helper def : uselessAssociations : Set(uml!Association) = OrderedSet {};
helper context uml!Association def: isBidirectional() : Boolean =
let sourceClass:uml!Class = self.endType->first() in (
if (sourceClass.oclIsUndefined()) then
false
else
let targetClass:uml!Class = self.endType->last() in (
if (targetClass.oclIsUndefined()) then
false
else
if (sourceClass = targetClass) then
-- self association, so to have a bidirectional association
-- we have to have a collection of property which type is sourceClass
-- and which is linked to an association
-- and this collection shall have a size equals to 2
(sourceClass.attribute->select(
attribute | (attribute.type = sourceClass)
and (not attribute.association.oclIsUndefined()))->size() = 2)
else
-- so we are looking to have exactly one property
-- which type is the opposite class in each class
(sourceClass.attribute->select(
attribute | (attribute.type = targetClass)
and (not attribute.association.oclIsUndefined()))->size() = 1)
and
(targetClass.attribute->select(
attribute | (attribute.type = sourceClass)
and (not attribute.association.oclIsUndefined()))->size() = 1)
endif
endif
)
endif);
helper context uml!Association def: getOppositeAssociation() : uml!Association =
if (self->isBidirectional()) then
thisModule.bidirectionalAssociations->select(association |
(not (association = self)) and (self.endType->includesAll(association.endType))
)->first()
else
self
endif;
-- initialize collection of useless association and property
entrypoint rule init() {
do {
for (association in thisModule.bidirectionalAssociations) {
if (thisModule.uselessAssociations->excludes(association)
and thisModule.uselessAssociations->excludes(association->getOppositeAssociation())) {
--association->toString().output();
--association->getOppositeAssociation()->toString().output();
-- finally, we will flag useless association and property
-- (only one association, but useless property of both associations)
thisModule.uselessAssociations <- thisModule.uselessAssociations->append(association);
--thisModule.uselessProperties <- thisModule.uselessProperties->union(association.ownedEnd);
--thisModule.uselessProperties <- thisModule.uselessProperties->union(association->getOppositeAssociation().ownedEnd);
} -- else nothing to do
}
}
}
-- copy association that are not bidirectional
rule Association {
from s : uml!"uml::Association" (
if (thisModule.inElements->includes(s))
then
if (s.oclIsTypeOf(uml!"uml::Association"))
then
-- add specific test
not s->isBidirectional()
else
false
endif
else false
endif)
to t : uml!"uml::Association" mapsTo s (
name <- s.name,
visibility <- s.visibility,
isLeaf <- s.isLeaf,
isAbstract <- s.isAbstract,
isDerived <- s.isDerived,
eAnnotations <- s.eAnnotations,
ownedComment <- s.ownedComment,
clientDependency <- s.clientDependency,
nameExpression <- s.nameExpression,
elementImport <- s.elementImport,
packageImport <- s.packageImport,
ownedRule <- s.ownedRule,
templateParameter <- s.templateParameter,
templateBinding <- s.templateBinding,
ownedTemplateSignature <- s.ownedTemplateSignature,
generalization <- s.generalization,
powertypeExtent <- s.powertypeExtent,
redefinedClassifier <- s.redefinedClassifier,
substitution <- s.substitution,
representation <- s.representation,
collaborationUse <- s.collaborationUse,
ownedUseCase <- s.ownedUseCase,
useCase <- s.useCase,
ownedEnd <- s.ownedEnd,
memberEnd <- s.memberEnd,
navigableOwnedEnd <- s.navigableOwnedEnd)
}
-- copy bidirectional association
rule BidirectionalAssociation {
from s : uml!"uml::Association" (
if (thisModule.inElements->includes(s))
then
if (s.oclIsTypeOf(uml!"uml::Association"))
then
(s->isBidirectional() and thisModule.uselessAssociations->excludes(s))
else
false
endif
else false
endif)
using {
-- if they are same, it may not be a problem
sourceClass:uml!Class = s.memberEnd->select(element | s.ownedEnd->includes(element))->first().type;
targetClass:uml!Class = s.memberEnd->select(element | s.ownedEnd->excludes(element))->first().type;
opposite:uml!Property = targetClass.attribute->select(attribute | attribute.type = sourceClass)->first();
}
to t : uml!"uml::Association" mapsTo s (
name <- sourceClass->toString() + ' to ' + targetClass->toString(),
visibility <- s.visibility,
isLeaf <- s.isLeaf,
isAbstract <- s.isAbstract,
isDerived <- s.isDerived,
eAnnotations <- s.eAnnotations,
ownedComment <- s.ownedComment,
clientDependency <- s.clientDependency,
nameExpression <- s.nameExpression,
elementImport <- s.elementImport,
packageImport <- s.packageImport,
ownedRule <- s.ownedRule,
templateParameter <- s.templateParameter,
templateBinding <- s.templateBinding,
ownedTemplateSignature <- s.ownedTemplateSignature,
generalization <- s.generalization,
powertypeExtent <- s.powertypeExtent,
redefinedClassifier <- s.redefinedClassifier,
substitution <- s.substitution,
representation <- s.representation,
collaborationUse <- s.collaborationUse,
ownedUseCase <- s.ownedUseCase,
useCase <- s.useCase,
-- do not retrieve elements of collection 'ownedEnd'
--ownedEnd <- s.ownedEnd,
-- and filter elements of collection 'memberEnd' to eliminate elements in collection 'ownedEnd'
memberEnd <- s.memberEnd->select(element | s.ownedEnd->excludes(element)),
-- and now we will add opposite property from other unidirectionnal association
memberEnd <- opposite,
navigableOwnedEnd <- s.navigableOwnedEnd)
do {
--('opposite property = ' + opposite->toString())->output();
t.name->output();
}
}
-- to filter useless property
rule Property {
from s : uml!"uml::Property" (
if thisModule.inElements->includes(s) then
if (s.oclIsTypeOf(uml!"uml::Property"))
then thisModule.uselessProperties->excludes(s)
else false
endif
else false endif)
to t : uml!"uml::Property" mapsTo s (
name <- s.name,
visibility <- s.visibility,
isLeaf <- s.isLeaf,
isStatic <- s.isStatic,
isOrdered <- s.isOrdered,
isUnique <- s.isUnique,
isReadOnly <- s.isReadOnly,
isDerived <- s.isDerived,
isDerivedUnion <- s.isDerivedUnion,
aggregation <- s.aggregation,
eAnnotations <- s.eAnnotations,
ownedComment <- s.ownedComment,
clientDependency <- s.clientDependency,
nameExpression <- s.nameExpression,
type <- s.type,
upperValue <- s.upperValue,
lowerValue <- s.lowerValue,
templateParameter <- s.templateParameter,
end <- s.end,
deployment <- s.deployment,
redefinedProperty <- s.redefinedProperty,
defaultValue <- s.defaultValue,
subsettedProperty <- s.subsettedProperty,
-- test to avoid link to deleted Association
association <- if (thisModule.uselessAssociations->excludes(s.association)) then
s.association
else
OclUndefined
endif,
qualifier <- s.qualifier)
}