| /***************************************************************************** |
| * 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.interoperability.rpy.blackboxes.uml.AssociationOwnerHelper; |
| import org.eclipse.papyrus.interoperability.common.blackboxes.uml.UMLHelper; |
| import RpyToPapyrusUtils; |
| import SysMLRpyUtils; |
| import RpyUtils; |
| |
| 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 umlrpy "strict" uses 'http://www.eclipse.org/Papyrus/UMLRpy/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 Rpy Semantic model into a UML model |
| */ |
| transformation Rpy2PapyrusSemanticElements(in inModel:umlrpy, 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); |
| |
| /**The UML Package representing the Rpy libraries and user custom types*/ |
| property typesLibraries:Sequence(uml::Package); |
| |
| /** |
| * 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 umlrpy::IProject::iProjectToPapyrusModel() : uml::Model { |
| name:=self.name.replaceAll("\"",""); |
| eAnnotations+=inModel.rootObjects()->selectByType(IProject)![IProject].createEAnnotationForVersioning(); |
| |
| var localComment:Comment:=self.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| |
| //we map the packaged elements |
| packagedElement+=self.Subsystems.map iDefaultSubsystemTypeToPackage(); |
| |
| //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()){ |
| typesLibraries+= object Package{ |
| name:="UserTypesDeclaration"; |
| packagedElement+=userTypeDeclaration; |
| } |
| }; |
| |
| //we sort the library by alphabetical order |
| var sortedLibrary:Sequence(uml::Package):=sortNamedElement(typesLibraries)->selectByKind(uml::Package); |
| sortedLibrary->forEach(pack){ |
| //we sort the contents of the library by alphabetical order |
| var packageableElements:Sequence(PackageableElement):=pack.packagedElement->selectByKind(uml::PackageableElement)->asSequence(); |
| pack.packagedElement:=null; |
| sortNamedElement(packageableElements)->forEach(n){ |
| //we don't found an other way than this forEach to maintain the sort' |
| if(n.oclIsKindOf(uml::PackageableElement)){ |
| pack.packagedElement+=n.oclAsType(uml::PackageableElement); |
| }; |
| }; |
| }; |
| |
| //we add them to the final model |
| packagedElement+=sortedLibrary; |
| |
| } |
| |
| /** |
| * Create packages from DefaultSubsystemType |
| */ |
| mapping umlrpy::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); |
| |
| //managing rpy objects IAssociationClass |
| packagedElement+=iSubSystem.AssociationElements->selectByType(IAssociationClass)->selectByKind(EObject).map generalMappingToUMLElement().oclAsType(uml::PackageableElement); |
| |
| 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 Rpy 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, |
| ecore::EObject::iAssociationClassToUMLAssociation |
| {} |
| |
| /** |
| * This mapping convert an IActor into a UML Actor |
| */ |
| mapping EObject::iActorToUMLActor():uml::Actor when {self.oclIsTypeOf(umlrpy::IActor)}{ |
| var actor:IActor:=self.oclAsType(IActor); |
| name:=actor.name; |
| ownedComment += actor.Annotations->selectByType(IComment).oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| |
| var localComment:Comment:=actor.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| /** |
| * |
| * 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(umlrpy::IPart).map iPartToUMLElement().oclAsType(uml::Element); |
| case (metaClassName="IAttribute") rpyAnnotatedElement.oclAsType(umlrpy::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 |
| |
| //this regex works fine (for php, tested on https://regex101.com/r/9FfA4S/4)) |
| // {\\\\[a-zA-Z0-9\\\\\s]*(;\}+)?|\\\\[a-zA-Z0-9]* |
| //a nicer regex |
| var res:String:=self.replaceAll("\\\\ldblquote\\s", "“"); //replace left quote followed by a space |
| res:=res.replaceAll("\\\\rdblquote\\s?","”"); //replace right quote maybe followed by a space |
| res:=res.replaceAll("\\\\pard",""); //remove explicitely the tag \\pard |
| res:=res.replaceAll("\\\\par","\n"); //replace all new paragraph by new line |
| res:=res.replaceAll("\\\\line","\n"); //replace all new paragraph by new line |
| res:=res.replaceAll("\\{\\\\[a-zA-Z0-9\\\\\\s]*(;\\}+)?|\\\\[a-zA-Z0-9]*\\s?", ""); //to remove all others formatting informations |
| |
| res:=res.replaceAll("'\\w+(;})?",""); //in some case we get this kind of string after the first regex : 'cb'ce'cc'e5;}myText |
| |
| res:=res.replaceAll("\r\n","\n"); |
| |
| var a:="}\n"; |
| var lastIndex:=res.lastIndexOf(a); |
| if(lastIndex<>-1 and lastIndex=res.length()-(a.size()-1)){ |
| res:=res.substring(1,lastIndex-1); |
| }; |
| |
| while(res.startsWith("\n") or res.startsWith("}") or res.startsWith(";") or res.startsWith("{")){ |
| res:=res.substring(2,res.length()); |
| }; |
| |
| while(res.endsWith("\n") or res.endsWith("}") or res.endsWith(";") or res.endsWith("{")){ |
| res:=res.substring(1,res.length()-1); |
| }; |
| |
| return res; |
| } |
| |
| /** |
| * |
| * return true if the IClass is representing an interface |
| */ |
| mapping ecore::EObject::iClassToUMLInterface() : uml::Interface when {self.oclIsTypeOf(umlrpy::IClass) and self.oclAsType(umlrpy::IClass).isInterface() /*self.isSysMLFlowSpecification()*/}{ |
| var localIClass:umlrpy::IClass:=self.oclAsType(umlrpy::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(); |
| |
| var localComment:Comment:=localIClass.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| |
| |
| /** |
| * |
| * When we match any condition, we create a uml::DataType or a uml::Enumeration. |
| * 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 Rpy (declaring a type with a string, see bug 510869) |
| */ |
| mapping ecore::EObject::iTypeToDefault():uml::DataType when{self.oclIsTypeOf(IType)}{ |
| init{ |
| var localIType:IType:=self.oclAsType(IType); |
| var nameToUse:String:=""; |
| if(localIType.name=null or localIType.name.oclIsInvalid()){ |
| if(localIType.declaration<>null){ |
| nameToUse:=localIType.declaration; |
| } |
| }else{ |
| nameToUse:=localIType.name.replaceAll("\"",""); |
| }; |
| if(nameToUse.indexOf("Enum")=0){ |
| result:=object DataType{}; |
| }else{ |
| result:=object Enumeration{}; |
| } |
| } |
| name:=nameToUse; |
| |
| var fileName:String:=localIType.oclAsType(EModelElement).getFileNameWithoutExtension(); |
| var package:uml::Package:=fileName.map createPackageLibrary(); |
| if(not package.oclIsUndefined()){ |
| package.packagedElement+=result; |
| } |
| } |
| |
| /** |
| * This mapping allows to create a package from a string |
| */ |
| mapping String::createPackageLibrary():uml::Package when {not self.oclIsUndefined()}{ |
| name:=self; |
| typesLibraries+=result; |
| } |
| |
| |
| /** |
| * This method allows to map a RpyType on an other type |
| */ |
| query umlrpy::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 Rpy Library (like PredefinedTypes) must be imported as DatType |
| */ |
| query umlrpy::IType::isUMLDataType(): Boolean { |
| var res:=self.isSysMLValueType() and not self.isKindEnumeration(); |
| if(not res){ |
| res:=(self.isRpyDataType() or self.isRpyLibraryType()) and (self.isKindLanguage() or self.isKindTypedef()); |
| }; |
| return res; |
| } |
| |
| |
| /** |
| * Return true if the IType is kind Typedef |
| */ |
| query umlrpy::IType::isKindTypedef(): Boolean{ |
| return self.kind="Typedef"; |
| } |
| |
| /** |
| * Return true if the IType is kind Enumeration |
| */ |
| query umlrpy::IType::isKindEnumeration(): Boolean{ |
| return self.kind="Enumeration"; |
| } |
| |
| /** |
| * Return true if the IType is kind Enumeration |
| */ |
| query umlrpy::IType::isKindStructure(): Boolean{ |
| return self.kind="Structure"; |
| } |
| |
| /** |
| * Return true if the IType has kind Language |
| */ |
| query umlrpy::IType::isKindLanguage(): Boolean { |
| return self.kind="Language"; |
| } |
| |
| query umlrpy::IType::isUMLClass(): Boolean{ |
| return self.isKindStructure() and (self.isRpyDataType() or self.isSysMLValueType()); |
| } |
| |
| query umlrpy::IType::isUMLEnumeration():Boolean{ |
| return self.isKindEnumeration() and ((self.isRpyDataType() or self.isSysMLValueType()) //TODO to check : is it required to check isDatatYpe and isSysmlValueType ? |
| or self.isRpyLibraryType()); //to create Enumeration for Type defined ni RpyLibrary |
| } |
| |
| query umlrpy::IType::isUMLInstanceSpecification(): Boolean { |
| return self.isKindLanguage() and (self.isSysMLDimension() or self.isSysMLUnit()); |
| } |
| |
| //--------association code-------------- |
| |
| /** |
| * This mapping creates a UML association with its 2 members ends and owned ends when required, according to the navigability value |
| */ |
| mapping ecore::EObject::iAssociationClassToUMLAssociation(): uml::Association when{self.oclIsKindOf(IAssociationClass)}{ |
| var localIAssociationClass:IAssociationClass:=self.oclAsType(IAssociationClass); |
| name:= localIAssociationClass.name.replaceAll("\"",""); |
| var end1:IAssociationEnd:=localIAssociationClass.m_end1; |
| var end2:IAssociationEnd:=localIAssociationClass.m_end2; |
| |
| var mapping1:Property:=end1.map toAssociationsEnd().oclAsType(Property); |
| var mapping2:Property:=end2.map toAssociationsEnd().oclAsType(Property); |
| |
| //if navigable: owned by class |
| //if non navigable, owned by the association |
| |
| memberEnd+=mapping1; |
| memberEnd+=mapping2; |
| |
| if(not end1.isNavigable()){ |
| ownedEnd+=mapping1; |
| }; |
| if(not end2.isNavigable()){ |
| ownedEnd+=mapping2; |
| } |
| } |
| |
| /** |
| * Return true if the association end is navigable. In this case, the property will be owned by the class, |
| * otherwse, by the association |
| */ |
| helper umlrpy::IAssociationEnd::isNavigable():Boolean{ |
| return self.navigability.equalsIgnoreCase("Navigable"); |
| } |
| |
| /** |
| * Common method to create association from an IAssociationEnd |
| */ |
| mapping umlrpy::IAssociationEnd::iAssociationEndToUMLAssociation(): uml::Association disjuncts |
| umlrpy::IAssociationEnd::iAssociationEndToUMLAssociation_case1, |
| umlrpy::IAssociationEnd::iAssociationEndToUMLAssociation_case2 |
| {} |
| |
| mapping umlrpy::IAssociationEnd::iAssociationEndToUMLAssociation_case1(): uml::Association when {self.isNavigable() and self.inverse.oclIsUndefined()}{ |
| //please keep this order (O source and 1 target) -> if we change this property we broke the BDD of test2 |
| |
| //when isNavigable() returns true, the property is owned by the classifier |
| //when isNavigable() returns false, the property is owned by the association |
| //here, in the Rpy model, we have only one end, so here this end will be owned by the classifier and the other one by the association |
| var localMemberEnd:=self.map toAssociationsEnd(); |
| memberEnd+= localMemberEnd; |
| var localOwnedEnd:= object Property{ |
| type:= self.container().oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); |
| }; |
| ownedEnd+= localOwnedEnd; |
| name:=localOwnedEnd.type.name + " refers to " + localMemberEnd.type.name + " as " + localMemberEnd.name; |
| |
| } |
| |
| mapping umlrpy::IAssociationEnd::iAssociationEndToUMLAssociation_case2():uml::Association when{ |
| self.isNavigable() and |
| (not self.inverse.oclIsUndefined()) |
| and self.inverse.oclIsTypeOf(IAssociationEnd) |
| and self.inverse.oclAsType(IAssociationEnd).isNavigable() |
| and self.m_associationClass.oclIsUndefined()}{ //in this case, the association is created by the mapping for IAssociationClass |
| //when isNavigable() returns true, the property is owned by the classifier |
| //when isNavigable() returns false, the property is owned by the association |
| //-> here the 2 properties are owned by the classifier |
| init{ |
| //this resolve is not a mistake. We call resolve to avoid to create several time the same association |
| result:=self.inverse.resolveoneIn(umlrpy::IAssociationEnd::iAssociationEndToUMLAssociation_case2); |
| } |
| if(result.memberEnd->size()=0){//the result has been created goint out of the init, because the resolve doesn't allow to find an existing association |
| result.memberEnd+=self.map toAssociationsEnd(); |
| result.memberEnd+=self.inverse.oclAsType(IAssociationEnd).map toAssociationsEnd(); |
| //order of member can't be determined in this case |
| } |
| } |
| |
| mapping umlrpy::IAssociationEnd::toAssociationsEnd(): uml::Property when{self.oclIsTypeOf(IAssociationEnd)}{ |
| name:=self.name.replaceAll("\"",""); |
| type:= self.otherClass.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(Type); |
| aggregation:=AggregationKind::none; |
| } |
| |
| /** |
| * |
| * This mapping convert a IPart into a uml Element |
| */ |
| mapping umlrpy::IPart::iPartToUMLElement():uml::Element disjuncts |
| umlrpy::IPart::iPartToUMLProperty |
| {} |
| |
| /** |
| * This method convert an IPart into a uml Property |
| * |
| */ |
| mapping umlrpy::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); |
| }; |
| var localComment:Comment:=self.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| mapping umlrpy::IPart::iPartToUMLAssociation():uml::Association when {true}{ |
| var part:uml::Property:=self.resolveoneIn(umlrpy::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(umlrpy::IClass)){ |
| //TODO : make a util for this stereotype application |
| res:=initialVal.oclAsType(umlrpy::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; |
| } |
| |
| //------end of association code---------------------- |
| |
| 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)); |
| |
| if(not localIType.isRpyLibraryType()){ |
| var localComment:Comment:=localIType.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| }; |
| } |
| |
| 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)); |
| |
| if(not localIType.isRpyLibraryType()){ |
| var localComment:Comment:=localIType.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| }; |
| } |
| |
| mapping umlrpy::IEnumerationLiteral::toUMLEnumerationLiteral() : uml::EnumerationLiteral { |
| name:= self.name.replaceAll("\"",""); |
| |
| if(not self.oclAsType(EObject).isRpyLibraryType()){ |
| var localComment:Comment:=self.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| }; |
| } |
| |
| 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("\"",""); |
| |
| var localComment:Comment:=localIType.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| //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)); |
| |
| var localComment:Comment:=localIType.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| |
| mapping ecore::EObject::iClassToUMLClass(): uml::Class when {self.oclIsTypeOf(umlrpy::IClass) and not (self.oclAsType(umlrpy::IClass).isInterface())}{ |
| var localIClass:umlrpy::IClass:=self.oclAsType(umlrpy::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->selectByType(IAssociationEnd)->select(a | a.isNavigable()).map toAssociationsEnd(); |
| associationsToAdd+=localIClass.Associations[IAssociationEnd].map iAssociationEndToUMLAssociation(); |
| |
| 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); |
| |
| var localComment:Comment:=localIClass.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| |
| /** |
| * This method map a IObjectLink with a UML Element |
| * |
| */ |
| mapping umlrpy::IInformationFlow::iInformationFlowToUMLElement():uml::Element disjuncts |
| umlrpy::IInformationFlow::iInformationFlowToUMLConnector |
| {} |
| |
| /** |
| * This method map a IInformationFlow with a UML Connector |
| * |
| */ |
| mapping umlrpy::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 umlrpy::IInformationFlow::iInformationFlowSourceToUMLConnectorEnd():uml::ConnectorEnd{ |
| var end1:umlrpy::End1_Type:=self.end1_; |
| var end1ObjectPort:umlrpy::IInstance:=self.end1ObjectPort_; |
| |
| var mappingEnd1:uml::Element; |
| var mappingEnd1ObjectPort:uml::Element; |
| //1. we manage the end1 property |
| if(end1<>null){ |
| if(end1.oclIsTypeOf(umlrpy::IPart)){ |
| mappingEnd1:=end1.oclAsType(umlrpy::IPart).map iPartToUMLElement().oclAsType(uml::Property); |
| }elif(end1.oclIsTypeOf(umlrpy::IAttribute)){ |
| mappingEnd1:=end1.oclAsType(IAttribute).map iVariableToUMLElement(); |
| }elif(end1.oclIsKindOf(umlrpy::IRelation)){ |
| mappingEnd1:=end1.oclAsType(IRelation).map iRelationToUMLElement(); |
| }; |
| }; |
| |
| //2. we manage the end1ObjectPort_ property when required |
| if(end1ObjectPort<>null and end1ObjectPort.oclIsKindOf(umlrpy::IRelation)){ |
| mappingEnd1ObjectPort:=end1ObjectPort.oclAsType(umlrpy::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 umlrpy::IInformationFlow::iInformationFlowTargetToUMLConnectorEnd():uml::ConnectorEnd{ |
| var end2:umlrpy::End1_Type:=self.end2_; |
| var end2ObjectPort:umlrpy::IInstance:=self.end2ObjectPort_; |
| |
| var mappingEnd2:uml::Element; |
| var mappingEnd2ObjectPort:uml::Element; |
| //1. we manage the end2 property |
| if(end2<>null){ |
| if(end2.oclIsTypeOf(umlrpy::IPart)){ |
| mappingEnd2:=end2.oclAsType(umlrpy::IPart).map iPartToUMLElement().oclAsType(uml::Property); |
| }elif(end2.oclIsTypeOf(umlrpy::IAttribute)){ |
| mappingEnd2:=end2.oclAsType(IAttribute).map iVariableToUMLElement(); |
| }elif(end2.oclIsKindOf(umlrpy::IRelation)){ |
| mappingEnd2:=end2.oclAsType(IRelation).map iRelationToUMLElement(); |
| }; |
| }; |
| |
| //2. we manage the end2ObjectPort_ property when required |
| if(end2ObjectPort<>null and end2ObjectPort.oclIsKindOf(umlrpy::IRelation)){ |
| mappingEnd2ObjectPort:=end2ObjectPort.oclAsType(umlrpy::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 umlrpy::IInformationFlow::isUMLConnector(): Boolean{ |
| return self.Stereotypes[IStereotype]->select(ste | ste.name="BindingConnector").oclAsSet()->notEmpty() |
| } |
| |
| |
| |
| /** |
| * This method map a IObjectLink with a UML Element |
| * |
| */ |
| mapping umlrpy::IObjectLink::iObjectLinkToUMLElement():uml::Element disjuncts |
| umlrpy::IObjectLink::iObjectLinkToUMLConnector |
| {} |
| |
| /** |
| * This method map a IObjectLink with a UML Connector |
| * |
| */ |
| mapping umlrpy::IObjectLink::iObjectLinkToUMLConnector():uml::Connector when{self.isUMLConnector() }{ |
| name:= self.name.replaceAll("\"",""); |
| _end+=self.map iObjectLinkSourceToUMLConnectorEnd(); |
| _end+=self.map iObjectLinkTargetToUMLConnectorEnd(); |
| |
| var localComment:Comment:=self.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| /** |
| * This method map a IObjectLink with a UML Connector End used as source |
| * |
| */ |
| mapping umlrpy::IObjectLink::iObjectLinkSourceToUMLConnectorEnd():uml::ConnectorEnd{ |
| var fromLink:umlrpy::FromLinkType:=self.fromLink; |
| var fromPort:umlrpy::IRelation:=self.fromPort; |
| //1. we manage the from link property |
| if(fromLink<>null){ |
| if(fromLink.oclIsTypeOf(umlrpy::IPart)){ |
| partWithPort:=fromLink.oclAsType(umlrpy::IPart).map iPartToUMLElement().oclAsType(uml::Property); |
| }elif(fromLink.oclIsTypeOf(umlrpy::IAssociationEnd)){ |
| partWithPort:=fromLink.oclAsType(IAssociationEnd).map toAssociationsEnd(); |
| }elif(fromLink.oclIsKindOf(umlrpy::IRelation)){ |
| role:=fromLink.oclAsType(umlrpy::IRelation).map iRelationToUMLElement().oclAsType(uml::Port); |
| }; |
| }; |
| |
| //2. we manage the fromPort property when required |
| if(fromPort<>null and fromPort.oclIsKindOf(umlrpy::IRelation)){ |
| if(role=null){ |
| role:=fromPort.oclAsType(umlrpy::IRelation).map iRelationToUMLElement().oclAsType(uml::Port); |
| } |
| //I don't know what to do in other case! |
| }; |
| |
| if(partWithPort.oclIsTypeOf(Property) and role=null){ |
| role:=partWithPort; |
| partWithPort:=null; |
| } |
| } |
| |
| /** |
| * This method map a IObjectLink with a UML Connector End used as target |
| * |
| */ |
| mapping umlrpy::IObjectLink::iObjectLinkTargetToUMLConnectorEnd():uml::ConnectorEnd{ |
| var toLink:umlrpy::FromLinkType:=self.toLink; |
| var toPort:umlrpy::IRelation:=self.toPort; |
| //1. we manage the from link property |
| if(toLink<>null){ |
| if(toLink.oclIsTypeOf(umlrpy::IPart)){ |
| partWithPort:=toLink.oclAsType(umlrpy::IPart).map iPartToUMLElement().oclAsType(uml::Property); |
| }elif(toLink.oclIsTypeOf(umlrpy::IAssociationEnd)){ |
| partWithPort:=toLink.oclAsType(IAssociationEnd).map toAssociationsEnd(); |
| }elif(toLink.oclIsKindOf(umlrpy::IRelation)){ |
| role:=toLink.oclAsType(umlrpy::IRelation).map iRelationToUMLElement().oclAsType(uml::Port); |
| }; |
| }; |
| |
| //2. we manage the fromPort property when required |
| if(toPort<>null and toPort.oclIsKindOf(umlrpy::IRelation)){ |
| if(role=null){ |
| role:=toPort.oclAsType(umlrpy::IRelation).map iRelationToUMLElement().oclAsType(uml::Port); |
| } |
| //I don't know what to do in other case! |
| }; |
| |
| if(partWithPort.oclIsTypeOf(Property) and role=null){ |
| role:=partWithPort; |
| partWithPort:=null; |
| } |
| } |
| |
| /** |
| * |
| * Returns true of the object is a UML Connector |
| */ |
| query umlrpy::IObjectLink::isUMLConnector(): Boolean{ |
| return self.isStereotypedWith("connector"); |
| } |
| |
| mapping umlrpy::IRelation::iRelationToUMLElement():uml::Element disjuncts |
| umlrpy::IRelation::iRelationToSysMLPort, |
| umlrpy::IRelation::iRelationToUMLProperty |
| {} |
| |
| |
| /** |
| * This mapping convert a IRelation instanceof ISysMLPort into a uml Property |
| * |
| */ |
| mapping umlrpy::IRelation::iRelationToUMLProperty(): uml::Property when {self.isRpySysMLPortRepresentingUMLProperty()}{ |
| var sysPort:umlrpy::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"); |
| }; |
| var localComment:Comment:=sysPort.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| /** |
| * This mapping convert a IRelation instanceof ISysMLPort into a uml Port |
| * |
| */ |
| mapping umlrpy::IRelation::iRelationToSysMLPort(): uml::Port when {self.isRpySysMLPortRepresentingUMLPort()}{ |
| var sysPort:umlrpy::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; |
| |
| //to my mind, the Rpy field isConjugated manage the SysML FlowPort property and the UML one. |
| //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"); |
| }; |
| |
| var localComment:Comment:=sysPort.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| |
| query umlrpy::IRelation::isRpySysMLPortRepresentingUMLPort(): Boolean{ |
| if(self.isRpyPort()){ |
| 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 umlrpy::IRelation::isRpySysMLPortRepresentingUMLProperty(): Boolean{ |
| if(self.isRpyPort()){ |
| 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 umlrpy::IRelation::isRpySysMLPortContraintParameter(): Boolean{ |
| if(self.isRpyPort()){ |
| 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 umlrpy::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 umlrpy::IStateChart::getMixTransitions(parentStates:Set(umlrpy::IState), allsubStates:Set(umlrpy::IState)): Set(umlrpy::ITransition) |
| { |
| var mixTrnasitions:Set(umlrpy::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 umlrpy::IStateChart::getSubStates(parentstate: umlrpy::IState ): Set(umlrpy::IState) |
| { |
| var subStates:Set(umlrpy::IState); |
| self.States->forEach(state) |
| { |
| if (state.parent.oclAsType(IState)=parentstate) |
| { |
| subStates+=state.oclAsType(IState); |
| } |
| }; |
| return subStates; |
| } |
| query umlrpy::IStateChart::getCompositeStates(): Set(umlrpy::IState) |
| { |
| var parentStates:Set(umlrpy::IState); |
| self.States->forEach(state) |
| { |
| |
| if (not(state.parent.oclAsType(IState).name.replaceAll("\"","")="ROOT")) |
| { |
| parentStates+=state.parent.oclAsType(IState); |
| } |
| }; |
| |
| return parentStates; |
| } |
| |
| query umlrpy::IStateChart::getallSubStates(): Set(umlrpy::IState) |
| { |
| var allSubStates:Set(umlrpy::IState); |
| self.States->forEach(state) |
| { |
| if (not(state.parent.oclAsType(IState).name.replaceAll("\"","")="ROOT")) |
| { |
| allSubStates+=state.oclAsType(IState); |
| } |
| }; |
| return allSubStates; |
| } |
| |
| mapping umlrpy::IDefaultDrvdTrans::toInitialTransition(pseudo:uml::Vertex): uml::Transition |
| { |
| |
| name:=self.name; |
| target:= self.itsTarget[IState].resolveone(State); |
| source:=pseudo; |
| |
| |
| } |
| |
| mapping umlrpy::IState::toCompositeStates(statechart:umlrpy::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 umlrpy::IState::toStates(): uml::State |
| when {not(self.name.replaceAll("\"","")="ROOT")} |
| |
| { |
| name:=self.name.replaceAll("\"",""); |
| } |
| |
| |
| mapping umlrpy::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 umlrpy::IAction::toBehavior(): uml::OpaqueBehavior |
| { |
| |
| body:=self.body.trim(); |
| language:= "C++"; |
| |
| |
| } |
| |
| mapping umlrpy::IGuard::toGuard(): uml::Constraint |
| { |
| |
| result.specification := object OpaqueExpression |
| { |
| body:=self.body.trim(); |
| language:= "C++"; |
| } |
| |
| } |
| |
| mapping umlrpy::IInterfaceItemTrigger::toTrigger(): uml::Trigger |
| { |
| |
| event:= self.itsInterfaceItem.resolveone(SignalEvent); |
| |
| |
| } |
| |
| |
| |
| |
| mapping umlrpy::IGeneralization::toPapyrusGeneralization(): uml::Generalization |
| { |
| general:= self.oclAsType(IGeneralization).dependsOn.oclAsType(IClass).oclAsType(EObject).map iClassToUMLClass(); |
| |
| } |
| |
| mapping umlrpy::IReception::toReceptions(): uml::Reception |
| { |
| name:= self.event.name.replaceAll("\"",""); |
| signal := self.event[IEvent].resolveone(Signal); |
| |
| |
| } |
| |
| mapping umlrpy::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 umlrpy::IVariable::iVariableToUMLElement():uml::Property disjuncts |
| umlrpy::IArgument::iArgumentToUMLElement, |
| umlrpy::IAttribute::iAttributeToUMLElement |
| {} |
| |
| |
| |
| mapping umlrpy::IArgument::iArgumentToUMLElement(): uml::Property when {self.oclIsTypeOf(umlrpy::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); |
| }; |
| |
| var localComment:Comment:=self.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| /** |
| * We map IAttribute declared in the TopLevel class as instance specifications |
| */ |
| helper umlrpy::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; |
| } |
| }; |
| |
| var desiredVisibility := getVisibility(iAttribute.protection); |
| if (desiredVisibility != VisibilityKind::public) { //to avoid green + in UML editor |
| visibility:= desiredVisibility |
| }; |
| |
| var localComment:Comment:=iAttribute.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| mapping umlrpy::IAttribute::iAttributeToUMLElement(): uml::Property when {self.oclIsTypeOf(umlrpy::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; |
| |
| var localComment:Comment:=self.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| |
| /** |
| * 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 Rpy |
| // elif(self.protection="iPackage"){ |
| // return VisibilityKind::package; |
| // }; |
| return VisibilityKind::public; |
| } |
| |
| |
| mapping umlrpy::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 Rpy there is a returnType attribute instead, |
| }; |
| return direction; |
| } |
| |
| |
| mapping umlrpy::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(); |
| |
| var localComment:Comment:=localEvent.description.oclAsType(EObject).map generalMappingToUMLElement().oclAsType(uml::Comment); |
| localComment.annotatedElement:=result; |
| ownedComment+=localComment; |
| } |
| |
| //collect the call events from the umlrpy file |
| |
| query umlrpy::ISubsystem::callEvents() : Set(umlrpy::IEvent) |
| { |
| return self.Events.oclAsType(Set(IEvent))->asSet(); |
| } |
| |
| //collect the signal events from the umlrpy file |
| |
| query umlrpy::ISubsystem::SignalEvents() : Set(umlrpy::IEvent) |
| { |
| var allSignalEvents : Set(umlrpy::IEvent); |
| var classes : Set(umlrpy::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; |
| |
| } |