blob: 737861e1d7fad82ea8ee7cd6597bf09c7684279a [file] [log] [blame]
/*
-----------------------------------------------------------------------
-- CHESS M2M plugin --
-- --
-- Copyright (C) 2011-2012 --
-- University of Padova, ITALY --
-- --
-- Author: 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 --
-----------------------------------------------------------------------
*/
library 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";
query Element::getMetaclass(stereoName : String) : EObject {
var s = self.getAppliedStereotype(stereoName);
return self.getStereotypeApplication(s);
}
query Model::getView(viewName : String) : Package {
var seq := self.packagedElement[Package]-> union(self.packagedElement[Package].packagedElement[Package]);
return seq -> selectOne(isStereotyped("CHESS::Core::CHESSViews::" + viewName));
}
query Element::isStereotyped(stereoName : String) : Boolean {
return self.getAppliedStereotype(stereoName) <> null
}
/*
Return the connector associated to a port assuming
each port has at most only one connector
*/
//TODO Assumption: a port should have only one connector
query Port::getConnector() : Connector {
return self._end->asSequence()->first().owner.oclAsType(Connector);
}
/*
Return the RI Slot of the 'instance' InstanceSpecification that corresponds to the given port
*/
//query Port::portToSlot(in instance : InstanceSpecification) : Slot {
// return instance.ownedElement[Slot]->selectOne(definingFeature = self);
//}
query CallOperationAction::portToSlotFull(in instance : InstanceSpecification) : Set(Slot) {
var rule := self.activity.specification![Operation]._class.getRuleFor(self);
if rule.oclIsInvalid() or rule.oclIsUndefined() then //if there is no contraint all the ports are called simultaneously
return instance.slot->select(definingFeature = self.onPort)
else {
return instance.portToSlotsByRule(self.onPort, rule)->asSet();
}endif;
return null;
}
query Class::getRuleFor(callOp : CallOperationAction) : Constraint {
self.ownedRule->forEach(rule){
if rule.constrainedElement![CallOperationAction] = callOp then
return rule
endif;
};
return null;
}
query Element::isNull() : Boolean {
return self.oclIsInvalid() or self.oclIsUndefined();
}
//TODO Assumption: The InstanceSpecification.classifier property should really have one and only element!
query InstanceSpecification::classifier() : Classifier {
return self.classifier->selectOne(true);
}
/*
Test if a connector is attached to the 'el' element
*/
query Connector::isLinkedWith(el : Element) : Boolean {
return self._end->selectOne(partWithPort = el) <> null;
}
//TODO extends with other comparison criteria
query Operation::isSameOperation(op : Operation) : Boolean {
var b := self.name = op.name
and self.ownedParameter->size() = op.ownedParameter->size()
and self.visibility = op.visibility
and op.isStatic = self.isStatic
and op.isAbstract = self.isAbstract;
if not b then
return false
endif;
// the ownedParameter is an ordered set...
var i := 1;
while (i <= self.ownedParameter->size()) {
b := b and self.ownedParameter->at(i).isSameParameter(op.ownedParameter->at(i));
i := i + 1;
};
return b;
}
query Parameter::isSameParameter(pa : Parameter) : Boolean {
return self.name = pa.name and self.type = pa.type and self.direction = pa.direction;
}
/*
Build the name of an operation: the name of a operation corresponds to
its name concatenated to the name of type of its parameters
*/
query BehavioralFeature::name() : String {
var n := self.name;
self.ownedParameter.type.name->forEach(s){
n := n + "_" + s;
};
return n;
}
/*
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.
Used in CHESS_PIM2PSM_Inst_full_VERDE.qvto and CHESS_CeilingAssignment.qvto
TODO: consider decision nodes and branches (no loops?)
*/
query Activity::collectCallOperationNodes() : Sequence(CallOperationAction) {
var nodes : Sequence(CallOperationAction) := Sequence{};
var prevNode : ActivityNode := self.node![InitialNode];
var nextNode : ActivityNode;
while(true){
//TODO Assumption one edge per node
nextNode := prevNode.outgoing->any(true).target;
if (nextNode <> null and nextNode.oclIsKindOf(CallOperationAction)) then {
nodes += nextNode.oclAsType(CallOperationAction);
prevNode := nextNode;
}
else{
if (nextNode.oclIsKindOf(ActivityFinalNode)) then {
break;
}
endif;
}
endif;
};
return nodes;
}
// Constructors
constructor Operation::Operation(n : String) {
name := n;
}
constructor Operation::Operation(op: Operation) {
name:= op.name();
op.ownedParameter -> forEach(par) {
ownedParameter += new Parameter(par);
};
redefinedOperation:= op;
// TODO complete with other attributes if necessary
}
constructor Parameter::Parameter(par: Parameter) {
name:= par.name;
type:= par.type;
}
constructor Package::Package(n:String) {
name:= n;
}
constructor Class::Class(n:String) {
name:= n;
}
constructor Activity::Activity(n:String) {
name:= n;
}
constructor InitialNode::InitialNode(n: String) {
name:= n;
}
constructor ActivityFinalNode::ActivityFinalNode(n: String) {
name:= n;
}
constructor ControlFlow::ControlFlow(n: String) {
name:= n;
guard:= new OpaqueExpression();
}
constructor OpaqueAction::OpaqueAction(n: String) {
name:= n;
}
constructor Constraint::Constraint(n: String) {
name:= n;
}
constructor OpaqueExpression::OpaqueExpression() {
body:="true";
language:="OCL";
}