-- @atlcompiler atl2006 -- $Id$ -- Implements the Observer profile. module UML2Observer; --extends UML2Copy create OUT : UML2 from IN : UML2, OBSERVER : UML2, UML2TYPES : UML2; uses UML2Copy; uses Strings; uses UML2; uses Mappings; -- ====================================================================== -- model-specific helpers begin -- ====================================================================== helper def : language : String = 'language'.value(); helper def : separator : String = 'separator'.value(); helper def : Observer : UML2!"uml::Interface" = 'observer::Observer'.interface(); helper def : ObserverName : String = thisModule.Observer.qualifiedName('separator'.value()); helper def : oclString : UML2!"uml::PrimitiveType" = 'String'.primitiveType(); helper def : oclAny : UML2!"uml::PrimitiveType" = 'OclAny'.primitiveType(); helper def : observables : Sequence(UML2!"Observer::Observable") = UML2!"Observer::Observable".allInstances(); helper def : observers : Sequence(UML2!"Observer::Observer") = UML2!"Observer::Observer".allInstances(); helper def : subscribes : Sequence(UML2!"Observer::subscribe") = UML2!"Observer::subscribe".allInstances(); helper def : accessors : Sequence(UML2!"Accessors::accessor") = UML2!"Accessors::accessor".allInstances(); helper context UML2!"uml::Classifier" def : isObservable : Boolean = thisModule.observables->exists(o|o.base_Classifier=self); helper context UML2!"uml::Classifier" def : isObserver : Boolean = thisModule.observers->exists(o|o.base_Classifier=self); helper context UML2!"uml::Association" def : isSubscribe : Boolean = thisModule.subscribes->exists(s|s.base_Association=self); helper context UML2!"uml::Dependency" def : isAccessor : Boolean = thisModule.accessors->exists(a|a.base_Dependency=self); helper context UML2!"uml::Dependency" def : accessor : Boolean = thisModule.accessors->any(a|a.base_Dependency=self); helper context UML2!"uml::Class" def : update() : String = self.handlers()->iterate(o; acc : String = ''|acc + o.update()); helper context UML2!"uml::Class" def : handlers() : Sequence(UML2!"uml::Operation") = self.ownedOperation->select(o| o.name.startsWith('on') and o.name.endsWith('Change') and o.name.size() > 8); helper context UML2!"uml::Operation" def : update() : String = self.name.updateBody(self.propertyName, self.parTypeName); helper context UML2!"uml::Operation" def : propertyName : String = self.name.substring(3, self.name.size() - 6); -- onPropertyChange -> Property helper context UML2!"uml::Operation" def : parTypeName : String = self.ownedParameter->first().type.qualifiedName(thisModule.separator); helper context UML2!"uml::Behavior" def : isNotifyMethod : Boolean = if self.specification.isAccessor then self.owner.isObservableKind else false endif; helper context UML2!"uml::Behavior" def : isSubscribeMethod : Boolean = if self.specification.isAccessor then if self.owner.isObserverKind then self.specification.isSubscriber else false endif else false endif; helper context UML2!"uml::Operation" def : accessorFor : UML2!"uml::Property" = self.accessorDependency.supplier->any(p| p.oclIsKindOf(UML2!"uml::Property")); helper context UML2!"uml::Operation" def : accessorDependency : UML2!"uml::Dependency" = self.clientDependency->any(d|d.isAccessor); helper context UML2!"uml::Operation" def : isAccessor : Boolean = not self.accessorDependency.oclIsUndefined(); helper context UML2!"uml::Classifier" def : isObservableKind : Boolean = if self.isObservable then true else self.generalization->exists(g|g.general.isObservableKind) endif; helper context UML2!"uml::Classifier" def : isObserverKind : Boolean = if self.isObserver then true else self.generalization->exists(g|g.general.isObserverKind) endif; helper context UML2!"uml::Operation" def : isSubscriber : Boolean = if self.isAccessor then self.accessorFor.hasSubscribesAssociation else false endif; helper context UML2!"uml::Property" def : hasSubscribesAssociation : Boolean = if self.association.oclIsUndefined() then false else self.association.isSubscribe endif; helper context UML2!"uml::Operation" def : notify(body : String) : String = let acc : UML2!"Accessor::accessor" = self.accessorDependency.accessor in if acc.kind = #remove then self.accessorFor.removerNotify(body) else if acc.kind = #add or acc.kind = #insert then self.accessorFor.adderNotify(body) else if acc.kind = #set then self.accessorFor.setterNotify(body) else body endif endif endif; helper context UML2!"uml::Property" def : setterNotify(body : String) : String = self.name.setterNotifyBody( self.type.qualifiedName(thisModule.separator), body, false); helper context UML2!"uml::Property" def : adderNotify(body : String) : String = self.name.adderNotifyBody( self.type.qualifiedName(thisModule.separator), body, self.isUnique, false); helper context UML2!"uml::Property" def : removerNotify(body : String) : String = self.name.removerNotifyBody( self.type.qualifiedName(thisModule.separator), body, false); helper context UML2!"uml::Operation" def : subscribe(body : String) : String = let acc : UML2!"Accessor::accessor" = self.accessorDependency.accessor in if acc.kind = #remove then self.accessorFor.name.removerSubscribeBody(body, false) else if acc.kind = #add or acc.kind = #insert then self.accessorFor.name.adderSubscribeBody(body) else if acc.kind = #set then self.accessorFor.name.setterSubscribeBody(body, false) else body endif endif endif; -- ====================================================================== -- model-specific helpers end -- ====================================================================== -- ====================================================================== -- transformation rules begin -- ====================================================================== rule Class { from s : UML2!"uml::Class" ( if thisModule.inElements->includes(s) then s.oclIsTypeOf(UML2!"uml::Class") and not s.isObservable else false endif) to t : UML2!"uml::Class" ( __xmiID__ <- s.__xmiID__, name <- s.name, visibility <- s.visibility, isLeaf <- s.isLeaf, isAbstract <- s.isAbstract, isActive <- s.isActive, 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, ownedAttribute <- s.ownedAttribute, ownedConnector <- s.ownedConnector, ownedBehavior <- s.ownedBehavior ->union(if s.isObserver then Set{thisModule.ObserverClass(s)} else Set{} endif), classifierBehavior <- s.classifierBehavior, interfaceRealization <- s.interfaceRealization, ownedTrigger <- s.ownedTrigger, nestedClassifier <- s.nestedClassifier, ownedOperation <- s.ownedOperation, ownedReception <- s.ownedReception) } rule ObservableClass { from s : UML2!"uml::Class" ( if thisModule.inElements->includes(s) then s.oclIsTypeOf(UML2!"uml::Class") and s.isObservable else false endif) to t : UML2!"uml::Class" ( __xmiID__ <- s.__xmiID__, name <- s.name.debug('ObservableClass'), visibility <- s.visibility, isLeaf <- s.isLeaf, isAbstract <- s.isAbstract, isActive <- s.isActive, 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, ownedAttribute <- s.ownedAttribute->union(Set{observers}), ownedConnector <- s.ownedConnector, ownedBehavior <- s.ownedBehavior ->union(Set{getBehavior, addBehavior, removeBehavior, notifyBehavior}) ->union(if s.isObserver then Set{thisModule.ObserverClass(s)} else Set{} endif), classifierBehavior <- s.classifierBehavior, interfaceRealization <- s.interfaceRealization, ownedTrigger <- s.ownedTrigger, nestedClassifier <- s.nestedClassifier, ownedOperation <- s.ownedOperation, ownedReception <- s.ownedReception), -- Observable functionality -- observers : UML2!"uml::Property" ( name <- 'observer', type <- thisModule.Observer, visibility <- #private, isUnique <- true, isOrdered <- true, upperValue <- observersUpper, lowerValue <- observersLower), observersUpper : UML2!"uml::LiteralUnlimitedNatural" ( value <- 0-1), observersLower : UML2!"uml::LiteralInteger" ( value <- 0), -- Get -- getOp : UML2!"uml::Operation" ( name <- 'getObservers', class <- s, visibility <- #public, ownedParameter <- Sequence{getPar}, concurrency <- #sequential), getPar : UML2!"uml::Parameter" ( name <- 'return', lowerValue <- getParLow, upperValue <- getParUp, type <- observers.type, effect <- #read, direction <- #return), getParLow : UML2!"uml::LiteralInteger" ( value <- 0), getParUp : UML2!"uml::LiteralUnlimitedNatural" ( value <- 0-1), getBehavior : UML2!"uml::OpaqueBehavior" ( specification <- getOp, name <- getOp.name + 'Behavior', ownedParameter <- Sequence{getBPar}, language <- Sequence{thisModule.language}, body <- Sequence{observers.name.multiGetterBody()}), getBPar : UML2!"uml::Parameter" ( name <- 'return', lowerValue <- getBParLow, upperValue <- getBParUp, type <- observers.type, effect <- #read, direction <- #return), getBParLow : UML2!"uml::LiteralInteger" ( value <- 0), getBParUp : UML2!"uml::LiteralUnlimitedNatural" ( value <- 0-1), -- Add -- addOp : UML2!"uml::Operation" ( name <- 'addObserver', class <- s, visibility <- #public, ownedParameter <- Sequence{addPar}, concurrency <- #sequential), addPar : UML2!"uml::Parameter" ( name <- observers.name, type <- observers.type, effect <- #update, direction <- #"in"), addBehavior : UML2!"uml::OpaqueBehavior" ( specification <- addOp, name <- addOp.name + 'Behavior', ownedParameter <- Sequence{addBPar}, language <- Sequence{thisModule.language}, body <- Sequence{observers.name.adderBody(observers.isUnique)}), addBPar : UML2!"uml::Parameter" ( name <- observers.name, type <- observers.type, effect <- #update, direction <- #"in"), -- Remove -- removeOp : UML2!"uml::Operation" ( name <- 'removeObserver', class <- s, visibility <- #public, ownedParameter <- Sequence{removePar}, concurrency <- #sequential), removePar : UML2!"uml::Parameter" ( name <- observers.name, type <- observers.type, effect <- #update, direction <- #"in"), removeBehavior : UML2!"uml::OpaqueBehavior" ( specification <- removeOp, name <- removeOp.name + 'Behavior', ownedParameter <- Sequence{removeBPar}, language <- Sequence{thisModule.language}, body <- Sequence{observers.name.removerBody()}), removeBPar : UML2!"uml::Parameter" ( name <- observers.name, type <- observers.type, effect <- #update, direction <- #"in"), -- Notify -- notifyOp : UML2!"uml::Operation" ( name <- 'notifyObservers', class <- s, visibility <- #public, ownedParameter <- Sequence{notifyPar1, notifyPar2}, concurrency <- #sequential), notifyPar1 : UML2!"uml::Parameter" ( name <- 'name', type <- thisModule.oclString, effect <- #read, direction <- #"in"), notifyPar2 : UML2!"uml::Parameter" ( name <- 'value', type <- thisModule.oclAny, effect <- #update, direction <- #"in"), notifyBehavior : UML2!"uml::OpaqueBehavior" ( specification <- notifyOp, name <- notifyOp.name + 'Behavior', ownedParameter <- Sequence{notifyBPar1, notifyBPar2}, language <- Sequence{thisModule.language}, body <- Sequence{thisModule.ObserverName.notifyObserversBody()}), notifyBPar1 : UML2!"uml::Parameter" ( name <- 'name', type <- thisModule.oclString, effect <- #read, direction <- #"in"), notifyBPar2 : UML2!"uml::Parameter" ( name <- 'value', type <- thisModule.oclAny, effect <- #update, direction <- #"in") } rule ObserverClass(s : UML2!"uml::Class") { to real : UML2!"uml::InterfaceRealization" ( contract <- thisModule.Observer, implementingClassifier <- s), -- Update -- updateOp : UML2!"uml::Operation" ( name <- 'update'.debug('ObserverClass : ' + s.name), class <- s, visibility <- #public, ownedParameter <- Sequence{updatePar1, updatePar2}, concurrency <- #sequential), updatePar1 : UML2!"uml::Parameter" ( name <- 'name', type <- thisModule.oclString, effect <- #read, direction <- #"in"), updatePar2 : UML2!"uml::Parameter" ( name <- 'value', type <- thisModule.oclAny, effect <- #update, direction <- #"in"), updateBehavior : UML2!"uml::OpaqueBehavior" ( specification <- updateOp, name <- updateOp.name + 'Behavior', ownedParameter <- Sequence{updateBPar1, updateBPar2}, language <- Sequence{thisModule.language}, body <- Sequence{s.update()}), updateBPar1 : UML2!"uml::Parameter" ( name <- 'name', type <- thisModule.oclString, effect <- #read, direction <- #"in"), updateBPar2 : UML2!"uml::Parameter" ( name <- 'value', type <- thisModule.oclAny, effect <- #update, direction <- #"in") do { updateBehavior; } } rule OpaqueBehavior { from s : UML2!"uml::OpaqueBehavior" ( if thisModule.inElements->includes(s) then s.oclIsTypeOf(UML2!"uml::OpaqueBehavior") else false endif) to t : UML2!"uml::OpaqueBehavior" ( __xmiID__ <- s.__xmiID__, name <- s.name, visibility <- s.visibility, isLeaf <- s.isLeaf, isAbstract <- s.isAbstract, isActive <- s.isActive, isReentrant <- s.isReentrant, body <- if s.isNotifyMethod then if s.isSubscribeMethod then s.body->collect(b|s.specification.notify(s.specification.subscribe(b))) else s.body->collect(b|s.specification.notify(b)) endif else if s.isSubscribeMethod then s.body->collect(b|s.specification.subscribe(b)) else s.body endif endif, language <- s.language, 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, ownedAttribute <- s.ownedAttribute, ownedConnector <- s.ownedConnector, ownedBehavior <- s.ownedBehavior, classifierBehavior <- s.classifierBehavior, interfaceRealization <- s.interfaceRealization, ownedTrigger <- s.ownedTrigger, nestedClassifier <- s.nestedClassifier, ownedOperation <- s.ownedOperation, ownedReception <- s.ownedReception, redefinedBehavior <- s.redefinedBehavior, ownedParameter <- s.ownedParameter, precondition <- s.precondition, postcondition <- s.postcondition, ownedParameterSet <- s.ownedParameterSet, specification <- s.specification) } -- ====================================================================== -- transformation rules end -- ======================================================================