blob: 7083324a72ac7eaed06ab92b89fca29b85ce51d5 [file] [log] [blame]
/*
-----------------------------------------------------------------------
-- 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-v20.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::MARTE_Foundations::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::MARTE_DesignModel::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::MARTE_Foundations::Alloc::Assign);
return asg._from![InstanceSpecification] = p;
}