/***************************************************************************** * Copyright (c) 2016 CEA LIST. * * 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 * * Contributors: * Vincent Lorenzo (CEA LIST) vincent.lorenzo@cea.fr - Initial API and implementation *****************************************************************************/ import org.eclipse.papyrus.migration.rhapsody.blackboxes.uml.AssociationOwnerHelper; import org.eclipse.papyrus.migration.rhapsody.blackboxes.rhapsody.RhapsodyHelper; import RhapsodyToPapyrusUtils; import SysMLRhapsodyUtils; modeltype uml "strict" uses 'http://www.eclipse.org/uml2/5.0.0/UML'; modeltype ecore "strict" uses 'http://www.eclipse.org/emf/2002/Ecore'; modeltype umlrhapsody "strict" uses 'http://www.eclipse.org/Papyrus/UMLRhapsody/1.0.0'; modeltype notation "strict" uses 'http://www.eclipse.org/gmf/runtime/1.0.2/notation'; modeltype UMLPrimitivesTypes "strict" uses 'http://www.eclipse.org/uml2/5.0.0/Types' ; //add syml profile modeltype sysml11 "strict" uses 'http://www.eclipse.org/papyrus/0.7.0/SysML'; /** * Transformation rules for importing a Rhapsody Semantic model into a UML model */ transformation Rhapsody2PapyrusSemanticElements(in inModel:umlrhapsody, out outModel:uml, in primitives:UMLPrimitivesTypes); property events : Set(IEvent) = null; /**This variable is used to reference the types created outside of all contexts. (bug 510869)*/ property userTypeDeclaration: Set(Type); /** * Maunch the semantic transformation */ main() { log('Start UML Semantic QVTo Transfo'); inModel.rootObjects()[IProject]->map iProjectToPapyrusModel(); setAssociationOwnerAndClear(); log('Finish UML Semantic QVTO Transfo'); } /** * * Create a Model from the IProject */ mapping umlrhapsody::IProject::iProjectToPapyrusModel() : uml::Model { name:=self.name.replaceAll("\"",""); eAnnotations+=inModel.rootObjects()->selectByType(IProject)![IProject].createEAnnotationForVersioning(); //managing the rhapsodyType, importing them in the user model var rhapsodyLibraries:Sequence(uml::Package):=getISubsystemsFromRhapsodyLibraries(self).map importRhapsodyTypeLibrary(); //we map the packaged elements packagedElement+=self.Subsystems.map iDefaultSubsystemTypeToPackage(); //we add the rhapsody library at the end packagedElement+=rhapsodyLibraries;//we add them add the end of the list. it is a kind of feature, to show firstly in the model the user elements //import uml basic primitives Types by default var importedPackages: Set(PackageImport); var models : Set(Model) := primitives.objectsOfType(Model); models->forEach(package){ var packageImport:=object PackageImport{ importedPackage:=package; }; importedPackages+=packageImport; }; packageImport+=importedPackages; if(userTypeDeclaration->notEmpty()){ packagedElement+= object Package{ name:="UserTypesDeclaration"; packagedElement+=userTypeDeclaration; } } } /** * * dedicated method to import only types from Rhapsody Library */ mapping umlrhapsody::ISubsystem::importRhapsodyTypeLibrary():uml::Package{ name:=self.name; packagedElement += self.Types->selectByType(IType)->selectByKind(EObject).map generalMappingToUMLElement().oclAsType(uml::PackageableElement); } /** * Create packages from DefaultSubsystemType */ mapping umlrhapsody::DefaultSubsystemType::iDefaultSubsystemTypeToPackage():uml::Package when{self.oclIsKindOf(ISubsystem)}{ var iSubSystem:ISubsystem:=self.oclAsType(ISubsystem); name:=iSubSystem.name; //no idea about this code coming from the initial prototype if(iSubSystem.SignalEvents()[IEvent].oclAsSet()->notEmpty()){ var SignalsPackage := object Package{ name:= "Signals"; packagedElement:= iSubSystem.SignalEvents()->selectByKind(EObject).map generalMappingToUMLElement().oclAsType(PackageableElement); }; nestedPackage+=SignalsPackage; }; //no idea about this code coming from the initial prototype if(iSubSystem.SignalEvents()[IEvent].oclAsSet()->notEmpty()){ var SignalEventPackage := object Package{ name:= "Signal Events"; packagedElement:= iSubSystem.SignalEvents()[IEvent].map toSignalEvents(); }; nestedPackage+=SignalEventPackage; }; packagedElement+=iSubSystem.Events->selectByType(IEvent)->selectByKind(EObject).map generalMappingToUMLElement().oclAsType(PackageableElement); packagedElement+= iSubSystem.Classes->selectByType(IClass)->any(name="TopLevel").Attrs->selectByKind(IAttribute).oclAsType(EObject).map generalMappingToUMLElement().oclAsType(PackageableElement); //TODO probably more check are required to remove TopLevel without problems (check with MARTE...) packagedElement+= iSubSystem.Classes->selectByType(IClass)->select(curr | curr.name<>"TopLevel")->selectByKind(EObject).map generalMappingToUMLElement().oclAsType(uml::PackageableElement); packagedElement += iSubSystem.Classes[IClass].Associations[IAssociationEnd]->select(assoEnd: IAssociationEnd |not (assoEnd.oclAsType(IAssociationEnd).inverse.oclIsUndefined()))->any(true).map toAssociationswithoutProp(); packagedElement += iSubSystem.Types->selectByType(IType)->selectByKind(EObject).map generalMappingToUMLElement().oclAsType(uml::PackageableElement); packagedElement += iSubSystem.Actors->selectByKind(IActor)->oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::PackageableElement); packagedElement +=iSubSystem.Declaratives[DefaultSubsystemType].oclAsSet().map iDefaultSubsystemTypeToPackage(); ownedComment += iSubSystem.Annotations->select(a | (a.oclIsTypeOf(IAnnotation) or a.oclIsTypeOf(IComment)))->oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); var localComment:Comment:=iSubSystem.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); localComment.annotatedElement:=result; ownedComment+=localComment; } /** * * This method has been created to be the common entry point for all the semantic transformations from the Rhapsody Model to the UML Model * TODO : rewrite all transformations in order to use me everywhere */ mapping ecore::EObject::generalMappingToUMLElement():uml::Element disjuncts ecore::EObject::iActorToUMLActor, ecore::EObject::iCommentToUMLComment, ecore::EObject::iDescriptionToUMLComment, ecore::EObject::iAttributeToUMLInstanceSpecification, ecore::EObject::iClassToUMLInterface, ecore::EObject::iClassToUMLClass, ecore::EObject::iEventToUMLSignal, ecore::EObject::iTypeToUMLDatatype, ecore::EObject::iTypeToUMLInstanceSpecification, ecore::EObject::iTypeToUMLEnumeration, ecore::EObject::iTypeToUMLClass, //TODO : merge me with the existing other way to create a class ecore::EObject::iTypeToDefault {} /** * This mapping convert an IActor into a UML Actor */ mapping EObject::iActorToUMLActor():uml::Actor when {self.oclIsTypeOf(umlrhapsody::IActor)}{ var actor:IActor:=self.oclAsType(IActor); name:=actor.name; ownedComment += actor.Annotations->selectByType(IComment).oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); } /** * * This mapping convert a IComment into a UML Comment */ mapping EObject::iCommentToUMLComment(): uml::Comment when {self.oclIsTypeOf(IComment)}{ var comment:IComment:=self.oclAsType(IComment); body:=comment.body; if(body=null or body.size()=0){ body:=comment.description.text; if(body=null or body.size()=0){ body:=comment.description.textRTF.getTextWithoutMarkers(); } }; comment.Anchors->forEach(anchor){ var rpyAnnotatedElement:EObject:=anchor.dependsOn.oclAsType(EObject); //this is the generic method to call to create/find mapped element var resolvedContext:Element:=rpyAnnotatedElement.map generalMappingToUMLElement(); //TODO : the code of the transformation should be refactored to use the previous one, nevertheless, waiting for this refactoring, we use this code if(resolvedContext=null){ var metaClassName:String:= rpyAnnotatedElement.metaClassName(); annotatedElement+=switch{ case (metaClassName="IPart") rpyAnnotatedElement.oclAsType(umlrhapsody::IPart).map iPartToUMLElement().oclAsType(uml::Element); case (metaClassName="IAttribute") rpyAnnotatedElement.oclAsType(umlrhapsody::IAttribute).map iVariableToUMLElement().oclAsType(uml::Element); }; }else{ annotatedElement+=resolvedContext; } } } /** * * This mapping convert a IDescription into a UML Comment */ mapping EObject::iDescriptionToUMLComment(): uml::Comment when {self.oclIsTypeOf(IDescription)}{ var description:IDescription:=self.oclAsType(IDescription); body:=description.text; if(body=null or body.size()=0){ body:=description.textRTF.getTextWithoutMarkers(); }; if(self.eContainer().oclIsKindOf(Element)){ annotatedElement+=self.eContainer().oclAsType(Element); } } /** * This method remove all markers in the string */ helper String::getTextWithoutMarkers():String{ //this code seems me quite specific to my examples, but I don't have better idea var res:String:=self.replaceAll("\\\\[a-zA-Z0-9]*", ""); //to remove all formatting information //we remove the end of the string var lastIndex:Integer:=res.lastIndexOf("\n}"); if(lastIndex<>-1){ res:=res.substring(1,lastIndex-1); }; var t:="}\n "; //} + carriage return + white space //we remove the beginning of the string lastIndex:=res.lastIndexOf(t); if(lastIndex<>-1){ res:=res.substring(lastIndex+t.length(),res.length()); }; return res; } /** * * return true if the IClass is representing an interface */ mapping ecore::EObject::iClassToUMLInterface() : uml::Interface when {self.oclIsTypeOf(umlrhapsody::IClass) and self.oclAsType(umlrhapsody::IClass).isInterface() /*self.isSysMLFlowSpecification()*/}{ var localIClass:umlrhapsody::IClass:=self.oclAsType(umlrhapsody::IClass); name:= localIClass.name.replaceAll("\"",""); ownedAttribute+= localIClass.Attrs[IAttribute].map iVariableToUMLElement(); // ownedAttribute+= self.Associations[IAssociationEnd].map toAssociationsEnd(); // ownedOperation := self.Operations [IPrimitiveOperation].map toOperations(); // ownedReception:= self.Operations[IReception].map toReceptions(); // generalization:= self.Inheritances [IGeneralization].map toPapyrusGeneralization(); } /** * * When we match any condition, we create a uml::DataType. * We can be here in case of bug, when an existing type has not been resolved * or when the user use the C type declaration in Rhapsody (declaring a type with a string, see bug 510869) */ mapping ecore::EObject::iTypeToDefault():uml::DataType when{self.oclIsTypeOf(IType)}{ var localIType:IType:=self.oclAsType(IType); if(localIType.name=null or localIType.name.oclIsInvalid()){ if(localIType.declaration<>null){ name:=localIType.declaration; } }else{ name:=localIType.name.replaceAll("\"",""); }; } /** * This method allows to map a RhapsodyType on an other type */ query umlrhapsody::IType::mapToBasicType(inout templateableElement:TemplateableElement){ //we assurme here that the UML PrimitiveTypes are already imported var baseType:IUnit := self.typedefBaseType; if(not(baseType.oclIsUndefined()) and baseType.oclIsTypeOf(IType)){ // var name:String:=baseType.metaClassName(); var umlType:uml::Type :=baseType.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); if(not(umlType.oclIsUndefined())){//should never appends var templateBinding := object uml::TemplateBinding{ }; // var redefinableTemplateSignature:=object uml::RedefinableTemplateSignature { // // }; var templateParameterSubstitution:= object TemplateParameterSubstitution{ }; // var classifierTemplateParameter:= object ClassifierTemplateParameter{ // // }; templateableElement.templateBinding+=templateBinding; templateBinding.boundElement:=templateableElement; // //templateBinding.source:=templatableElement; //read only // //templateBinding.target:=templateParameterSubstitution; //read only // templateBinding.signature:=redefinableTemplateSignature; templateBinding.parameterSubstitution+=templateParameterSubstitution; templateParameterSubstitution.actual:=umlType; }; }; // return templateableElement; } /** * Return true if the object must be converted into a UML DataType * * For JUnit SysML test1: * must be converted into UML Datatype : * MyBool : kind = Typedef and stereotype = DataType * MyArrayOfInt : kind = Typedef and stereotype DataType * MyPrimitivesTypes : kind = Language and stereotype = DataType * MySpeed : kind = kind = Typedef and ValueType * IType defined in Rhapsody Library (like PredefinedTypes) must be imported as DatType */ query umlrhapsody::IType::isUMLDataType(): Boolean { var res:=self.isSysMLValueType() and not self.isKindEnumeration(); if(not res){ res:=(self.isRhapsodyDataType() or self.isRhapsodyLibraryType()) and (self.isKindLanguage() or self.isKindTypedef()); }; return res; } /** * Return true if the IType is kind Typedef */ query umlrhapsody::IType::isKindTypedef(): Boolean{ return self.kind="Typedef"; } /** * Return true if the IType is kind Enumeration */ query umlrhapsody::IType::isKindEnumeration(): Boolean{ return self.kind="Enumeration"; } /** * Return true if the IType is kind Enumeration */ query umlrhapsody::IType::isKindStructure(): Boolean{ return self.kind="Structure"; } /** * Return true if the IType has kind Language */ query umlrhapsody::IType::isKindLanguage(): Boolean { return self.kind="Language"; } query umlrhapsody::IType::isUMLClass(): Boolean{ return self.isKindStructure() and (self.isRhapsodyDataType() or self.isSysMLValueType()); } query umlrhapsody::IType::isUMLEnumeration():Boolean{ return self.isKindEnumeration() and ((self.isRhapsodyDataType() or self.isSysMLValueType()) //TODO to check : is it required to check isDatatYpe and isSysmlValueType ? or self.isRhapsodyLibraryType()); //to create Enumeration for Type defined ni RhapsodyLibrary } query umlrhapsody::IType::isUMLInstanceSpecification(): Boolean { return self.isKindLanguage() and (self.isSysMLDimension() or self.isSysMLUnit()); } mapping umlrhapsody::IAssociationEnd::toAssociationswithoutProp(): uml::Association { var assoEnd:Set(umlrhapsody::IAssociationEnd) =inModel.rootObjects()[IProject].defaultSubsystem[ISubsystem].Classes[IClass].Associations[IAssociationEnd]->select(assoEnd: IAssociationEnd |not (assoEnd.oclAsType(IAssociationEnd).inverse.oclIsUndefined()))->asSet(); memberEnd:=assoEnd.map toAssociationsEnd(); } mapping umlrhapsody::IAssociationEnd::toAssociationswithProp(): uml::Association { //please keep this order (O source and 1 target) -> if we change this property we broke the BDD of test2 var localMemberEnd:=self.map toAssociationsEnd(); memberEnd+= localMemberEnd; var localOwnedEnd:=self.map toOwnedAssociationEnd(); ownedEnd+= localOwnedEnd; name:=localOwnedEnd.type.name + " refers to " + localMemberEnd.type.name + " as " + localMemberEnd.name; } mapping umlrhapsody::IAssociationEnd::toOwnedAssociationEnd(): uml::Property{ type:= self.container().oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); var type : uml::Class = type.oclAsType(Class); } mapping ecore::EObject::iTypeToUMLDatatype() : uml::DataType when {self.oclIsTypeOf(IType) and self.oclAsType(IType).isUMLDataType()}{ var localIType:IType:=self.oclAsType(IType); name:= localIType.name.replaceAll("\"",""); ownedAttribute+=localIType.Attrs[IAttribute].map iVariableToUMLElement(); localIType.mapToBasicType(result.oclAsType(uml::TemplateableElement)); } mapping ecore::EObject::iTypeToUMLEnumeration() : uml::Enumeration when {self.oclIsTypeOf(IType) and self.oclAsType(IType).isUMLEnumeration()}{ var localIType:IType:=self.oclAsType(IType); name:= localIType.name.replaceAll("\"",""); ownedLiteral+=localIType.Literals[IEnumerationLiteral].map toUMLEnumerationLiteral(); localIType.mapToBasicType(result.oclAsType(uml::TemplateableElement)); } mapping umlrhapsody::IEnumerationLiteral::toUMLEnumerationLiteral() : uml::EnumerationLiteral { name:= self.name.replaceAll("\"",""); } mapping ecore::EObject::iTypeToUMLInstanceSpecification() : uml::InstanceSpecification when {self.oclIsTypeOf(IType) and self.oclAsType(IType).isUMLInstanceSpecification()}{ var localIType:IType:=self.oclAsType(IType); name:= localIType.name.replaceAll("\"",""); } //TODO : refactore me, there is at least 2 method to create a class, on efrom an IType and an other one from a IClass mapping ecore::EObject::iTypeToUMLClass() : uml::Class when {self.oclIsTypeOf(IType) and self.oclAsType(IType).isUMLClass()}{//stereotype Block is added later in the process var localIType:IType:=self.oclAsType(IType); name:= localIType.name.replaceAll("\"",""); ownedAttribute+=localIType.Attrs[IAttribute].map iVariableToUMLElement(); localIType.mapToBasicType(result.oclAsType(uml::TemplateableElement)); } mapping ecore::EObject::iClassToUMLClass(): uml::Class when {self.oclIsTypeOf(umlrhapsody::IClass) and not (self.oclAsType(umlrhapsody::IClass).isInterface())}{ var localIClass:umlrhapsody::IClass:=self.oclAsType(umlrhapsody::IClass); name:= localIClass.name.replaceAll("\"",""); ownedAttribute+= localIClass.Attrs[IAttribute].map iVariableToUMLElement(); ownedAttribute+= localIClass.Associations[IPart].map iPartToUMLElement().oclAsType(uml::Property); var associationsToAdd:=localIClass.Associations[IPart].map iPartToUMLAssociation(); nestedClassifier+= localIClass.Associations[IPart]->select(current | current.implicitClass<>null).implicitClass.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Classifier); nestedClassifier+=localIClass.Declaratives->selectByType(IClass)->selectByKind(EObject).map generalMappingToUMLElement().oclAsType(uml::Classifier); ownedAttribute+= localIClass.Associations[IAssociationEnd].map toAssociationsEnd(); associationsToAdd+=localIClass.Associations[IAssociationEnd]->select(assoEnd: IAssociationEnd |assoEnd.oclAsType(IAssociationEnd).inverse.oclIsUndefined()).oclAsSet().map toAssociationswithProp(); ownedOperation += localIClass.Operations [IPrimitiveOperation].map toOperations(); ownedReception += localIClass.Operations[IReception].map toReceptions(); generalization += localIClass.Inheritances [IGeneralization].map toPapyrusGeneralization(); ownedBehavior += localIClass.StateCharts[IStateChart].map toStateMachine(); ownedAttribute+=localIClass.Ports.map iRelationToUMLElement().oclAsType(uml::Property); ownedConnector+=localIClass.ObjectLinks[IObjectLink].map iObjectLinkToUMLElement().oclAsType(uml::Connector); ownedConnector+=localIClass.Declaratives[IInformationFlow].map iInformationFlowToUMLElement().oclAsType(uml::Connector); ownedComment+=localIClass.Annotations.oclAsType(IComment).oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); registerAssociationToStore(result, associationsToAdd); } /** * This method map a IObjectLink with a UML Element * */ mapping umlrhapsody::IInformationFlow::iInformationFlowToUMLElement():uml::Element disjuncts umlrhapsody::IInformationFlow::iInformationFlowToUMLConnector {} /** * This method map a IInformationFlow with a UML Connector * */ mapping umlrhapsody::IInformationFlow::iInformationFlowToUMLConnector():uml::Connector when{self.isUMLConnector() }{ name:= self.name.replaceAll("\"",""); _end+=self.map iInformationFlowSourceToUMLConnectorEnd(); _end+=self.map iInformationFlowTargetToUMLConnectorEnd(); } /** * This method map a IInformationFlow with a UML Connector End used as source * */ mapping umlrhapsody::IInformationFlow::iInformationFlowSourceToUMLConnectorEnd():uml::ConnectorEnd{ var end1:umlrhapsody::End1_Type:=self.end1_; var end1ObjectPort:umlrhapsody::IInstance:=self.end1ObjectPort_; var mappingEnd1:uml::Element; var mappingEnd1ObjectPort:uml::Element; //1. we manage the end1 property if(end1<>null){ if(end1.oclIsTypeOf(umlrhapsody::IPart)){ mappingEnd1:=end1.oclAsType(umlrhapsody::IPart).map iPartToUMLElement().oclAsType(uml::Property); }elif(end1.oclIsTypeOf(umlrhapsody::IAttribute)){ mappingEnd1:=end1.oclAsType(IAttribute).map iVariableToUMLElement(); }elif(end1.oclIsKindOf(umlrhapsody::IRelation)){ mappingEnd1:=end1.oclAsType(IRelation).map iRelationToUMLElement(); }; }; //2. we manage the end1ObjectPort_ property when required if(end1ObjectPort<>null and end1ObjectPort.oclIsKindOf(umlrhapsody::IRelation)){ mappingEnd1ObjectPort:=end1ObjectPort.oclAsType(umlrhapsody::IRelation).map iRelationToUMLElement().oclAsType(uml::Element); }; if(mappingEnd1ObjectPort=null){ if(mappingEnd1.oclIsTypeOf(uml::Property)){ role:=mappingEnd1.oclAsType(uml::Property); } }else{ if(mappingEnd1ObjectPort.oclIsTypeOf(uml::Property)){ role:=mappingEnd1ObjectPort.oclAsType(uml::Property); }elif(mappingEnd1ObjectPort.oclIsTypeOf(uml::Port) and mappingEnd1.oclIsTypeOf(uml::Property)){ //not sure, not example for this usecase role:=mappingEnd1ObjectPort.oclAsType(uml::Property); partWithPort:=mappingEnd1.oclAsType(uml::Property); }; }; } /** * This method map a IInformationFlow with a UML Connector End used as target * */ mapping umlrhapsody::IInformationFlow::iInformationFlowTargetToUMLConnectorEnd():uml::ConnectorEnd{ var end2:umlrhapsody::End1_Type:=self.end2_; var end2ObjectPort:umlrhapsody::IInstance:=self.end2ObjectPort_; var mappingEnd2:uml::Element; var mappingEnd2ObjectPort:uml::Element; //1. we manage the end2 property if(end2<>null){ if(end2.oclIsTypeOf(umlrhapsody::IPart)){ mappingEnd2:=end2.oclAsType(umlrhapsody::IPart).map iPartToUMLElement().oclAsType(uml::Property); }elif(end2.oclIsTypeOf(umlrhapsody::IAttribute)){ mappingEnd2:=end2.oclAsType(IAttribute).map iVariableToUMLElement(); }elif(end2.oclIsKindOf(umlrhapsody::IRelation)){ mappingEnd2:=end2.oclAsType(IRelation).map iRelationToUMLElement(); }; }; //2. we manage the end2ObjectPort_ property when required if(end2ObjectPort<>null and end2ObjectPort.oclIsKindOf(umlrhapsody::IRelation)){ mappingEnd2ObjectPort:=end2ObjectPort.oclAsType(umlrhapsody::IRelation).map iRelationToUMLElement().oclAsType(uml::Element); }; if(mappingEnd2ObjectPort=null){ if(mappingEnd2.oclIsTypeOf(uml::Property)){ role:=mappingEnd2.oclAsType(uml::Property); } }else{ if(mappingEnd2ObjectPort.oclIsTypeOf(uml::Property)){ role:=mappingEnd2ObjectPort.oclAsType(uml::Property); }elif(mappingEnd2ObjectPort.oclIsTypeOf(uml::Port) and mappingEnd2.oclIsTypeOf(uml::Property)){ //not sure, not example for this usecase role:=mappingEnd2ObjectPort.oclAsType(uml::Property); partWithPort:=mappingEnd2.oclAsType(uml::Property); }; }; } /** * * Returns true of the object is a UML Connector */ query umlrhapsody::IInformationFlow::isUMLConnector(): Boolean{ return self.Stereotypes[IStereotype]->select(ste | ste.name="BindingConnector").oclAsSet()->notEmpty() } /** * This method map a IObjectLink with a UML Element * */ mapping umlrhapsody::IObjectLink::iObjectLinkToUMLElement():uml::Element disjuncts umlrhapsody::IObjectLink::iObjectLinkToUMLConnector {} /** * This method map a IObjectLink with a UML Connector * */ mapping umlrhapsody::IObjectLink::iObjectLinkToUMLConnector():uml::Connector when{self.isUMLConnector() }{ name:= self.name.replaceAll("\"",""); _end+=self.map iObjectLinkSourceToUMLConnectorEnd(); _end+=self.map iObjectLinkTargetToUMLConnectorEnd(); } /** * This method map a IObjectLink with a UML Connector End used as source * */ mapping umlrhapsody::IObjectLink::iObjectLinkSourceToUMLConnectorEnd():uml::ConnectorEnd{ var fromLink:umlrhapsody::FromLinkType:=self.fromLink; var fromPort:umlrhapsody::IRelation:=self.fromPort; //1. we manage the from link property if(fromLink<>null){ if(fromLink.oclIsTypeOf(umlrhapsody::IPart)){ partWithPort:=fromLink.oclAsType(umlrhapsody::IPart).map iPartToUMLElement().oclAsType(uml::Property); }elif(fromLink.oclIsTypeOf(umlrhapsody::IAssociationEnd)){ partWithPort:=fromLink.oclAsType(IAssociationEnd).map toAssociationsEnd(); }elif(fromLink.oclIsKindOf(umlrhapsody::IRelation)){ role:=fromLink.oclAsType(umlrhapsody::IRelation).map iRelationToUMLElement().oclAsType(uml::Port); }; }; //2. we manage the fromPort property when required if(fromPort<>null and fromPort.oclIsKindOf(umlrhapsody::IRelation)){ if(role=null){ role:=fromPort.oclAsType(umlrhapsody::IRelation).map iRelationToUMLElement().oclAsType(uml::Port); } //I don't know what to do in other case! }; } /** * This method map a IObjectLink with a UML Connector End used as target * */ mapping umlrhapsody::IObjectLink::iObjectLinkTargetToUMLConnectorEnd():uml::ConnectorEnd{ var toLink:umlrhapsody::FromLinkType:=self.toLink; var toPort:umlrhapsody::IRelation:=self.toPort; //1. we manage the from link property if(toLink<>null){ if(toLink.oclIsTypeOf(umlrhapsody::IPart)){ partWithPort:=toLink.oclAsType(umlrhapsody::IPart).map iPartToUMLElement().oclAsType(uml::Property); }elif(toLink.oclIsTypeOf(umlrhapsody::IAssociationEnd)){ partWithPort:=toLink.oclAsType(IAssociationEnd).map toAssociationsEnd(); }elif(toLink.oclIsKindOf(umlrhapsody::IRelation)){ role:=toLink.oclAsType(umlrhapsody::IRelation).map iRelationToUMLElement().oclAsType(uml::Port); }; }; //2. we manage the fromPort property when required if(toPort<>null and toPort.oclIsKindOf(umlrhapsody::IRelation)){ if(role=null){ role:=toPort.oclAsType(umlrhapsody::IRelation).map iRelationToUMLElement().oclAsType(uml::Port); } //I don't know what to do in other case! }; } /** * * Returns true of the object is a UML Connector */ query umlrhapsody::IObjectLink::isUMLConnector(): Boolean{ return self.isStereotypedWith("connector"); } mapping umlrhapsody::IRelation::iRelationToUMLElement():uml::Element disjuncts umlrhapsody::IRelation::iRelationToSysMLPort, umlrhapsody::IRelation::iRelationToUMLProperty {} /** * * This mapping convert a IPart into a uml Element */ mapping umlrhapsody::IPart::iPartToUMLElement():uml::Element disjuncts umlrhapsody::IPart::iPartToUMLProperty {} /** * This method convert an IPart into a uml Property * */ mapping umlrhapsody::IPart::iPartToUMLProperty():uml::Property when {self.oclIsTypeOf(IPart)}{ name:= self.name.replaceAll("\"",""); //TODO : manage aggregation kind aggregation:=AggregationKind::composite; type:=self.otherClass.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Type); if((not self.multiplicity.oclIsUndefined()) and self.multiplicity<>"1"){ lowerValue:=createLowerMultiplicity(self.multiplicity); upperValue:=createUpperMultiplicity(self.multiplicity); } } mapping umlrhapsody::IPart::iPartToUMLAssociation():uml::Association when {true}{ var part:uml::Property:=self.resolveoneIn(umlrhapsody::IPart::iPartToUMLProperty); //TODO : replace me with a mapping var propOwner:uml::NamedElement:=part.owner.oclAsType(NamedElement); var propType:=part.type; var initialVal:=propType.invresolveone();//TODO is it a good idea to use unresolve ? var res:Boolean:=false; if(initialVal.oclIsTypeOf(umlrhapsody::IClass)){ //TODO : make a util for this stereotype application res:=initialVal.oclAsType(umlrhapsody::IClass).Stereotypes[IStereotype]->select(ste | ste.name="ConstraintBlock")->notEmpty(); }; if(res){ name:=propOwner.name + " has constraint " + propType.name + " applied as " + part.name; }elif(part.aggregation.toString()=AggregationKind::composite.toString()){ name:=propOwner.name + " owns a " + propType.name + " as " + part.name; }; var ownedEnd2:uml::Property:= object Property{}; ownedEnd2.name:=propOwner.name.toLowerCase(); ownedEnd2.type:=propOwner.oclAsType(uml::Type); memberEnd+=ownedEnd; memberEnd+=part; ownedEnd+=ownedEnd2; } /** * This mapping convert a IRelation instanceof ISysMLPort into a uml Property * */ mapping umlrhapsody::IRelation::iRelationToUMLProperty(): uml::Property when {self.isRhapsodySysMLPortRepresentingUMLProperty()}{ var sysPort:umlrhapsody::ISysMLPort:=self.oclAsType(ISysMLPort); name:= sysPort.name.replaceAll("\"",""); aggregation:=AggregationKind::composite; // if (not sysPort.otherClass.oclIsUndefined()){ // type := sysPort.otherClass.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); // }elif(sysPort.otherClass.oclIsKindOf(IClass)){ // type := sysPort.otherClass.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); // }; //at this time we don't generate implicite type if(sysPort.implicitClass<>sysPort.otherClass){ type := sysPort.otherClass.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); }; //a multiplicity has been defined if(not sysPort.multiplicity.oclIsUndefined()){ lowerValue:= createLowerMultiplicity(sysPort.multiplicity); upperValue:= createUpperMultiplicity(sysPort.multiplicity); }else{ lowerValue:= createLowerMultiplicity("1"); upperValue:= createUpperMultiplicity("1"); } } /** * This mapping convert a IRelation instanceof ISysMLPort into a uml Port * */ mapping umlrhapsody::IRelation::iRelationToSysMLPort(): uml::Port when {self.isRhapsodySysMLPortRepresentingUMLPort()}{ var sysPort:umlrhapsody::ISysMLPort:=self.oclAsType(ISysMLPort); name:= sysPort.name.replaceAll("\"",""); // if (not sysPort.otherClass.oclIsUndefined()){ // if(sysPort.otherClass.oclIsKindOf(IType)){ // type := sysPort.otherClass.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); // }elif(sysPort.otherClass.oclIsKindOf(IClass)){ // type := sysPort.otherClass.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); // } // }; if(sysPort.implicitClass<>sysPort.otherClass){ type := sysPort.otherClass.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); }; aggregation:=AggregationKind::composite; isConjugated:=sysPort.isConjugated(); //a multiplicity has been defined if(not sysPort.multiplicity.oclIsUndefined()){ lowerValue:= createLowerMultiplicity(sysPort.multiplicity); upperValue:= createUpperMultiplicity(sysPort.multiplicity); }else{ lowerValue:= createLowerMultiplicity("1"); upperValue:= createUpperMultiplicity("1"); } } query umlrhapsody::IRelation::isRhapsodySysMLPortRepresentingUMLPort(): Boolean{ if(self.isRhapsodyPort()){ return self.oclAsType(ISysMLPort).Stereotypes[IStereotype]->select(ste | ste.name="flowPort")->notEmpty(); //we could do an additional check, checking that owner is stereotyped by Block? }; return false; } query umlrhapsody::IRelation::isRhapsodySysMLPortRepresentingUMLProperty(): Boolean{ if(self.isRhapsodyPort()){ return self.oclAsType(ISysMLPort).Stereotypes[IStereotype]->select(ste | ste.name="ConstraintParameter")->notEmpty(); //we could do an additional check, checking that owner is stereotyped by ConstraintParamater? }; return false; } //TODO : merge me with previous one query umlrhapsody::IRelation::isRhapsodySysMLPortContraintParameter(): Boolean{ if(self.isRhapsodyPort()){ return self.oclAsType(ISysMLPort).Stereotypes[IStereotype]->select(ste | ste.name="ConstraintParameter")->notEmpty(); //we could do an additional check, checking that owner is stereotyped by ConstraintParamater? }; return false; } mapping umlrhapsody::IStateChart::toStateMachine(): uml::StateMachine { //get hierarchic states var parentStates:Set(IState) :=self.getCompositeStates(); var allsubStates:Set(IState):= self.getallSubStates(); name:=self.name.replaceAll("\"",""); // create the default region : for the default ROOT region concept did not exist in rhap region := object Region { name:="Region1"; subvertex += self.States[IState]->select(s|allsubStates->excludes(s) and parentStates->excludes(s)).map toStates(); var pseudo := object Pseudostate { name :="initial"; kind:= PseudostateKind::initial; }; subvertex+=pseudo; //only the first default transition transition += self.Transitions[IDefaultDrvdTrans]->select(t|parentStates->excludes(t.ofState)).map toInitialTransition(pseudo); subvertex+= self.States[IState]->select(s|parentStates->includes(s)).map toCompositeStates(self); // only transitions that its states are in the firest regions transition+=self.Transitions[ITransition]->select(t|((allsubStates->excludes(t.itsTarget.oclAsType(IState))) and (allsubStates->excludes(t.itsSource.oclAsType(IState))))).map toTransitions(); // other mix transition (source and target not in the same region) transition+=self.getMixTransitions(parentStates, allsubStates).map toTransitions(); }; } query umlrhapsody::IStateChart::getMixTransitions(parentStates:Set(umlrhapsody::IState), allsubStates:Set(umlrhapsody::IState)): Set(umlrhapsody::ITransition) { var mixTrnasitions:Set(umlrhapsody::ITransition); var outTransitions :=self.Transitions[ITransition]->select(t|((allsubStates->excludes(t.itsTarget.oclAsType(IState))) and (allsubStates->excludes(t.itsSource.oclAsType(IState))))); var innerTransitions := self.Transitions[ITransition]->select(t|allsubStates->includes(t.itsSource.oclAsType(IState)) and allsubStates->includes(t.itsTarget.oclAsType(IState))); mixTrnasitions := self.Transitions[ITransition]->select(t| (innerTransitions->excludes(t) and outTransitions->excludes(t))); return mixTrnasitions; } query umlrhapsody::IStateChart::getSubStates(parentstate: umlrhapsody::IState ): Set(umlrhapsody::IState) { var subStates:Set(umlrhapsody::IState); self.States->forEach(state) { if (state.parent.oclAsType(IState)=parentstate) { subStates+=state.oclAsType(IState); } }; return subStates; } query umlrhapsody::IStateChart::getCompositeStates(): Set(umlrhapsody::IState) { var parentStates:Set(umlrhapsody::IState); self.States->forEach(state) { if (not(state.parent.oclAsType(IState).name.replaceAll("\"","")="ROOT")) { parentStates+=state.parent.oclAsType(IState); } }; return parentStates; } query umlrhapsody::IStateChart::getallSubStates(): Set(umlrhapsody::IState) { var allSubStates:Set(umlrhapsody::IState); self.States->forEach(state) { if (not(state.parent.oclAsType(IState).name.replaceAll("\"","")="ROOT")) { allSubStates+=state.oclAsType(IState); } }; return allSubStates; } mapping umlrhapsody::IDefaultDrvdTrans::toInitialTransition(pseudo:uml::Vertex): uml::Transition { name:=self.name; target:= self.itsTarget[IState].resolveone(State); source:=pseudo; } mapping umlrhapsody::IState::toCompositeStates(statechart:umlrhapsody::IStateChart): uml::State { var allsubStates:Set(IState):= statechart.getSubStates(self); name:=self.name.replaceAll("\"",""); result.oclAsType(State).region:= object Region { name:="Region1"; subvertex += allsubStates.map toStates(); var pseudo := object Pseudostate { name :="initial"; kind:= PseudostateKind::initial; }; subvertex+=pseudo; transition += statechart.Transitions[IDefaultDrvdTrans]->select(t|t.ofState=self).map toInitialTransition(pseudo); transition += statechart.Transitions[ITransition]->select(t|allsubStates->includes(t.itsSource.oclAsType(IState)) and allsubStates->includes(t.itsTarget.oclAsType(IState))).map toTransitions(); } } mapping umlrhapsody::IState::toStates(): uml::State when {not(self.name.replaceAll("\"","")="ROOT")} { name:=self.name.replaceAll("\"",""); } mapping umlrhapsody::ITransition::toTransitions(): uml::Transition { name:=self.name; target:= self.itsTarget[IState].resolveone(State); source:=self.itsSource[IState].resolveone(State); trigger:=self.itsLabel[ILabel].itsTrigger [IInterfaceItemTrigger].map toTrigger(); //take the first guard guard:=self.itsLabel[ILabel].itsGuard[IGuard]->any(true).map toGuard(); effect:= self.itsLabel[ILabel].itsAction[IAction]->any(true).map toBehavior(); } mapping umlrhapsody::IAction::toBehavior(): uml::OpaqueBehavior { body:=self.body.trim(); language:= "C++"; } mapping umlrhapsody::IGuard::toGuard(): uml::Constraint { result.specification := object OpaqueExpression { body:=self.body.trim(); language:= "C++"; } } mapping umlrhapsody::IInterfaceItemTrigger::toTrigger(): uml::Trigger { event:= self.itsInterfaceItem.resolveone(SignalEvent); } mapping umlrhapsody::IAssociationEnd::toAssociationsEnd(): uml::Property when{self.oclIsTypeOf(IAssociationEnd)}{ name:=self.name.replaceAll("\"",""); type:= self.otherClass.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); aggregation:=AggregationKind::none; } mapping umlrhapsody::IClass::fromClasse2Associations(): uml::Association { //TODO FIXME: default subsystem : bad code var classes : Set(uml::Class) :=inModel.rootObjects()[IProject].defaultSubsystem[ISubsystem].Classes->selectByKind(EObject).map iClassToUMLClass()->asSet(); var associations: Set(uml::Association); var i : Integer=0; classes->forEach(element) { var newasso: uml::Association; // collect the classes with AssociationEnd and create an association with both classes if (not (element.oclAsType(IClass).Associations[IAssociationEnd]->isEmpty())) then { newasso := object uml::Association { var otherClass : IClass:= element.oclAsType(IClass).Associations[IAssociationEnd].otherClass->any(true).oclAsType(IClass); memberEnd+= element.oclAsType(IClass).Associations[IAssociationEnd].map toAssociationsEnd(); memberEnd+= otherClass.Associations[IAssociationEnd].map toAssociationsEnd(); memberEnd->asSet(); }; if (i=0){ associations+=newasso; i:= i+1; }; if (not (associations->isEmpty())) { associations->forEach(asso) { if( not (asso.memberEnd->includesAll(newasso.memberEnd))) associations+=newasso; } }endif; }endif; }; } mapping umlrhapsody::IGeneralization::toPapyrusGeneralization(): uml::Generalization { general:= self.oclAsType(IGeneralization).dependsOn.oclAsType(IClass).oclAsType(EObject).map iClassToUMLClass(); } mapping umlrhapsody::IReception::toReceptions(): uml::Reception { name:= self.event.name.replaceAll("\"",""); signal := self.event[IEvent].resolveone(Signal); } mapping umlrhapsody::IPrimitiveOperation::toOperations(): uml::Operation { name:= self.name.replaceAll("\"",""); // with the return type inside ownedParameter:= self.Args[IArgument]->map toArguments(); if (not self.returnType.oclIsUndefined()){ var return_param:= object uml::Parameter { direction:= ParameterDirectionKind::_return; type:= self.returnType.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); }; ownedParameter+=return_param; }; var desiredVisibility := getVisibility(self.protection); if (desiredVisibility != VisibilityKind::public) { //to avoid green + in UML editor visibility:= desiredVisibility }; } mapping umlrhapsody::IVariable::iVariableToUMLElement():uml::Property disjuncts umlrhapsody::IArgument::iArgumentToUMLElement, umlrhapsody::IAttribute::iAttributeToUMLElement {} mapping umlrhapsody::IArgument::iArgumentToUMLElement(): uml::Property when {self.oclIsTypeOf(umlrhapsody::IArgument)}{ name:= self.oclAsType(IArgument).name.replaceAll("\"",""); // should add the PtR Stereotpe if the type is a C++ Declaration : i,e: Class *; if (self.typeOf.oclIsUndefined()){ type := self.myTypeOf.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); userTypeDeclaration+=type; }else{ type := self.typeOf.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); }; } /** * We map IAttribute declared in the TopLevel class as instance specifications */ helper umlrhapsody::IAttribute::isInstanceSpecification():Boolean{ var owner:EObject:=self.oclAsType(EObject).eContainer(); return owner.oclIsKindOf(IClass) and owner.oclAsType(IClass).name="TopLevel"; } /** * This mapping creates InstanceSpecification from IAttribute */ mapping ecore::EObject::iAttributeToUMLInstanceSpecification(): uml::InstanceSpecification when {self.oclIsKindOf(IAttribute) and self.oclAsType(IAttribute).isInstanceSpecification()}{ var iAttribute:IAttribute:=self.oclAsType(IAttribute); name:=iAttribute.name; classifier+=iAttribute.typeOf.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Classifier); var tmp:String:=""; if(not iAttribute.ValueSpecifications.oclIsUndefined()){ tmp:=iAttribute.ValueSpecifications.value; }; if(classifier->any(true).oclIsTypeOf(Enumeration)){ specification:=object InstanceValue{ name:="InstanceValue1"; instance:=classifier.oclAsType(Enumeration).member->any(name=tmp).oclAsType(InstanceSpecification); } }else{ specification:=object OpaqueExpression{ body:=tmp; } } } mapping umlrhapsody::IAttribute::iAttributeToUMLElement(): uml::Property when {self.oclIsTypeOf(umlrhapsody::IAttribute)}{ name:= self.name.replaceAll("\"",""); // should add the PtR Stereotpe if the type is a C++ Declaration : i,e: Class *; if (self.typeOf.oclIsUndefined()) { type := self.myTypeOf.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); userTypeDeclaration+=type; }else{ type := self.typeOf.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); }; var desiredVisibility := getVisibility(self.protection); if (desiredVisibility != VisibilityKind::public) { //to avoid green + in UML editor visibility:= desiredVisibility }; //a multiplicity has been defined if(not self.multiplicity.oclIsUndefined()){ lowerValue:= createLowerMultiplicity(self.multiplicity); upperValue:= createUpperMultiplicity(self.multiplicity); }; aggregation:=AggregationKind::composite; } /** * Create LiteralInteger to represent the lower multiplicity */ helper createLowerMultiplicity(multiplicity:String):LiteralInteger{ if(multiplicity.oclIsUndefined() or multiplicity.size()=0){ return null; }; var lower:String; if(multiplicity.indexOf("..")<>0){ lower:=multiplicity.substringBefore(".."); }elif(multiplicity.indexOf(",")<>0){ lower:=multiplicity.substringBefore(","); }else{ lower:=multiplicity; }; var lit:LiteralInteger:= object LiteralInteger{}; lit.value:=lower.toInteger(); return lit; } /** * Create LiteralUnlimitedNatural to represent the upper multiplicity */ helper createUpperMultiplicity(multiplicity:String):LiteralUnlimitedNatural{ if(multiplicity.oclIsUndefined() or multiplicity.size()=0){ return null; }; var upper:String; if(multiplicity.indexOf("..")<>0){ upper:=multiplicity.substringAfter(".."); }elif(multiplicity.indexOf(",")<>0){ upper:=multiplicity.substringAfter(","); }else{ upper:=multiplicity; }; var lit:LiteralUnlimitedNatural:= object LiteralUnlimitedNatural{}; if(upper.equalsIgnoreCase("*")){ lit.value:=-1; }else{ lit.value:=upper.toInteger(); }; return lit; } /** * Return the visibility kind for an IAttribtue or an operation */ helper getVisibility(protection:String):uml::VisibilityKind{ if(protection="iPublic"){ return VisibilityKind::public; }elif(protection="iProtected"){ return VisibilityKind::protected; }elif(protection="iPrivate"){ return VisibilityKind::private; }; //seems not possible in Rhapsody // elif(self.protection="iPackage"){ // return VisibilityKind::package; // }; return VisibilityKind::public; } mapping umlrhapsody::IArgument::toArguments(): uml::Parameter { name:= self.name.replaceAll("\"",""); direction:= getDirectionKind(self.argumentDirection); // should add the PtR Stereotpe if the type is a C++ Declaration : i,e: Class *; if (self.typeOf.oclIsUndefined()) { type := self.myTypeOf.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); userTypeDeclaration+=type; }else { type := self.typeOf.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); } } query getDirectionKind(s:String): uml::ParameterDirectionKind{ var direction: uml::ParameterDirectionKind; direction:= switch { case (s="in") ParameterDirectionKind::_in; case (s="out") ParameterDirectionKind::_out; case (s="inout") ParameterDirectionKind::_inout; // there is no return direction in Rhapsody there is a returnType attribute instead, }; return direction; } mapping umlrhapsody::IEvent::toSignalEvents(): uml::SignalEvent { name:= self.name.replaceAll("\"",""); signal:= self[IEvent].resolveone(Signal); //TODO replace me with a mapping } mapping ecore::EObject::iEventToUMLSignal(): uml::Signal when {self.oclIsTypeOf(IEvent)}{ var localEvent:IEvent:=self.oclAsType(IEvent); name:= localEvent.name.replaceAll("\"",""); ownedAttribute += localEvent.Args[IVariable]->map iVariableToUMLElement(); } //collect the call events from the umlrhapsody file query umlrhapsody::ISubsystem::callEvents() : Set(umlrhapsody::IEvent) { return self.Events.oclAsType(Set(IEvent))->asSet(); } //collect the signal events from the umlrhapsody file query umlrhapsody::ISubsystem::SignalEvents() : Set(umlrhapsody::IEvent) { var allSignalEvents : Set(umlrhapsody::IEvent); var classes : Set(umlrhapsody::IClass) :=inModel.rootObjects()[IProject].defaultSubsystem[ISubsystem].Classes[IClass]->asSet(); classes->forEach(classe) { if (not(classe.Operations[IReception]->isEmpty())) { classe.Operations[IReception]->forEach(reception) { if (not(reception.oclAsType(IReception).event.oclIsUndefined())) allSignalEvents+= reception.oclAsType(IReception).event; } }endif; }; return allSignalEvents; }