/* ----------------------------------------------------------------------- -- CHESS ceiling assignment transformation -- -- -- -- Copyright (C) 2011-2012 -- -- University of Padova, ITALY -- -- -- -- Authors: Marco Panunzio panunzio@math.unipd.it -- -- Alessandro Zovi azovi@math.unipd.it -- -- -- -- All rights reserved. This program and the accompanying materials -- -- are made available under the terms of the Eclipse Public License -- -- v1.0 which accompanies this distribution, and is available at -- -- http://www.eclipse.org/legal/epl-v10.html -- ----------------------------------------------------------------------- */ import ProfileUtils_Inst_full; import UMLUtils_Inst_full; import chess.lib; modeltype UML uses "http://www.eclipse.org/uml2/2.0.0/UML"; modeltype MARTEP uses "http://www.eclipse.org/papyrus/MARTE/1"; modeltype CHESS uses "http://CHESS"; modeltype ECORE uses "http://www.eclipse.org/emf/2002/Ecore"; transformation CHESS_Assignment(inout source:UML); property model : Model = null; property MARTEProfile : Profile = null; property CHESSProfile : Profile = null; property assigns : Set(Comment) = null; property compView : Package = null; property deplView : Package = null; property instSpecPackage : Package = null; property instSpecPackageDepl : Package = null; main() { log("*** CHESS Ceiling assignment transformation ***"); model := source.rootObjects()![Model]; MARTEProfile := model.getView("ComponentView").getAppliedProfiles()->selectOne(name="GCM").owner.owner.oclAsType(Profile); CHESSProfile := model.getAppliedProfiles()->selectOne(name="CHESS").oclAsType(Profile); initUtils(MARTEProfile, CHESSProfile); compView := model.getView("ComponentView"); instSpecPackage := compView.allOwnedElements()[Package]->selectOne(not getMetaclass("CHESS::Core::CHGaResourcePlatform").oclIsUndefined()); deplView := model.getView("DeploymentView"); instSpecPackageDepl := deplView.allOwnedElements()[Package]->selectOne(not getMetaclass("CHESS::Core::CHGaResourcePlatform").oclIsUndefined()); assigns := deplView.allOwnedElements()[Comment]->select(isStereotyped(AssignQN)); model.map ModelWithCeiling(); log("*** End of CHESS Ceiling assignment transformation ***"); } helper Set(Slot)::printCeilings(){ self->forEach(ps) { var specs : Sequence(chessmlprofile::RTComponentModel::CHRtSpecification) := (ps.getMetaclass(CHRtPortSlotQN).oclAsType(chessmlprofile::RTComponentModel::CHRtPortSlot)).cH_RtSpecification->asSequence(); specs->forEach(spec) { var x := ps.definingFeature.qualifiedName + " " + spec.context.qualifiedName; x := x + " "+ spec.ceiling; log(x); } }; } mapping inout Model::ModelWithCeiling() { init{ var chrtPortSlotList : Set(Slot) :=instSpecPackage.allOwnedElements()[Slot]->select(ps | ps.isStereotyped(CHRtPortSlotQN))->asSet(); } // Initialization of own ceilings of cyclic and sporadic operations // Initialization of ceiling of protected operation // Initialization of ceiling of unprotected operation chrtPortSlotList->forEach(ps) { var specs : Sequence(chessmlprofile::RTComponentModel::CHRtSpecification) := (ps.getMetaclass(CHRtPortSlotQN).oclAsType(chessmlprofile::RTComponentModel::CHRtPortSlot)).cH_RtSpecification->asSequence(); specs->forEach(spec) { if (spec.isDeferred()) then { spec.ceiling := spec.relativePriority } else { spec.ceiling := "-127"; } endif; } }; log("Before:"); chrtPortSlotList->printCeilings(); // Ceiling propagation chrtPortSlotList->forEach(ps) { var specs : Sequence(chessmlprofile::RTComponentModel::CHRtSpecification) := (ps.getMetaclass(CHRtPortSlotQN).oclAsType(chessmlprofile::RTComponentModel::CHRtPortSlot)).cH_RtSpecification->asSequence(); specs->forEach(spec) { if (spec.isDeferred()) then { ps.map propagateCeiling(spec); } endif } }; log("After:"); chrtPortSlotList->printCeilings(); //After ceiling propagation, remove ceilings of unprotected operations chrtPortSlotList->forEach(ps) { var specs : Sequence(chessmlprofile::RTComponentModel::CHRtSpecification) := (ps.getMetaclass(CHRtPortSlotQN).oclAsType(chessmlprofile::RTComponentModel::CHRtPortSlot)).cH_RtSpecification->asSequence(); specs->forEach(spec) { if ((not spec.isDeferred()) and (not spec.isProtected())) then { spec.ceiling := null; } endif } } } mapping inout Slot::propagateCeiling(spec : chessmlprofile::RTComponentModel::CHRtSpecification) { init { var ceilingToPropagate := spec.ceiling; var sourceOp : Operation := spec.context.oclAsType(Operation); var currInstance : InstanceSpecification := self.owningInstance; } if (sourceOp.method->notEmpty()) then { var act := (sourceOp.method->asSequence()->first().oclAsType(Activity)); var coaList := act.collectCallOperationNodes(); coaList->forEach(coa) { var calledOp := coa.operation; var riPort := coa.onPort; var riSlot : Slot := currInstance.slot[definingFeature = riPort]->any(true); var connectedSlot : Slot := riSlot.getConnectedSlot(currInstance); var CHRtSpec := connectedSlot.CHRtSpecForOperation(calledOp); /* If the component instances are deployed on different nodes * we need to set the ceiling priority to the priority of the * server task of the middleware. * Currently it is hardcoded to 27. */ if (not riSlot.owningInstance.isDeployedOnSameProcesor(connectedSlot.owningInstance)) then ceilingToPropagate := "27" endif; if (ceilingToPropagate.asInteger() > CHRtSpec.ceiling.asInteger()) then { if (CHRtSpec.isDeferred()) then { //Raise the ceiling of the OBCS and terminate CHRtSpec.ceiling := ceilingToPropagate; } else { if (CHRtSpec.isProtected()) then { //Raise the ceiling of the protected object // (i.e. all protected operations of the slot) // and recursively continue CHRtSpec.ceiling := ceilingToPropagate; connectedSlot.map propagateCeiling(CHRtSpec); var specs : Sequence(chessmlprofile::RTComponentModel::CHRtSpecification) := (connectedSlot.getMetaclass(CHRtPortSlotQN).oclAsType(chessmlprofile::RTComponentModel::CHRtPortSlot)).cH_RtSpecification->asSequence(); specs ->forEach(mySpec) { if (mySpec.isProtected()) then { if (ceilingToPropagate.asInteger() > mySpec.ceiling.asInteger()) then { mySpec.ceiling := ceilingToPropagate; connectedSlot.map propagateCeiling(mySpec); } endif; } endif; } } else {//Unprotected CHRtSpec.ceiling := ceilingToPropagate; connectedSlot.map propagateCeiling(CHRtSpec); } endif; } endif; } endif; }; } endif; } query InstanceSpecification::isConnectorInstance() : Boolean { if (self.classifier->isEmpty()) then if (self.slot->any(true).isStereotyped(ClientServerPortQN)) then return true endif endif; return false; } query Element::isNullOrInvalid() : Boolean { if(self.oclIsInvalid() or self.oclIsUndefined())then return true endif; return self.isNull(); } query Slot::getConnectedSlot(compInst : InstanceSpecification) : Slot { var riPort := self.definingFeature.oclAsType(Port); var myInstanceValue : InstanceValue := null; var connectorPIslot : Slot := null; var targetInstance : InstanceSpecification := null; var connectorInstList := InstanceSpecification.allInstances()->select(classifier->size() = 0); connectorInstList->forEach(connInst) { var candidateSlot : Slot := connInst.slot->selectOne(definingFeature = riPort); if (candidateSlot.oclIsInvalid()) continue endif; if (not candidateSlot.isNullOrInvalid()) then { myInstanceValue := (candidateSlot.allOwnedElements()[InstanceValue])->selectOne(instance = compInst); if (myInstanceValue.oclIsInvalid()) continue endif; if (not myInstanceValue.isNullOrInvalid()) then { connectorPIslot := connInst.slot->selectOne(definingFeature <> riPort); targetInstance := connectorPIslot.value->selectOne(true).oclAsType(InstanceValue).instance; return targetInstance.slot->selectOne(definingFeature = connectorPIslot.definingFeature); } endif; } endif; }; return null; } query InstanceSpecification::isDeployedOnSameProcesor(is : InstanceSpecification) : Boolean { var proc1 : InstanceSpecification := getDeploymentProcessor(self); return proc1 = getDeploymentProcessor(is); } query getDeploymentProcessor(p : InstanceSpecification) : InstanceSpecification { var a := assigns -> selectOne(isAssignedFrom(p)); var asg := a.getMetaclass(AssignQN).oclAsType(MARTE::Alloc::Assign); return asg.to![InstanceSpecification]; } /** * Start of reused code by azovi */ /* Given an ICB-Activity return the list of all its CallOperationAction nodes, assuming that their are all connected in a single chain: no loops and branches. older version. current one has been moved in UMLUtils_Inst_full.qvto */ query Activity::collectCallOperationNodesOLD() : Sequence(CallOperationAction) { var nodes : Sequence(CallOperationAction) := Sequence{}; var prevNode : ActivityNode := self.node![InitialNode]; var nextNode : ActivityNode; while(true){ nextNode := prevNode.outgoing->any(true).target.oclAsType(CallOperationAction); if (nextNode.oclIsInvalid()) break endif; if (not nextNode.isNullOrInvalid()) then { nodes += nextNode.oclAsType(CallOperationAction); prevNode := nextNode; } else{ break; } endif; }; return nodes; } query chessmlprofile::RTComponentModel::CHRtSpecification::isDeferred() : Boolean { var arrivalPattern := self.occKind.getArrivalPatternType(); //the operation is deferred if the arrival pattern is: periodic, sporadic, bursty if arrivalPattern.oclIsInvalid() then return false endif; return (arrivalPattern <> null and arrivalPattern.length() <> 0); } query chessmlprofile::RTComponentModel::CHRtSpecification::isSporadic() : Boolean { var arrivalPattern := self.occKind.getArrivalPatternType(); return (arrivalPattern.equalsIgnoreCase("sporadic"));// and self.isGuarded()); } query chessmlprofile::RTComponentModel::CHRtSpecification::isProtected() : Boolean { return (not self.isDeferred()) and self.protection = MARTE::HLAM::CallConcurrencyKind::guarded; } query Port::getConnectedPort() : Port { var bindingConnector := self.getConnector(); var myConnectorEnd := (bindingConnector.allOwnedElements()[ConnectorEnd])-> selectOne(role <> self); return myConnectorEnd.role.oclAsType(Port); } query Comment::isAssignedFrom(p : InstanceSpecification) : Boolean { var asg := self.getMetaclass(AssignQN).oclAsType(MARTE::Alloc::Assign); return asg._from![InstanceSpecification] = p; }