Skip to content
Snippets Groups Projects
Forked from Eclipse Projects / Eclipse CHESS / chess
403 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
CHESS_CeilingAssignment.qvto 11.04 KiB
/*
-----------------------------------------------------------------------
--            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;
}